132 lines
6.8 KiB
Markdown
132 lines
6.8 KiB
Markdown
# 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. 데이터 모델 (초안)
|
|
|
|
```
|
|
table todo (
|
|
id uuid pk default gen_random_uuid(),
|
|
title text not null,
|
|
done boolean not null default false,
|
|
attachment_key text null, -- S3 object key (없으면 null)
|
|
attachment_name text null, -- 원본 파일명
|
|
attachment_type text null, -- content-type
|
|
created_at timestamptz not null default now()
|
|
)
|
|
```
|
|
- 첨부 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·다운로드 방식을 확정.
|