Search Engine Architecture — Implementation Reference
본 문서 = 개발자 / partner / 새 팀원이 SearchRight 검색 pipeline 의 구현 내부를 빠르게 잡는 reference. 헤드헌터 사용자는 사용자 가이드
how-it-works.md가 더 적합 (이 문서는 implementation log 톤).Diátaxis: Reference (architecture 깊이). 변경 시 의무 = m-q-3b §6 위험 /
feedback_parser_prompt_global_perturb등 박제 룰 확인.
§1 컴포넌트 구조 (current main)
apps/web/src/app/api/companies/search/route.ts ← POST controller (44 LOC orchestrator, m-q-3b)
apps/web/src/server/service/search/ ← pipeline 11 module (m-q-3b)
├── parse-request.ts ← body 구조분해 + cappedLimit + env-driven defaults
├── auto-hybrid.ts ← short brand-like query auto-promote
├── build-cache-key.ts ← filtersSnapshot + engineFlagsSnapshot + RANKING_VERSION
├── build-filter.ts ← whereClause 30+ filter 조립 + 3 domain pre-filter
├── hyde-step.ts ← HyDE 호출 + fallback + usage 추적
├── embed-step.ts ← OpenAI embedding + feedback adjustments
├── retrieve-hybrid.ts ← Dense + BM25 + RRF SQL CTE
├── retrieve-dense.ts ← Dense SQL CTE + countDense
├── rerank-step.ts ← composeRerankQuery + Cohere/LLM listwise + fallback
├── rank-step.ts ← additive boost + final_score + feedback factor + sort
├── rerank-query.ts ← Cohere rerank query 4 분기 (fintech_payment > fintech > ads_display > default)
├── embed-text.ts ← HyDE on/off 조립
├── scoring.ts ← normalizeQuery / computeCacheKey / tierBonus / additiveBoost
└── search-history.ts ← lookupCache / bumpCacheHit / insertHistory
POST function 1027 → 44 LOC controller orchestrator (m-q-3b 결과, -95.7%). 11 module unit test 207 case.
§2 데이터 흐름 (8 단계)
| # | 단계 | 모델 / 라이브러리 | 박제 위치 |
|---|---|---|---|
| 1 | parser | gpt-5.4-nano + zod schema | apps/web/src/lib/parser.ts |
| 2 | 구조화 필터 | drizzle ORM whereClause | server/service/search/build-filter.ts |
| 3 | HyDE (optional) | gpt-5.4-nano | apps/web/src/lib/hyde.ts |
| 4 | embedding | OpenAI text-embedding-3-small (1536-d) | apps/web/src/lib/embedding.ts |
| 5 | SQL pool | pgvector cosine + Lindera BM25 (ParadeDB pg_search) + RRF (k=60) | retrieve-hybrid.ts / retrieve-dense.ts |
| 6 | rerank | Cohere v3.5 cross-encoder (default) 또는 gpt-5.4-mini listwise (opt-in) | apps/web/src/lib/rerank.ts + lib/llm-rerank.ts |
| 7 | final_score | rerank * tw + additive_boost * feedback_factor (tw=1.0 dead, M-tier-weight-audit) | rank-step.ts |
| 8 | 출력 | desc sort + cappedLimit slice + enrichRows (candidates / alumni signal) | route.ts |
§3 변경 절대 금지 박제값 (m-q-3b §6 위험)
| 영역 | 값 | 이유 |
|---|---|---|
| SQL CTE priority CASE | llm_enriched 1 / manual 2 / homepage 3 / innoforest 4 / else 5 | best_profile DISTINCT ON 순서 |
| RRF k | 60 | M2 측정 결과 sweet spot |
| RRF weight | dense=1.0 / BM25=0.25 | BM25 noise 절제 |
tier_weight SQL pool | global_bigtech 2.0 / domestic_bigtech 1.8 / unicorn 1.5 / growth_stage 1.2 / else 1.0 | sparsity prior |
tier_weight JS final | 1.0 (dead) | M-tier-weight-audit — multiplier 복구 시 -2 hits |
MIN_SIMILARITY | 0 (필터 있을 때) / 0.35 (필터 없을 때) | 전체 15k pool 노이즈 방어선 |
RANKING_VERSION | "m19pp-pmf2-2026-05-07" | cache key invalidate — bump 시 prod cache cold-start |
FEEDBACK_DEMOTE_FACTOR / BOOST_FACTOR | 0.3 / 1.2 (multiplicative) | M19''-PMF-2 Improve layer |
rerankQuery qualifier precedence | fintech_payment > fintech > ads_display > default | G7/G22 검증 |
변경 시 의무 = m-q-3b 트랙의 dual-call eval 게이트 통과 (88/88 byte-identical) + eval-compare paired-t (verdict ∈ {identical, noise}).
§4 6 dim G4 ontology
각 회사 = 6 차원 구조화 속성 (DB column + parser 자동 추출 + UI 필터).
| dim | DB column | 값 set / 정의 |
|---|---|---|
| scale | tier enum (7), total_funding_krw, employee_count, annual_revenue_krw | global_bigtech / domestic_bigtech / unicorn / enterprise / growth_stage / mid_sized / early_stage |
| target_market | customer_type enum, target_age_bands[], target_gender, service_regions[] | b2b / b2c / b2b2c / b2g, KR / GLOBAL / 미국 / EU / 일본 / ASEAN / ... |
| tech | backend_stack[], frontend_stack[], infra_stack[], uses_ai_ml bool, ai_ml_details[] | normalize 의무 (tech-stack-ontology.ts, ai-ml-detail-ontology.ts) |
| bm | service_archetypes[], revenue_models[], revenue_models_v2[], service_type, sales_channel, has_offline_store, has_recommendation/search/display_curation | saas / marketplace / d2c / platform + subscription / transaction_commission / ads_display / ... |
| culture | org_structure[], dev_process[] | normalize (culture-ontology.ts) — slug → DB 한글 토큰 expand |
| grounding | domains[] (slug 30+), narrow_segment (G3/G4 ontology v1.6, 281 segment) | fintech_payment / airline_seat_booking 같은 fine-grain |
자세한 정의: apps/web/src/lib/segment-ontology.ts (281 narrow_segment), docs/research/02-taxonomy.md.
G4 cascade 통계 (2026-05-22)
- enriched 7,023 회사 (LLM gpt-5.4-mini + WebSearch Phase 2)
- 6-dim 박제 5,624 row (Tier A + B + C 일부)
- recall@200 default 79.8% / opt-in
llm_rerank82.4% (11 query × 3 dim testset)
§5 검색 측정 SSOT
| 지표 | 위치 |
|---|---|
| testset (g5-testset.json) | docs/data/g5-testset.json (11 query, locked 2026-05-20) |
| metric 정의 | docs/data/search-metrics-glossary.md |
| recall 시계열 | docs/status/timeline.md |
| 측정 script | packages/db/scripts/run-test-set.ts |
| paired-t compare | packages/db/scripts/eval-compare.ts |
| EVAL_CACHE_MODE | apps/web/src/lib/eval-cache.ts (parser/HyDE pin) |
| dual-call eval (m-q-3b 게이트) | packages/db/scripts/dual-call-eval.ts |
새 mission 측정 의무 사항:
- 3-run paired (
feedback_hyde_change_multisample) — HyDE/parser 변경 시 - EVAL_CACHE_MODE=true 격리 (
feedback_filter_cut_counterfactual) — stochastic 분리 - per-company root cause (
feedback_expected_db_inspection) — aggregate 분포만 보지 말 것 - GATE-5 eval-compare artifact 첨부 —
docs/data/eval-runs/*.json
§6 외부 API (v1)
| endpoint | 책임 | spec |
|---|---|---|
POST /api/v1/search | 검색 (Bearer key + scope search:read + rate limit) | docs/api/external.md |
GET /api/v1/openapi.json | OpenAPI 3.1 (zod → spec auto-gen, M-HARDEN H-3) | runtime fetch |
GET /reference | Scalar 인터랙티브 UI (m-user-docs-1) | — |
/llms.txt + /llms-full.txt | partner LLM (Cursor/Codex) 컨텍스트 (M-SSOT-1 S-7, Anthropic 패턴) | apps/web/public/ 정적 |
/api/health | 헬스체크 (인증 불요) | — |
인증 layer: /admin/clients (운영자) — DB-backed Bearer key (srk_live_<32B>) + scope + revocation. api_usage_log → /admin/observability + /admin/usage dashboard (H-5).
§7 Stack snapshot
- runtime: Next.js 16.2 (app router, Turbopack) + React 19 + TypeScript strict
- DB: PostgreSQL + ParadeDB pg_search (BM25 Lindera Korean tokenizer) + pgvector (cosine)
- ORM: Drizzle (postgres-js driver)
- LLM:
- parser / HyDE: OpenAI gpt-5.4-nano
- rerank: Cohere rerank-v3.5 (default) 또는 OpenAI gpt-5.4-mini listwise (opt-in)
- embedding: OpenAI text-embedding-3-small (1536-d)
- auth: NextAuth v5 (Google OAuth + DB credentials, M-HARDEN H-1)
- infra: AWS ECS (auto-deploy on main push via
.github/workflows/deploy.yml) - testing: Vitest (207 case unit) + dual-call byte-identity (m-q-3b)
§8 더 깊은 reference
- 사용자 가이드 (헤드헌터 톤):
docs/user/how-it-works.md - 검색 알고리즘 트랙 history:
docs/archives/handoffs-2026-{04,05}.md(M-PROD-G2 ~ G22) - 본 트랙 mission file:
docs/plans/missions/m-q-3b.md(POST refactor + dual-call) - 6 dim ontology source:
apps/web/src/lib/segment-ontology.ts+docs/research/02-taxonomy.md - search metric SSOT:
docs/data/search-metrics-glossary.md - 외부 API consumer 가이드:
docs/api/external.md(5 단계 walkthrough 포함) - AGENTS.md (모든 에이전트 항상 로딩):
/AGENTS.md - 북극성:
docs/context/north-star.md