# Analysis (Check) — todo-app > PDCA Phase: **Check** · Feature: `todo-app` · 작성일: 2026-06-15 > 상위: [Plan](../01-plan/features/todo-app.plan.md) · [Design](../02-design/features/todo-app.design.md) ## Context Anchor | 항목 | 내용 | |------|------| | WHY | 사내 샘플을 실제 쓰는 최소 To-Do 앱으로 — DB+S3 패턴 시연 | | WHO | 로그인 없는 단일 공용 목록 | | RISK | 첨부 처리, schema 마이그레이션, S3-DB 정합성 | | SUCCESS | 브라우저 CRUD + 첨부 업/다운로드, db/minio check 통과 | | SCOPE | IN: todo CRUD + 첨부 1개 + 웹UI + API / OUT: 인증·태그·검색 | ## Match Rate | 축 | 점수 | 가중치 | 기여 | |----|:----:|:------:|:----:| | Structural | 100% | 0.15 | 15.0 | | Functional | 96% | 0.25 | 24.0 | | Contract | 100% | 0.25 | 25.0 | | Runtime (L1) | 100% | 0.35 | 35.0 | | **Overall** | **99%** | | | > 런타임 실행 공식 적용(서버 기동). 16/16 L1 테스트 통과, 서버 로그 에러 없음. ## 1. Structural Match — 100% Design §2 모듈 구조 전부 존재, §4 라우트 6개(`GET /`, `GET/POST /api/todos`, `PATCH/DELETE /api/todos/:id`, `GET /api/todos/:id/attachment`) 모두 구현·마운트 확인. ## 2. Functional Depth — 96% | 항목 | 결과 | |------|------| | 업로드 보상 삭제(§5,§6) | ✅ 업로드 실패 시 `repo.remove` | | 삭제 시 S3 선삭제 후 DB(§6) | ✅ best-effort 로깅 후 진행 | | pgcrypto fallback(§3) | ✅ 런타임에서 실제 발동 확인(`permission denied`→`randomUUID`) | | 입력 검증(title/uuid/done) | ✅ | | placeholder/미구현 | 없음 | **−4% 사유 (Minor)**: Design §5는 "단일 INSERT(첨부 키 포함)"로 기술됐으나, 구현은 "INSERT → setAttachment UPDATE" 2단계. 동작·정합성은 동일(오히려 id 기반 키 생성에 더 적합). 문서-구현 표현 불일치만 존재. ## 3. API Contract — 100% (3자 검증) Design §4 ↔ `src/routes.todos.js` ↔ `public/index.html` fetch 호출 일치: - 응답 envelope `{data}` / `{error}` ✅ - `hasAttachment` 노출 + `attachment_key` 비노출 ✅ (런타임 L1-8 검증) - 상태코드(201/400/404/413/204/200) 일치 ✅ - 다운로드 `Content-Disposition` 헤더 ✅ (L1-10) ## 4. Runtime Verification (L1) — 16/16 PASS | # | 검증 | 기대 | 결과 | |---|------|:----:|:----:| | 1 | GET / | 200 | ✅ | | 2-3 | GET /api/todos + {data} | 200 | ✅ | | 4 | POST title | 201 | ✅ | | 5-6 | POST no title + {error} | 400 | ✅ | | 7 | 첨부 hasAttachment | true | ✅ | | 8 | attachment_key 비노출 | — | ✅ | | 9-10 | 다운로드 + Content-Disposition | 200 | ✅ | | 11 | PATCH done | 200 | ✅ | | 12-14 | PATCH bad uuid/no done/404 | 400/400/404 | ✅ | | 15 | DELETE | 204 | ✅ | | 16 | 삭제 후 다운로드(cascade) | 404 | ✅ | ## 5. Success Criteria 평가 | SC | 상태 | 근거 | |----|:----:|------| | SC-01 CRUD UI | ✅ Met | L1 + public/index.html | | SC-02 업로드→S3+DB key | ✅ Met | L1-7, S3 객체 생성 | | SC-03 다운로드 | ✅ Met | L1-9/10 내용 일치 | | SC-04 삭제 시 S3도 삭제 | ✅ Met | L1-16 cascade | | SC-05 db/minio check | ✅ Met | 둘 다 통과 | | SC-06 podman | ⚠️ Partial | Dockerfile 무변경으로 빌드 가능하나 이 세션 미실행 | ## 6. Decision Record 준수 검증 | 결정 | 준수 | |------|:----:| | Option C(repo/attachments/routes 분리) | ✅ | | 서버 프록시 스트리밍(presigned 미사용) | ✅ `GetObjectCommand` pipe | | pgcrypto + randomUUID fallback | ✅ 런타임 발동 | | 변경점: multer 1.x→2.1.1 | ✅ 의도된 보안 대응, API 동일 | ## 7. Gap 목록 | ID | Severity | 내용 | 조치 | |----|:--------:|------|------| | G1 | Minor | §5 단일 INSERT 서술 vs 2단계 구현 | 문서 동기화(선택) | | G2 | Minor | SC-06 podman 빌드 미검증 | 컨테이너 빌드 1회 권장 | | G3 | Minor | 파일 content-type 화이트리스트 미적용(NFR-03 일부) | OUT-of-scope 수준, 향후 | **Critical/Important 갭: 0건.** ## 8. 결론 Overall **99%** (≥90% 목표 달성). Critical/Important 이슈 없음. Minor 3건은 모두 문서/범위 외/검증 절차 항목으로 코드 수정 불요. → iterate 없이 **QA 또는 report** 단계로 진행 가능.