구조 · 문제점 · UI/UX 검증 보고서
1프로젝트 구조 파악
레포 전체 tracked 99파일 / 10.4MB. 앱은 의존성 0의 단일 파일이며, 규모 대비 조직 상태가 좋습니다.
| 경로 | 역할 | 상태 |
|---|---|---|
app/index.html | 앱 전체 — 바닐라 JS, localStorage 원장 + SHA-256 해시체인. 6,651줄/637KB | 건강 전역 이름 중복 정의 0건, 핵심 엔진(append·verifyChain·renderHwpTable) 각 20줄 이하 |
templates/ | HWP 레이아웃 — 트리밍 41개 + 기계추출 원본 5개 | 앱 임베드 상수 42개와 수동 동기화 (하네스가 방어) |
forms-dictionary.json | 서식 필드 사전 — 39서식 / 254필드 | 문서 불일치 README는 "25종 372필드" |
mappings/ | 행위 카탈로그 41 + 행위→서식 매핑 39 | 행위 2건 미매핑 상태를 하네스가 정상으로 잠금 |
worker/ | 캐플 온도계 수신 CF Worker + D1 (425줄) | 기대 이상 SQL 전부 파라미터 바인딩, XSS 이스케이프 |
verify/ | 회귀 하네스 (static 305 · final 109) | PASS 이 맥에서 독립 재실행 검증 완료 |
docs/ | 설계·규정 KB·PT 자료 (v2 + astra 1·2·3) | 미푸시 09-07 작업분 약 50파일이 Drive에만 존재 |
app/index.html 내부 분포
| 구간 | 비중 | 내용 |
|---|---|---|
| RENDER.* 화면 34개 | 32% | 뷰 핸들러 (최대: adminperiodic ~428줄, ledgerlist ~426줄) |
| FORM_VIEWS 40종 | 32% | 원장→종이서식 재구성 (단일 객체 리터럴 ~1,200줄) |
| HWP 임베드 데이터 | 18% | 레이아웃 상수 42개 = 89KB. 부피의 주범은 로직이 아니라 데이터 |
| 엔진 + 원장 + 헬퍼 | 13% | append(474행)·verifyChain(484행)·SENSOR_MAP_DEFAULT(1248행) 등 |
2즉시 조치 — PT 전 필수 P0
SENSOR_MAP_DEFAULT에서 fridge와 frz1이 동일 시리얼 2569-6911. 냉동1 실측(-18℃대)이 냉장 기준(-2~5℃) 칸에 들어가 기본 상태에서 CCP-1B가 매번 빨간 부적합으로 렌더됩니다. PT 스크린샷·라이브 데모 양쪽에 걸리는 기존 🔴 과제 — 실제 냉장 온도계 배치 + 매핑 교체가 근본 해결이고, 그 전까지는 최소한 기본값을 "미매핑=빈칸"으로 되돌리는 판단이 필요합니다.
09-07 작업분 — PT 정본 v2(pt-deck-v2.pdf/html/md, pt-business-plan-v2.md, step1-facts.md)와 astra2·astra3 패키지 등 docs 약 50개 파일 + LOG.md 갱신 — 이 Drive에만 있고 push되지 않았습니다. Drive는 병합·이력이 없는 저장소라 동기화 충돌·실수 삭제 한 번에 PT 제출물이 날아갑니다. 다음 윈도우 CTO 세션에서 commit+push가 1순위.
동일 이벤트가 홈 Audit Log에는 20:48:42, 원장 블록에는 11:48:42로 정확히 9시간 차이. "위조 불가능한 원장"을 파는 제품에서 화면 간 시각 불일치는 심사장 질문 한 방에 무너지는 지점입니다. 표시 계층에서 KST 통일 필요(원장 저장값 변경 아님 — 렌더만).
제외/유예 중 택일이 안 된 상태라 센서 화면 캡처마다 빨간 부적합이 찍힙니다(-17.9℃가 '-18 이하' 기준에 걸리는 사례 포함). PT 캡처 품질과 직결되므로 ①과 함께 이번 주 결정 권장.
3단기 — 데모 공개 품질 P1
TEST 칩·팝업은 마커 검색으로 쉽게 제거되지만, 원장 화면의 id="seedBtn"(데모 1년치 시드)은 마커 밖이라 놓치기 쉽습니다. 실원장에 가짜 1년치를 소급 적재하는 버튼이라 삭제 버튼보다 오히려 위험합니다. PIN 하드코딩 안내문(1497행)도 함께 제거 대상.
3단 드릴다운을 들어가도 URL·history 불변 → 모바일에서 뒤로가기 제스처 한 번에 앱 통째 이탈. 현장 직원의 가장 흔한 조작입니다. go() 라우터에 hash 히스토리(pushState) 연동 권장.
PIN 패드처럼 잘 만든 자체 모달이 이미 있는데, 파괴적 동작 확인이 문맥 없는 OS 다이얼로그입니다. 앱 모달로 통일 권장 — 자동화·테스트 하네스와의 궁합도 좋아집니다.
HWP 표(642px)가 컨테이너(354px)를 넘어 '기록(예/아니오)' 열이 화면 밖 — 스크롤은 되지만 그라데이션/화살표 힌트가 없어 비전문가는 열 존재 자체를 모를 수 있습니다. 390px에서 홈 AUDIT LOG 패널이 대체 안내 없이 사라지는 것도 동일 맥락.
일지 카드에 서식코드·오늘 작성/승인 배지가 없어 점검 탭 완료 상태와 단절 / 심사 뷰 17,267px 중 대부분이 12개월 캘린더(화면용 미니 히트맵·접기 권장, 인쇄는 유지) / 시드 실행 60초+ 인데 진행 안내 없음.
README "25종 372필드" → 실제 39서식 254필드 (haccp-knowledge.md:237이 이미 자체 교정해 둠) / DEV-HANDOFF "실물 시연 필요" → 09-03 결정(평가장 시연·반입 금지)과 정면 충돌 / CLAUDE.md "130KB+" → 실제 637KB(4.9배, 컨텍스트 절약 규칙의 근거 수치라 오도).
4기술부채 — 워커·레포 위생 P2
| 항목 | 내용 | 위치 |
|---|---|---|
| /status 토큰이 URL 쿼리 | 다른 엔드포인트는 X-Read-Token 헤더인데 여기만 쿼리스트링 — 히스토리·리퍼러·로그에 토큰 잔류 | worker/src/index.js:342 |
| 전역 try/catch 부재 | D1 예외 시 500 + 스택 그대로 노출 | worker/src/index.js:387–417 |
| raw_events 무제한 증가 | 보존정책·TTL·정리 크론 전무 + observability 미설정이라 관측 수단도 없음. 5분 폴링 × 장비수로 영구 누적 | worker/schema.sql, wrangler.jsonc |
| D1 N+1 쿼리 | 장비별 순차 await, batch() 미사용 — 현재 4대는 무해, 확장 시 병목 | worker/src/index.js:126–174 |
| HWP 3중 중복 7.3MB | 루트 *.hwp = meating/*.hwp (md5 동일) = meating.zip. 10.4MB 중 70%가 중복 — meating.zip untrack부터 | 레포 루트 |
| 죽은 함수 7개 | yearCorrected·nonconformList·complaintList·recallList·visitorList·planRowsOf·rawPaper — 호출 0회 | app/index.html:575,616–619,2696,5289 |
| 하네스 크롬 경로 | 기본값이 특정 개발자 윈도우 경로 하드코딩 — 그 외 전원 CHROME 환경변수 필수 (README엔 선택처럼 기술) | verify/*-verify.js:18 |
| git 이력 계정 메타 | 커밋 08aac19에 CF 계정 ID·이메일(dev@onoffer.kr) — 현재는 삭제·gitignore 완료, 공개 전환 시에만 history rewrite | git history |
✅ 확인된 무결 사항: 앱·워커 코드에 시크릿 하드코딩 없음(전부 env 바인딩·헤더 전송) · .gitignore는 예방적으로 잘 작성됨(private/·.omc/ 커밋 이력 0) · SQL 인젝션 없음 · XSS 이스케이프 적용.
5UI/UX 잘 된 점 (지킬 것)
- 예외 보고형 점검 위저드 — "해당 없음이 정상, 이상 있을 때만 탭" + 원탭 확정. 현장 부담 최소화 설계가 탁월.
- PIN 서명 모달 — 전자서명 4요소 설명·역할 칩·자동 역할 구분까지 안내 충분.
- 서명 직후 피드백 — "일지 자동 기재 — ○○서식 §1~4" 식으로 어느 칸이 채워졌는지 즉시 표시. 점검→일지 멘탈모델 연결이 훌륭.
- 정직한 한계 고지 — "이 화면의 데이터 한계 — 숨기지 않고 적습니다" 카피 품질.
- 성능 — 1년치 2,737블록에서도 50건 페이지네이션·콘솔 에러 0건·심사 뷰 DOM 경량(2,175 노드).
6액션 플랜
| 순위 | 액션 | 담당 | 비고 |
|---|---|---|---|
| P0 | Drive 09-07 작업분 commit+push | CTO (윈도우 세션) | PT 제출물 유실 방지 — 다음 세션 첫 작업 |
| P0 | 냉장 온도계 실배치 + fridge 매핑 교체 (전까지 기본값 빈칸 검토) | 대표 + CTO | 기존 🔴 과제, PT 캡처 직결 |
| P0 | 원장 표시 타임스탬프 KST 통일 (렌더만, 저장값 불변) | executor 위임 | 수정 후 하네스 305·109 필수 |
| P0 | 제상 스파이크 판정 기준 결정 (제외/유예) | 대표 | 결정만 하면 구현은 소규모 |
| P1 | TEST-ONLY 3개소 + seedBtn(6007) + PIN 안내문(1497) 일괄 제거 절차 문서화 | executor 위임 | 파일럿 실기록 시작 전 필수 |
| P1 | go() 라우터 hash 히스토리 연동 (뒤로가기) | executor 위임 | 모바일 이탈 방지 |
| P1 | alert/confirm(92곳) → 앱 모달 단계적 통일 (파괴적 동작부터) | executor 위임 | — |
| P1 | 모바일 스크롤 힌트 + AUDIT LOG 안내 + 서식 카드 상태 배지 | executor 위임 | — |
| P1 | README 수치·DEV-HANDOFF 시연 문구·CLAUDE.md 크기 정정 | CTO | 심사·개발자가 읽는 숫자 |
| P2 | 워커: /status 헤더화 + 전역 try/catch + raw_events 보존정책 + observability | 백엔드 개발자 | 서버 원장 착수와 묶어 전달 |
| P2 | meating.zip untrack + 죽은 함수 7개 제거 + 하네스 크롬 경로 크로스플랫폼 | executor 위임 | — |
| 보류 | 단일 파일 분할 | — | 비권장 — 중복 정의 0·엔진 깨끗·부피는 임베드 데이터. 분할하면 프리프린트 방어선(static-verify)을 통째로 재작성해야 함 |
7검증 방법 (전부 공개)
① 회귀 하네스 독립 실행 — 이 맥, GitHub 클론본에서:
cd scratchpad/snaplog/verify npm i CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" npm run all → PASS 305 · FAIL 0 / PASS 109 · FAIL 0 (기준선 동일, 회귀 없음)
② 레포 스캔 — GitHub main(8721e64) 클론본 정적 분석(읽기 전용, 무수정). Drive 대조는 Drive API 메타데이터 기준.
③ UI/UX — snaplog-demo.pages.dev를 실브라우저(Chrome)로 5탭 전수 + 390px iframe 근사. 이 과정에서 이 맥 브라우저의 localStorage에만 데모 변경 3건 발생(체크인 서명 1·팀장 승인 1·1년치 시드 — 삭제는 안 함). 서버 없음·브라우저별 저장이라 다른 기기에 영향 없음. ⚠️ 미검증으로 남긴 것: 시드 버튼 자체의 진행 표시 UI(네이티브 confirm 우회로 함수 직접 호출), 실기기 터치·PIN 모달 모바일 렌더링(iframe 근사 한계).