사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.











constant.ts에서 검색할 field마다 text 역할을 붙입니다.document.ts의 filter에서 q.search(text)를 호출합니다.listBySearch를 "relevance" 정렬로 부릅니다.{ text: "title" }처럼 씁니다.document.ts에 이름을 붙여 선언한 query입니다. service에 그 이름을 딴 listBySearch 같은 메서드가 생깁니다.{ text: "title" }처럼 역할을 적습니다. 얼마나 잘 검색되길 바라는지가 아니라 값이 무엇인지를 보고 고르세요. 역할마다 순위 가중치가 다릅니다.| 역할 | 가중치 |
|---|---|
| ↳ 용도 | |
| title | 10 |
| 사람이 검색창에 치는 이름입니다. 다른 어떤 역할보다 순위에 크게 반영됩니다. | |
| tag | 3 |
| 키워드 목록입니다. 제목보다 낮고 본문보다 높습니다. | |
| desc | 1 |
| 본문입니다. 매치는 되지만 이름이 맞은 결과보다 앞서지 않도록 가중치가 낮습니다. | |
| filter | 0 |
| status나 owner처럼 범위를 좁히는 값입니다. 검색에는 걸리지만 순위는 올리지 않습니다. | |
| thumb | — |
| 검색 결과를 화면에 그릴 때 쓰도록 함께 저장됩니다. 색인되지 않으므로 매치되지 않습니다. | |
title, tag, desc는 String을 받습니다. filter와 thumb은 ID나 field(File) 같은 관계 field도 받고, 문자열 enum은 String으로 취급됩니다.[String]은 항목마다 색인되고, 내장 스칼라 안의 역할은 부모 field를 통해 색인됩니다. Map 안의 field는 색인되지 않습니다.


field.secret, field.hidden, resolve()에는 text 역할을 줄 수 없습니다. 인덱스는 평문을 저장하므로, 색인된 비밀 값은 검색으로 새어 나갑니다. 타입 검사에서 거절됩니다.q.search()는 다른 것과 똑같은 query 노드라서 q.all() 안에서 일반 조건과 조합됩니다. service에서 검색하는 데 slice는 필요 없습니다..arg()는 필수 인자이고, .opt()는 생략할 수 있으며 모든 .arg() 뒤에 둡니다. 둘 다 선언한 순서대로 .query()에 들어오고, 마지막에 q가 붙습니다.{}는 아무 조건도 더하지 않습니다. 상태를 넘기지 않으면 검색어만으로 결과를 좁힙니다..query()에 인자까지 이름을 적어 줍니다:{ sort, skip, limit }로 정렬하고 페이지를 나눕니다.exec이 반환할 때 씁니다.q.search()의 두 번째 인자로 넘깁니다.Ken으로 Kenny를 못 찾습니다.thumb은 색인되지 않으므로 고를 수 없습니다.follow-up은 “follow-up”과 “follow up”을 찾습니다.| sort 값 |
|---|
| ↳ 결과 순서 |
"relevance" |
| 가장 잘 맞는 결과부터 옵니다. |
다른 키 ("latest" 등) |
| 점수보다 그 키가 우선합니다. |
| 생략 — service에서 호출 |
| query에 검색이 있으므로 가장 잘 맞는 결과부터 옵니다. |
| 생략 — slice endpoint |
"latest"가 채워지므로 점수 순이 되지 않습니다. |


"relevance"를 반드시 명시하세요. slice endpoint는 sort를 비워 두면 "latest"를 채우므로 점수 순으로 정렬되지 않습니다..slice() 아래에 .desc()와 함께 씁니다. MCP 에이전트는 그 설명을 보고 도구를 고릅니다.st.do.initProductBySearch(text, statuses, { sort: "relevance" }).live() slice는 { fallback: "invalidate" }를 선언합니다.

init({ guards })로만 보호됩니다. slice()의 guard 맵은 root slice와 생성된 CRUD에만 적용됩니다. 자기 guard가 없으면 HTTP로 누구나 호출할 수 있고, MCP에는 공개되지 않습니다.q.search()가 에러를 던집니다. q.search()를 선언한 filter 자체는 문제없고, 실제로 실행된 query만 실패합니다.unicode61에는 unaccent가(remove_diacritics 0이면 불필요), trigram에는 pg_trgm이 필요합니다. Akan이 쓰는 데이터베이스 role에 권한이 있으면 Akan이 만들고, 없으면 권한이 있는 role로 CREATE EXTENSION unaccent(또는 pg_trgm)를 실행합니다.LC_CTYPE로 만듭니다. en_US.UTF-8이나 C.UTF-8 같은 값입니다. 그렇지 않으면 SQLite와 달리 ASCII 문자에서만 대소문자를 구분하지 않습니다.unicode61에서 Postgres는 document마다 title, tag, filter 텍스트의 앞 20,000자와 desc의 앞 200,000자만 색인합니다.q.search()를 둘 수 없는 곳과, 헷갈리기 쉬운 동작들입니다:q.search()는 AND 위치에만 둘 수 있습니다. q.any()나 q.not() 아래에 두면 query가 에러를 던집니다.updateOne / updateMany / removeOne / removeMany, 그리고 생성된 updateBySearch / removeBySearch 계열은 대량 write가 인덱스와 join할 수 없어서 이를 거절합니다. 에러 메시지에는 updateOneByQuery나 updateManyByQuery라는 이름으로 나옵니다.schema.index()는 검색과 무관합니다. schema.index({ name: "text" })라고 써도 일반 조회 인덱스만 만듭니다.