Plan — todo-app (간단한 To-Do 앱)
PDCA Phase: Plan · Feature: todo-app · 작성일: 2026-06-15
스택: Node 22 (ESM) + Express · Postgres(src/db.js) · MinIO/S3(src/s3.js) · podman 로컬 / Coolify 배포
Executive Summary
| 관점 |
요약 |
| Problem |
할 일을 기록·관리할 화면과 저장소가 없다. 현재 앱은 연결 확인용 엔드포인트(/db, /s3)만 존재한다. |
| Solution |
Postgres에 할 일(todo)을 CRUD로 저장하고, 할 일별 첨부파일은 MinIO/S3에 저장하는 단일 공용 To-Do 웹 앱. 기존 db.js/s3.js/config.js를 그대로 확장한다. |
| Function UX Effect |
브라우저에서 할 일 추가/완료/삭제, 파일 첨부·다운로드가 즉시 동작. REST API도 함께 제공해 curl/외부 연동 가능. |
| Core Value |
DB(구조화 데이터) + S3(바이너리 파일)를 함께 쓰는 가장 단순하고 실용적인 표준 패턴을 적은 코드로 제공. |
Context Anchor
| 항목 |
내용 |
| WHY |
사내 워크스페이스 샘플을 실제로 쓸 수 있는 최소 To-Do 앱으로 만들어 DB+S3 활용 패턴을 보여준다. |
| WHO |
로그인 없이 접근하는 단일 사용자/소규모 팀(단일 공용 목록). |
| RISK |
첨부파일 처리(업로드 크기/타입, presigned URL), schema 마이그레이션 누락, S3 키-DB 레코드 정합성. |
| SUCCESS |
브라우저에서 할 일 CRUD + 첨부 업로드/다운로드가 동작하고 npm run db:check/minio:check가 통과. |
| SCOPE |
IN: todo CRUD, 첨부 1개/항목, 웹 UI, REST API. OUT: 인증/멀티유저, 마감일/태그/검색, 실시간 동기화. |
1. 배경 및 목표
기존 src/server.js는 /healthz, /db, /s3, / 만 제공한다. 여기에 To-Do 도메인을 얹는다.
- 목표: "DB와 S3를 이용한 간단한 To-Do 앱"을 최소 변경으로 구현.
- 설계 원칙: 외부 연결은 반드시
src/config.js/src/db.js/src/s3.js를 경유(CLAUDE.md 규약). 비밀값은 env에서만.
- 데이터 분담: 구조화 데이터(todo 본문/상태) → Postgres, 바이너리(첨부파일) → MinIO/S3, 둘을 키로 연결.
2. 요구사항
2.1 기능 요구사항 (FR)
| ID |
요구사항 |
우선순위 |
| FR-01 |
할 일 목록 조회 (최신순) |
Must |
| FR-02 |
할 일 추가 (제목, 선택적 첨부파일 1개) |
Must |
| FR-03 |
할 일 완료/미완료 토글 |
Must |
| FR-04 |
할 일 삭제 (연결된 S3 첨부도 함께 삭제) |
Must |
| FR-05 |
첨부파일 업로드 → MinIO/S3 저장, DB에 키 기록 |
Must |
| FR-06 |
첨부파일 다운로드 (presigned URL 또는 프록시 스트리밍) |
Must |
| FR-07 |
간단한 웹 UI(HTML) — 목록/추가/완료/삭제/첨부 |
Must |
| FR-08 |
REST API(JSON) — 위 동작을 curl로도 수행 가능 |
Should |
2.2 비기능 요구사항 (NFR)
| ID |
요구사항 |
| NFR-01 |
ESM, Node 22+, 외부 연결은 config/db/s3 경유 (CLAUDE.md 규약 준수) |
| NFR-02 |
비밀값 코드/커밋 금지 — 모두 .project-env env에서 주입 |
| NFR-03 |
업로드 파일 크기 제한(예: 10MB) 및 기본 검증 |
| NFR-04 |
podman 빌드/실행 및 Coolify 동일 Dockerfile에서 동작 |
| NFR-05 |
DB schema는 앱 시작 시 멱등(idempotent) 생성 또는 마이그레이션 스크립트 제공 |
3. 범위 (Scope)
- In scope: todo CRUD, 항목당 첨부파일 1개(S3), 서버 렌더 웹 UI, JSON REST API, schema 부트스트랩.
- Out of scope: 인증/멀티유저, 마감일·태그·우선순위·검색, 다중 첨부, 실시간(WebSocket), 페이지네이션.
4. 데이터 모델 (초안)
- 첨부 S3 키 규칙(초안):
todos/{todo_id}/{원본파일명} (버킷 coolify-user-data).
- 삭제 시 DB row 삭제 + S3 object 삭제(정합성).
5. API 설계 (초안)
| Method |
Path |
설명 |
| GET |
/ |
웹 UI (할 일 목록 페이지) |
| GET |
/api/todos |
목록(JSON) |
| POST |
/api/todos |
추가 (multipart: title + 선택 file) |
| PATCH |
/api/todos/:id |
done 토글 |
| DELETE |
/api/todos/:id |
삭제(+ S3 첨부 삭제) |
| GET |
/api/todos/:id/attachment |
첨부 다운로드(presigned redirect 또는 스트리밍) |
6. 구현 항목 (모듈 단위)
| 모듈 |
작업 |
신규/수정 |
src/schema.js (또는 scripts/migrate.js) |
todo 테이블 멱등 생성 |
신규 |
src/todos.repo.js |
DB CRUD 쿼리 (pool 사용) |
신규 |
src/attachments.js |
S3 업로드/삭제/presigned URL (s3.js 확장) |
신규 |
src/routes.todos.js |
REST 라우트 핸들러 |
신규 |
src/server.js |
라우트/정적·multipart 미들웨어 연결 |
수정 |
public/index.html (또는 인라인 템플릿) |
간단한 웹 UI |
신규 |
package.json |
multer(업로드), @aws-sdk/s3-request-presigner 의존성 추가 |
수정 |
7. 의존성
- 추가 예정:
multer(multipart 업로드 파싱), @aws-sdk/s3-request-presigner(다운로드 URL). 추가 후 npm install로 lock 갱신.
- 기존:
express, pg, @aws-sdk/client-s3 재사용.
8. Success Criteria
| SC |
기준 |
검증 방법 |
| SC-01 |
브라우저에서 할 일 추가/완료/삭제가 동작 |
수동 + L2 UI 테스트 |
| SC-02 |
첨부파일 업로드 시 S3에 객체 생성, DB에 key 기록 |
/s3 또는 MinIO 확인 + DB row |
| SC-03 |
첨부 다운로드가 정상 동작 |
다운로드 후 파일 일치 확인 |
| SC-04 |
할 일 삭제 시 S3 객체도 삭제 |
삭제 후 S3 키 부재 확인 |
| SC-05 |
npm run db:check / npm run minio:check 통과 |
CLI 실행 |
| SC-06 |
podman build + podman run --env-file .project-env로 동일 동작 |
컨테이너 기동 확인 |
9. 리스크 및 대응
| 리스크 |
대응 |
gen_random_uuid() 미존재(pgcrypto) |
pgcrypto 확장 활성 확인 또는 앱에서 uuid 생성 |
| 업로드 대용량/악성 파일 |
크기 제한(10MB), content-type 화이트리스트 검토 |
| DB-S3 정합성(삭제 누락) |
삭제는 S3 먼저 시도 후 DB 삭제, 실패 시 로깅 |
| presigned URL 만료/내부 호스트 노출 |
짧은 만료 또는 서버 프록시 스트리밍 중 Design에서 택1 |
10. 다음 단계
/pdca design todo-app — 3가지 아키텍처 옵션(최소변경 / 클린 / 실용균형)을 비교하고 데이터 모델·API·다운로드 방식을 확정.