From 7bb96ef19c851503016515696ac21ed2895414f5 Mon Sep 17 00:00:00 2001 From: zenn Date: Mon, 13 Apr 2026 15:16:52 +0900 Subject: [PATCH] =?UTF-8?q?app:=20=EB=A9=80=ED=8B=B0=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EB=93=9C=EB=9E=98=EA=B7=B8=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- .env.example | 3 +- docs/deploy.md | 9 +- docs/history.md | 4 + docs/map.md | 7 +- docs/spec.md | 42 +++- docs/update.md | 7 + package-lock.json | 4 +- package.json | 2 +- src/App.vue | 336 +++++++++++++++++++++++++------ src/composables/useAuth.js | 56 ++++++ src/composables/useCategories.js | 87 ++++++++ src/composables/useTodos.js | 14 +- src/composables/useTodosBoard.js | 225 +++++++++++++++++++++ 13 files changed, 708 insertions(+), 88 deletions(-) create mode 100644 src/composables/useAuth.js create mode 100644 src/composables/useCategories.js create mode 100644 src/composables/useTodosBoard.js diff --git a/.env.example b/.env.example index 2eec8ee..21f1550 100644 --- a/.env.example +++ b/.env.example @@ -8,7 +8,7 @@ VITE_PUBLIC_APP_URL=https://todo.sori.studio # PocketBase 공개 URL(끝 슬래시 없음). 브라우저가 직접 호출한다 -VITE_POCKETBASE_URL=https://api.todo.sori.studio +VITE_POCKETBASE_URL=https://todo-pb.sori.studio # 로컬에서 PocketBase 컨테이너만 띄울 때 예시(필요 시 위 두 줄 대신 사용) # VITE_PUBLIC_APP_URL=http://127.0.0.1:5173 @@ -17,3 +17,4 @@ VITE_POCKETBASE_URL=https://api.todo.sori.studio # docker compose 기본 호스트 포트로 NAS LAN에서 접속할 때(포트는 docker-compose.yaml과 맞출 것) # VITE_PUBLIC_APP_URL=http://192.168.0.50:42881 # VITE_POCKETBASE_URL=http://192.168.0.50:42917 + diff --git a/docs/deploy.md b/docs/deploy.md index 46d96d4..e987e0a 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -2,7 +2,7 @@ ## 현재 버전 -- `v0.0.8` +- `v0.0.9` NAS에 SSH로 올리는 **전체 순서**는 `docs/nas-deploy-guide.md`에 따로 정리했다. @@ -42,9 +42,10 @@ docker compose up -d --build ### PocketBase 초기 설정 요약 -1. 관리자 UI에서 컬렉션 `todos` 생성(`title` text, `done` bool). -2. API 규칙을 배포 방식에 맞게 설정(인증 사용 시 로그인 사용자만 생성·수정 가능 등). -3. CORS 허용 출처에 웹 앱 출처를 추가한다. (LAN이면 `http://:42881`, 도메인이면 `https://todo.sori.studio` 등 **주소창과 동일**하게.) +1. `users`(auth) 컬렉션으로 사용자 계정을 만든다. +2. 컬렉션 `categories`, `todos`를 `docs/spec.md`의 스키마대로 만든다. +3. API 규칙은 “본인 데이터만 접근”을 기본으로 적용한다. (예시는 `docs/spec.md` 참고) +4. CORS 허용 출처에 웹 앱 출처를 추가한다. (LAN이면 `http://:42881`, 도메인이면 `https://todo.sori.studio` 등 **주소창과 동일**하게.) ### 선택: 관리자 자동 생성 diff --git a/docs/history.md b/docs/history.md index 6eaecd1..13cab84 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-04-13 · v0.0.9 — 멀티유저 + 카테고리 보드 도입 + +Todo를 단일 리스트에서 **로그인 사용자 기준 멀티유저** 구조로 확장하고, 카테고리 기반 보드(카테고리·항목 드래그 이동/정렬)로 전환했다. 완료 시각(`completedAt`)과 완료 항목 표시 토글을 추가해 “미리 알림” 스타일의 흐름을 유지하면서 관리 기능을 확장한다. + ## 2026-04-13 · v0.0.8 — PocketBase `user`와 `pb_data` 권한 호스트 바인드 `./pb_data`에 **`user: 1000:10`으로 기동**하면, 폴더가 root 소유이거나 비어 있을 때 SQLite가 **오류 14(unable to open database file)** 로 종료되는 경우가 잦다. 기본값에서는 `user`를 두지 않고 기동한 뒤, 필요 시 `chown` 후 `user`를 켜는 절차를 `docker-compose.yaml` 주석과 문서에 정리했다. diff --git a/docs/map.md b/docs/map.md index c2311ee..6e4ba30 100644 --- a/docs/map.md +++ b/docs/map.md @@ -2,17 +2,20 @@ ## 현재 버전 -- `v0.0.8` +- `v0.0.9` | 경로 | 역할 | | ------------------------- | ----------------------------------------- | -| `src/App.vue` | 미리 알림 스타일 UI, 목록·입력 | +| `src/App.vue` | 로그인 + 카테고리 보드 UI, 드래그 이동/정렬 | | `src/main.js` | 앱 부트스트랩, PWA 서비스 워커 등록 | | `src/style.css` | Tailwind 베이스, 모션 감소 대응 | | `src/lib/apiUrl.js` | `toApiUrl()` URL 정규화 | | `src/lib/pocketBase.js` | PocketBase 싱글톤 클라이언트 | | `src/lib/todoSchema.js` | 할 일 제목 Zod 스키마 | | `src/composables/useTodos.js` | 목록 로드·추가·완료 토글 | +| `src/composables/useAuth.js` | 로그인/로그아웃, 세션 쿠키 유지 | +| `src/composables/useTodosBoard.js` | 카테고리/할일 로드·CRUD·완료시각·드래그 이동/정렬 | +| `src/composables/useCategories.js` | (레거시) 카테고리 로드·CRUD | | `vite.config.js` | Vue 플러그인, PWA 매니페스트(`VITE_PUBLIC_APP_URL` 반영) | | `tailwind.config.js` | 테마 색·폰트 | | `docker-compose.yaml` | PocketBase(`pocketbase-todo`, `./pb_data`, 선택 `user`) + 웹(`todo-web`), 호스트 포트 42881·42917 | diff --git a/docs/spec.md b/docs/spec.md index 1ba7330..5cea14a 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -2,7 +2,7 @@ ## 현재 버전 -- `v0.0.8` +- `v0.0.9` ## 스택 @@ -14,12 +14,42 @@ ## PocketBase 컬렉션: `todos` -| 필드 | 타입 | 설명 | -| ------ | ------- | ----------- | -| `title` | text | 할 일 제목 | -| `done` | bool | 완료 여부 | +이 앱은 **로그인 사용자 기반**으로 동작한다. 권한은 “본인 데이터만 접근”을 기본으로 한다. -규칙(API 규칙)은 운영 환경에 맞게 설정한다. 로컬 개발 시에는 본인 계정에 맞는 생성·수정 권한이 있어야 한다. +### `users` (auth collection) + +- PocketBase 기본 `users` 컬렉션을 사용한다. +- 프런트는 `authWithPassword` 방식으로 로그인한다. + +### `categories` + +| 필드 | 타입 | 설명 | +| --- | --- | --- | +| `owner` | relation -> users | 카테고리 소유자 | +| `name` | text(noempty) | 카테고리 이름 | +| `order` | number | 카테고리 정렬 순서(작을수록 위) | + +### `todos` + +| 필드 | 타입 | 설명 | +| --- | --- | --- | +| `owner` | relation -> users | 할 일 소유자 | +| `category` | relation -> categories | 소속 카테고리 | +| `title` | text(noempty) | 할 일 제목 | +| `done` | bool | 완료 여부 | +| `completedAt` | date(nullable) | 완료 시각(완료 시 set) | +| `order` | number | 카테고리 내 정렬 순서(작을수록 위) | + +### API Rules(권장) + +아래는 “로그인 사용자 본인 데이터만”을 기준으로 한 예시다. (컬렉션/필드 이름은 실제 설정과 동일해야 한다.) + +- **categories**: list/view/create/update/delete + - `@request.auth.id != "" && owner = @request.auth.id` +- **todos**: list/view/create/update/delete + - `@request.auth.id != "" && owner = @request.auth.id` + +`create` 규칙은 레코드에 `owner`를 포함해 저장하는 것을 전제로 한다. 프런트에서 `owner`를 항상 설정한다. ## 환경 변수 diff --git a/docs/update.md b/docs/update.md index ec19dd0..663cf83 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,12 @@ # 업데이트 로그 +## v0.0.9 + +- ~추가. 로그인 기반 멀티유저(`users` auth) + 카테고리 보드 UI. +- ~추가. 완료 시각(`completedAt`), 완료 항목 표시 토글. +- ~추가. 카테고리 CRUD + 카테고리/항목 드래그 이동·정렬(기본 HTML5 DnD). +- ~수정. `docs/spec.md`, `docs/deploy.md`, `docs/map.md` 스키마·가이드 동기화. + ## v0.0.8 - ~수정. PocketBase `unable to open database file (14)` 대비: 기본 `user` 비활성화(주석), `pb_data` 권한 안내·13절 표 추가. diff --git a/package-lock.json b/package-lock.json index 155eff3..37e5dd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "todo", - "version": "0.0.1", + "version": "0.0.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "todo", - "version": "0.0.1", + "version": "0.0.8", "dependencies": { "pocketbase": "^0.25.1", "vue": "^3.5.13", diff --git a/package.json b/package.json index 97f850a..268aab5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "todo", "private": true, - "version": "0.0.8", + "version": "0.0.9", "type": "module", "scripts": { "dev": "vite", diff --git a/src/App.vue b/src/App.vue index 71664af..5e3a0c4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,10 +1,84 @@