← 목록
기타 2026-07-26 7KB 읽기 8분

크라우니클린 P0 구축 (clean.crowny.org:9624)

  • 일자: 2026-07-26 착수 / 2026-07-27 완료
  • 산출: /Users/ef/crowny-clean/ — 순수 한선씨 서버 + 단일 앱.html
  • 사양 SSOT: /Users/ef/Downloads/크라우니클린 패키지/README.md (5.10 P0 범위)
  • 디자인 SSOT: 크라우니캔버스 디자인 규칙.css + 클린화면A–H·S·M.dc.html

개요

이사·입주 프리미엄 1:1 클리닝 서비스. 차별점은 청소 품질 주장이 아니라 전 과정 사진 기록이다. 접수 → 배정 스태프 공개 → 구역·머신별 작업 → before/after → 리포트를 고객이 모바일로 실시간 확인한다.

핵심 불변식(절대규칙 5)을 서버 라우트 수준에서 강제했다.

  • 금액 발생·고객 공개·주소 노출 = confirm=1 없으면 409 + 감사 로그 append-only
  • 스태프는 촬영·보고만 — 분류·짝·공개·금액 라우트는 403
  • 미분류(pending)·보류(held) 사진은 고객 응답에 절대 포함되지 않음
  • CRD는 정수 crd_milli로만 저장, 0.05 배수 검증, 표기는 항상 소수 2자리

무엇을 했는지

1. 서버.한선 (1,580줄 · 포트 9624 · hanseonc_high 경고 0)

데이터 모델(5.1) 전부를 PSV append-log(latest-wins)로 영속화 — 재기동 시 복원 확인. quote booking job zone photo report approval staff crew crd_ledger audit_log + staff_report review chat.

라우트 43개 전수 200/403/409/404 검증(아래 검증 절 참조).

라우트
공통GET /health GET / GET /fonts/PretendardVariable.woff2
1aGET /home
BPOST /quotes/estimate POST /quotes GET /quotes POST /quotes/finalize(관리자)
CGET /slots GET /staff GET /crews/assigned POST /bookings(confirm) GET /bookings POST /bookings/change
DGET /jobs/:id GET /jobs/:id/photos(published만) GET /jobs/:id/timeline
EPOST /approvals(관리자) GET /approvals POST /approvals/decide(confirm+decision 명시) GET·POST /chat
FGET /jobs/:id/report POST /reports/publish(관리자) POST /reviews(CRD 적립) GET /crd
SPOST /staff/photos(스태프) GET /staff/queue GET·POST /staff/report
MGET /admin/inbox POST /admin/photos/classify POST /admin/zones/publish(confirm) POST /admin/zones/status GET /admin/audit
뷰 배치GET /view/live /view/booking /view/report /view/staff /view/admin한 화면 = 한 요청
촬영→공개 파이프라인(5.2)이 실제로 동작한다: 스태프 업로드 → visibility=pending(고객 불가시) → 관리자 classify(교정 이력 감사 기록) → 관리자 zones/publish(확인 다이얼로그) → 그때서야 /jobs/:id/photos에 등장.

2. 앱.html (단일 파일 · 고객 6 + 스태프 3 + 관리자 2 화면)

  • 토큰은 크라우니캔버스 디자인 규칙.css 값 무수정 복사, 다크는 [data-theme="다크"] 토큰 스왑만
  • 딥링크 #역할/화면, ?theme=다크 (알림·공유 링크가 화면에 직결)
  • 확인 다이얼로그 공통 컴포넌트 — 제목·설명·기록 문구·실행 4요소 강제
  • 웹폰트 자체 서빙(외부 CDN 미사용)

3. 앱.한선 — 프론트 뷰모델 정본 (한선씨 동반, 셀프테스트 33/33 PASS)

화면 라우팅·탭 모델·권한 매트릭스·골드 상한·CRD 표기·용어 게이트를 한선씨로 선언. env RUN=1 crownyc run 앱.toau로 검증한다. JS는 이 규칙의 렌더 계층이다.

검증

  1. 컴파일: hanseonc_high 서버.한선 경고 0 (54,519 큐브) · 앱.한선 경고 0
  2. 라우트: curl 43/43 PASS (권한 403 5건 · 확인 게이트 409 3건 · 404 1건 포함)
  3. 재기동 복원: kill 후 재기동 → CRD 잔액·견적·승인 상태 그대로 복원
  4. 브라우저 육안: 8화면 전부 렌더 확인(라이트/다크). 스크린샷 /tmp/clean_shots/
  5. 디자인이식 diff: 판정 · 신규색 0 · 신규치수 0→3(토큰 var 참조 오탐)
  6. QA 체크리스트(5.9): 용어 혼용 0 · CRD 소수 2자리 · 골드 솔리드 화면당 ≤2(관리자 1) ·
라이브 계열 골드 0 · 미분류/보류 고객 노출 0 · 팀장 표기 "일잘하는 인준팀장" + 실명칩

이번에 확인한 함정 (다른 세션도 해당)

  1. TCP쓰기는 부분쓰기 루프가 없는 단일 write() (crownyc.c:12243).
2KB 넘는 본문이 조용히 잘리고, Content-Length를 믿는 브라우저 fetch는 영구 정지한다. → 본문은 임시파일 + 파일소켓전송(856)으로 보낼 것. C레벨 부분쓰기 루프가 있다.
  1. Content-Length는 UTF-8 바이트수여야 한다. 생략하면 fetch가 EOF를 기다리며 멈춘다.
글자수()는 문자수 → 한글 본문에서 어긋난다. 바이트수 헬퍼 필수.
  1. 한선씨 문자열의 ${...}는 변수 보간으로 파싱된다 — 체계()에 셸 변수를 넣을 때
${i}는 컴파일 에러(미정의 변수). "$n" 형태로 쓸 것.
  1. 브라우저는 한글 쿼리값을 %XX로 인코딩한다 — 서버에서 role=관리자 문자열 비교가
조용히 실패. 역할·모드 같은 제어 파라미터는 ASCII 코드로 주고받을 것.
  1. 응답 크기를 줄이는 것이 곧 안정성이다. 정적 UI 문구는 클라이언트 상수로, 목록은 커서 12건.
  2. 크라우니AI검증(WKWebView) 헤드리스는 +1초 수집 예산이라, 큰 fetch가 진행 중이면
"불러오는 중" 상태를 찍는다. 판정 전에 Chrome --virtual-time-budget로 교차 확인할 것.

관련 파일

  • /Users/ef/crowny-clean/서버.한선 · 서버.toau — 백엔드
  • /Users/ef/crowny-clean/앱.html — 프론트(고객·스태프·관리자)
  • /Users/ef/crowny-clean/앱.한선 · 앱.toau — 뷰모델 정본 + 셀프테스트 33/33
  • /Users/ef/crowny-clean/data/*.psv — append-log 영속화
  • /Users/ef/crowny-clean/fonts/PretendardVariable.woff2 — 자체 서빙 웹폰트
  • 디자인 리포트: /Users/ef/.claude/design-port/크라우니클린/리포트/

잔여 이슈

  • P1: G군(소개·선물·결제) · H군(마이·설정) · S4(특이사항 제안) · M3(자동화 학습 제안 단계)
  • P2: 반자동 승격(임계값 92%) · F5(A/S) · A6(검색). 현재 추론·규칙 승격은 미구현이며
스태프 추천 태그(confidence)만 저장·표시한다 — 수동 재배치로 서비스 가능한 상태가 P0 목표였다.
  • P3: 자동 단계 · 바타입 1080×360 · 태블릿 레일 64px
  • 실시간은 폴링 없이 화면 진입 시 조회다. WS(job.progress)·D5 동기화 실패 UI는 미구현.
  • 사진은 전부 스트라이프 플레이스홀더 — 실제 업로드 저장소·EXIF 제거 파이프라인 미구축
(서버는 exif_stripped=1 플래그만 기록).
  • 인증 없음. 역할은 쿼리 파라미터라 신뢰 경계가 없다 — 공개 전 세션·토큰 필수.
  • A군(사례·후기 목록)은 홈의 대표 사례 2건만. 목록·상세·뷰어는 미구현.

운영 중 발견한 시스템 이슈 (다른 세션 확인 요망)

crowny-monitor/모니터판.toau(pid 4293)가 [ARRAY] OOM 무한 스핀으로 /tmp/모니터판.err136GB를 쌓아 루트 디스크를 100%로 채우고 있었다. 작업 진행이 불가해 해당 프로세스를 종료하고 로그를 비웠다(디스크 136GB 회수). 근본 원인(배열 힙 고갈 후 재시도 루프)은 해당 서비스 담당 세션이 봐야 한다.