← 목록
기타 2026-07-12 10KB 읽기 10분

크라우니검색 (search.crowny.org) — 구축 완료

개요

사장님 비전(구글 가기 전에 크라우니 생태계를 먼저 노출 — "네이버 대응 정보의 장")에 따라 크라우니검색 서비스를 신규 구축했다. 정본 설계 문서: /Users/ef/CrownyDoc/projects/2026-07-12-크라우니검색-네이버대응-설계.md

  • 위치: /Users/ef/crowny-search/ (신규 디렉토리, CrownyBrowser 무접촉)
  • 언어: 한선씨 고수준(hanseonc_high) 100% — 인덱스 빌더 + HTTP 서버 전부
  • 포트: 9887 (게이트웨이 SSOT 등록 완료, crowny-ports.sh get search.crowny.org → 9887)

포트 변경 사유 (9885 → 9887)

설계 문서/작업 지시에는 9885가 제안되어 있었으나, 실측 결과 9885는 crowny-ports.sh check가 "사용가능"이라 답했음에도 불구하고 실제로는 이미 다른 서비스(결정사이드카.toau, PID 1740, 15시간+ 가동 중)가 127.0.0.1:9885에 바인딩되어 있었다 (gateway.yaml 미등록 + 실제 LISTEN 불일치 — crowny-ports.sh는 gateway.yaml 등록 여부만 확인하고 실제 소켓 바인딩은 확인하지 않음). lsof -iTCP:<포트> -sTCP:LISTEN으로 직접 재검증해 9887(완전 유휴)로 변경, `crowny-ports.sh set search.crowny.org 9887 crowny-search`로 정식 등록했다. 교훈: 포트 확보 시 gateway.yaml 체크만으론 부족 — lsof 실측 병행 필요(다른 세션 참고용으로 기록).

무엇을 했는지

1. 인덱스 빌더 (인덱스빌더.한선 + 인덱스빌더.sh + scripts/전처리.sh)

  • 소스A: gateway.yaml 271개 서비스 항목 awk 추출 → 267개 유효(URL 중복 제거 후)
  • 소스B: CrownyDoc/projects/*.md 2,887개 문서 — 파일당 awk 1회 호출로 첫 # 제목 +
첫 본문 문단만 조기 추출(exit로 전체 파일 읽기 회피). 본문 전체 아닌 제목+요약만 인덱싱(64KB 캡·문자열풀 480k 함정 회피 지시 준수)
  • 소스C: CrownyBrowser/src/앱목록.psv 10종
  • 정규화: 종류|제목|URL|요약키워드 4필드, 파이프/개행 제거, URL 기준 sort -u 중복 제거
  • 샤딩: 문서 2,887행을 split -l 150로 23개 샤드(~40KB/샤드)로 분할 — 한선씨 읽기()
64KB 캡과 배열 1023/4095 캡을 동시 회피
  • 한글 서비스 별칭 보강: gateway.yaml엔 description 필드가 없어(name/domain만 존재),
data/서비스별칭.psv(수동 큐레이션 ~50개 도메인 prefix→한글 키워드, 예: bank→"뱅크 은행 크라우니뱅크")로 서비스 키워드 필드를 보강. 이게 없으면 "크라우니뱅크" 같은 한글 질의가 영문 슬러그(crowny-bank)만 가진 서비스 행과 매칭되지 않음.
  • 한선씨 빌더 로직: 샤드 목록(data/샤드목록.txt) 순회 → 샤드별 읽기()분리(내용,"\n")
→ 줄별 분리(줄,"|") NF==4 무결성 검증 → 통과 행만 덧쓰기()로 최종 data/검색인덱스.psv 스트리밍 작성

실측 결과 (./hanseonc_high 인덱스빌더.한선 > toau && ./crownyc run toau):

샤드 수: 23
총 행수: 3164
유효 행수: 3164
무결성 오류: 0
사후 검증: awk -F'|' 'NF!=4' → 0건, URL 중복 → 0건. 종류별 서비스 267 / 문서 2887 / 앱 10.

2. 검색 서버 (검색서버.한선, 포트 9887)

  • TCP대기/TCP수락/TCP읽기(8192)/TCP쓰기/TCP닫기 루프(크라우니뱅크 패턴 준용)
  • GET /?q=<질의> → HTML 결과 페이지, GET /api/search?q= → JSON, GET /api/health
  • URL 디코드: 크라우니코드 학습DB HIT 재사용퍼센트디코드_URL한글쿼리 패턴
(버퍼 바이트 단위 %XX 디코드 → 버퍼문자열()로 UTF-8 무손실 재구성, 자체 UTF-8 코드포인트 수동조립보다 견고). 실측 라운드트립 검증(%ED%81%AC%EB%9D%BC%EC%9A%B0%EB%8B%88%EB%B1%85%ED%81%AC → "크라우니뱅크") 통과.
  • 검색 실행: 쓰기()로 질의를 패턴파일에 저장 → 체계("grep -F -f 패턴파일 카테고리.psv")
고정문자열(비정규식) 매칭 — 질의가 쉘 커맨드라인에 직접 노출되지 않아 인젝션 회피. 서비스/앱은 무캡, 문서는 head -150으로 캡(664KB 원본 파일이 읽기() 64KB를 넘으므로).
  • 랭킹(결정론, ML 없음): 점수매기기(종류,제목,키워드,질의) — 서비스 완전일치(1000) >
서비스 제목부분일치(500) > 서비스 키워드일치(400) > 문서 제목일치(300) > 문서 키워드(본문 요약)일치(200) > 앱(250/150) > 퍼지(20~50). 병렬배열(점수/종류/제목/URL/키워드) 수동 삽입정렬(정렬()은 문자열배열 미동작 함정 회피).
  • 결과 페이지 3단 구성(설계 문서 순): ① 크라우니LLM 답변(`curl :9976/q --data-urlencode
q@파일 -m 2`, 미기동 시 빈 문자열 반환 → 섹션 자동 생략) ② 생태계 결과 카드(서비스/문서/앱 뱃지) ③ 하단 "구글에서 검색 →" 버튼(항상 노출)
  • 크라우니디자인 SSOT 토큰 하드코딩: --bg:#FAF9F7 --gold:#C9A961 --coral:#D4743A
가드레일 명시 값 그대로, 다크모드 @media (prefers-color-scheme: dark) 대응, 폰트 'Söhne','Pretendard'. (※ crowny-design.sh apply는 정적 HTML 파일 대상 도구라 동적 생성 페이지엔 적용 대상이 없음 — 토큰을 직접 임베드하고 grep으로 SSOT 값 일치를 검증하는 방식으로 대체.)
  • VM 함정 회피: Content-Length 생략 + Connection: close(한글 바이트/문자수 불일치
트런케이션 회피), JSON/HTML 이스케이프 헬퍼 직접 구현, 예약어 메서드 충돌 발견 즉시 HTTP메서드로 개명(컴파일러가 TOK_METHOD로 예약).

검증 (실측)

포트 9887에서 서버 기동 → curl 3종 시나리오 + JSON API 확인 → 서버 종료 후 고아 프로세스 0 확인(lsof -iTCP:9887 재실행 결과 없음, ps -p <PID> 없음).

질의상단 결과HTTP
크라우니뱅크① 서비스 crowny-bank(bank.crowny.org, 점수 1000 완전일치) ② 이하 뱅크 관련 문서 다수200
양자① 서비스 crowny-estel(estel.crowny.org, 키워드 매칭 400) ② 이하 40큐비트 스테빌라이저·estEL 브랜드 등 양자 문서 다수(총 68건 중 상위 노출)200
아무거나없는말결과 0건 — "크라우니 생태계에 없습니다" 메시지 + 구글 폴백 버튼(google.com/search?q=아무거나없는말) 정상 노출200
/api/search?q=양자유효 JSON, count:68, results 배열 30건 캡200
/api/health{"status":"T","server":"CrownySearch/1.0"}200
grep -o -- "--bg:#FAF9F7" / "--gold:#C9A961" 실제 응답 HTML에서 확인 완료.

크라우니코드 보고

lookup HIT 1건(재사용: 퍼센트디코드_URL한글쿼리 — 버퍼 기반 UTF-8 무손실 %XX 디코드) / MISS 4건(생성: 크라우니검색_결정론랭킹점수, 크라우니검색_grep고정문자열안전검색, 한선씨_배열삽입정렬_병렬배열, 크라우니검색_인덱스빌더샤드검증) / learn 추가 4건.

관련 파일

  • /Users/ef/crowny-search/인덱스빌더.한선 — 인덱스 빌더 (한선씨)
  • /Users/ef/crowny-search/인덱스빌더.sh — 러너(전처리+컴파일+실행)
  • /Users/ef/crowny-search/scripts/전처리.sh — bash 전처리(awk/grep 추출+샤딩)
  • /Users/ef/crowny-search/검색서버.한선 — HTTP 검색 서버 (한선씨, 포트 9887)
  • /Users/ef/crowny-search/data/서비스별칭.psv — 도메인 prefix → 한글 키워드 수동 큐레이션
  • /Users/ef/crowny-search/data/raw/{서비스,문서,앱}.psv — 카테고리별 원시 인덱스(서버가 grep 대상으로 직접 사용)
  • /Users/ef/crowny-search/data/검색인덱스.psv — 통합 인덱스(3,164행, 무결성검증 완료)
  • /Users/ef/crowny-search/data/shards/ — 문서 샤드(23개, 재빌드 시 재생성됨)

브라우저 연동 포인트 (CrownyBrowser — 이번 세션 무접촉, 배치 예정)

설계 문서 "배치 큐" 항목 그대로 유지: crowny-browser.mnormalizeURLString 검색 라우팅 분기에서 google.com/search 직행 대신 https://search.crowny.org/?q=<원문질의> (또는 crowny-internal://search?q=)로 우회시키면 된다. 크라우니검색은 자체 하단에 구글 폴백 버튼을 항상 노출하므로, 브라우저 쪽은 검색창 입력 → 크라우니검색으로 1차 라우팅만 하면 되고 구글 이탈은 크라우니검색 페이지가 사용자 명시 클릭으로 처리한다(설계 문서 원칙 그대로). 이 배선은 상주세션 배선 완료 후 별도 배치로 진행 예정(이번 작업 범위 아님, CrownyBrowser 파일 미접촉 확인).

잔여 이슈 / TODO

  1. 게이트웨이 실배선 미완: crowny-ports.sh set으로 gateway.yaml에 `search.crowny.org
→ 127.0.0.1:9887` 항목은 추가됐으나(SSOT 갱신), 라이브 게이트웨이 프로세스 재기동/HTTPS cert 발급은 별도(가드레일 "라이브 게이트웨이 직접편집 금지" 준수, set만 수행). 실제 https://search.crowny.org 공개는 게이트웨이 담당 세션/워치독의 다음 재기동 사이클에서 반영됨.
  1. 크라우니검색 서비스 자체는 상시 데몬으로 등록하지 않았다 (가드레일 "데몬 무단영속
금지 — 벤치는 기동→종료" 준수, 검증 후 즉시 종료함). 실서비스로 상시 가동하려면 LaunchAgent 등록이 별도 필요(사용자 승인 후 진행 권장).
  1. 문서 검색 캡(head -150): 매우 일반적인 질의(예: "크라우니" 단독)는 664KB 문서
원시파일에서 150건 초과 매치가 나올 수 있어 상위 150건 이후는 랭킹 대상에서 제외된다. 현재 인덱스 규모(3,164행)에선 실용상 문제 없으나, 문서가 1만 건 이상으로 늘어나면 카테고리 내 2차 샤딩(예: 날짜/슬러그 접두사별)이 필요.
  1. 서비스 별칭 커버리지: data/서비스별칭.psv는 ~50개 주요 도메인만 수동 큐레이션함.
나머지 ~217개 서비스는 영문 슬러그로만 검색 가능(한글 질의 매칭 안 될 수 있음) — 필요시 점진 보강.
  1. 크라우니LLM 답변 섹션 미검증: :9976 서버가 이번 검증 시점에 가동되어 있지 않아
"미기동 시 생략" 경로만 실측했고, 실제 LLM 응답 JSON 파싱( 필드) 경로는 라이브 검증 못함 — LLM 서버 가동 후 1회 회귀 확인 권장.