diff --git a/.planning/STATE.md b/.planning/STATE.md index ac89fb5..d434cf1 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,9 +2,9 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone -current_phase: 3 -status: executing -last_updated: "2026-05-24T19:21:17.122Z" +current_phase: 4 +status: ready +last_updated: "2026-05-25T00:00:00Z" progress: total_phases: 5 completed_phases: 3 @@ -16,9 +16,9 @@ progress: # Project State **Project:** DocuVault -**Status:** Phase 3 In Progress — Plan 05 Tasks 1-2 Complete (awaiting human checkpoint) -**Current Phase:** 3 -**Last Updated:** 2026-05-23 +**Status:** Phase 3 Complete — Ready to begin Phase 4 +**Current Phase:** 4 +**Last Updated:** 2026-05-25 ## Phase Status @@ -26,15 +26,15 @@ progress: |---|---|---| | 1 | Infrastructure Foundation | ✓ Complete | | 2 | Users & Authentication | ✓ Complete (5/5 plans) | -| 3 | Document Migration & Multi-User Isolation | In Progress (5/5 plans — checkpoint pending) | +| 3 | Document Migration & Multi-User Isolation | ✓ Complete (5/5 plans, 10/10 UAT, security gate passed) | | 4 | Folders, Sharing, Quotas & Document UX | Not Started | | 5 | Cloud Storage Backends | Not Started | ## Current Position -**Phase:** 03-document-migration-multi-user-isolation — In Progress -**Plan:** 5/5 tasks 1-2 done; Task 3 checkpoint awaiting human verification -**Progress:** ████░░░░░░ 57% (2/5 phases complete, 14/15 plans committed; Phase 3 checkpoint pending) +**Phase:** 04-folders-sharing-quotas-document-ux — Ready to start +**Plan:** 0/N — awaiting /gsd:discuss-phase 4 +**Progress:** ██████░░░░ 60% (3/5 phases complete) ## Performance Metrics @@ -109,6 +109,22 @@ progress: - Verify cloud SDK minor versions on PyPI before Phase 5 pinning +### Workflow Changes (2026-05-25) + +Two mandatory cross-cutting gates added to all phases going forward: + +**1. Test gate** — every plan must leave `pytest -v` passing with zero failures. Every new function/endpoint/component requires at least one test. All security-invariant negative tests (wrong owner, admin block, token replay) must exist and pass. + +**2. Security gate** — a security agent runs after every plan execution and is a blocking requirement before phase advancement. It: +- Runs `bandit -r backend/`, `pip audit`, `npm audit --audit-level=high` +- Checks for path traversal, IDOR, SSRF, timing attacks, mass assignment, token replay +- Verifies admin endpoints never return `password_hash`, `credentials_enc`, or document content +- Fixes issues directly (full edit access) rather than deferring + +**3. Bug fix rule** — all fixes: root cause only, ≤50 lines, regression test required, no workarounds. + +See CLAUDE.md "Testing Protocol" and "Security Protocol" sections for full detail. + ### Blockers None. @@ -119,7 +135,8 @@ _Updated at each phase transition._ | Field | Value | |---|---| -| Last session | 2026-05-23 — Executed Plan 03-05 (3-step XHR upload, QuotaBar, UploadProgress error block) | -| Next action | Human checkpoint Task 3: test upload/quota/413 flow in browser; type "approved" or describe failures | +| Last session | 2026-05-25 — Phase 3 UAT complete (10/10); security gate passed (3 fixes: bandit B324, Referrer-Policy, IDOR on /topics/suggest); test fix for test_lmstudio.py import | +| Last session | 2026-05-25 — Phase 4 context gathered (4 areas: folder nav, sharing, PDF proxy, audit log) | +| Next action | Run `/gsd:plan-phase 4` to create execution plan | | Pending decisions | None | -| Resume file | `.planning/phases/03-document-migration-multi-user-isolation/03-05-SUMMARY.md` | +| Resume file | `.planning/phases/04-folders-sharing-quotas-document-ux/04-CONTEXT.md` | diff --git a/.planning/phases/04-folders-sharing-quotas-document-ux/04-CONTEXT.md b/.planning/phases/04-folders-sharing-quotas-document-ux/04-CONTEXT.md new file mode 100644 index 0000000..5049d47 --- /dev/null +++ b/.planning/phases/04-folders-sharing-quotas-document-ux/04-CONTEXT.md @@ -0,0 +1,154 @@ +# Phase 4: Folders, Sharing, Quotas & Document UX - Context + +**Gathered:** 2026-05-25 +**Status:** Ready for planning + + +## Phase Boundary + +Deliver a complete document management experience on top of the Phase 3 multi-user foundation: folder organization (create/rename/delete/move, breadcrumb navigation, sort), document sharing by exact handle with immediate revocation, quota feedback (already-built QuotaBar, upload rejection with detailed error), PDF in-browser preview proxied through the app with a per-user open-mode preference, full-text search via PostgreSQL tsvector, and an admin audit log viewer with export and daily automated CSV backups. + +This phase does NOT include cloud storage backend connectivity (Phase 5). The QuotaBar component and upload rejection flow are already built (Phase 3) — Phase 4 wires the remaining document UX features around them. + + + + +## Implementation Decisions + +### Folder Navigation Layout + +- **D-01:** Hybrid layout — AppSidebar shows top-level folders only (no nested expansion in sidebar). Once inside a folder, the main content area shows sub-folder rows + breadcrumb navigation. Top-level folders in sidebar are clickable to navigate directly. +- **D-02:** Unlimited nesting depth — no API or UI cap. The `Folder.parent_id` self-referential FK is the authoritative constraint. Breadcrumbs truncate long paths with an ellipsis when path depth > N segments. +- **D-03:** Non-empty folder delete shows a warning modal that includes the document count (e.g., "This folder contains 5 documents. Deleting it will permanently delete all documents inside."). If the user confirms, cascade-delete all documents (MinIO objects + DB rows + quota decrements) and the folder. If the user cancels, no action taken. Documents are NOT moved to root — they are destroyed with the folder. + +### Sharing + +- **D-04:** Exact handle input — user types the recipient's handle (no `@` prefix required by API, but UI may accept it). No autocomplete or user search endpoint needed. API returns 404 if handle not found; UI shows a clear "User not found" error. +- **D-05:** Share button is on the DocumentCard (inline icon button). Clicking opens a sharing modal containing: (a) a text input for the recipient handle, (b) a "Share" submit button, (c) a list of current recipients with their permission level and a "Revoke" button per row. +- **D-06:** "Shared with me" is a fixed virtual folder entry in AppSidebar, rendered above the user's own folder list. It is not stored as a real folder — the backend filters by `shares.recipient_id = current_user.id`. Shared documents count zero bytes against the recipient's quota (SHARE-02). +- **D-07:** Share permission is `view` only for Phase 4 (SHARE-03 — owner controls permission level; only `view` implemented; `edit` deferred). + +### PDF Proxy & Preview + +- **D-08:** Streaming proxy endpoint: `GET /api/documents/{id}/content` retrieves bytes from MinIO via the storage backend and returns them via FastAPI `StreamingResponse`. Supports `Range` headers for partial content (large file performance). `Content-Disposition: inline` with correct `Content-Type` from the document's `content_type` column. No presigned URL is ever generated or exposed to the browser (DOC-02 privacy model). +- **D-09:** Native browser PDF rendering — no PDF.js library. DOC-02 specifies PDF.js but the user explicitly chose native rendering (intent over literal spec). Content-Type header drives browser rendering. Zero frontend dependencies added. +- **D-10:** Per-user PDF open preference stored in DB. New column `users.pdf_open_mode` (String, default `'in_app'`, allowed values: `'in_app'` | `'new_tab'`). Exposed via `PATCH /api/me/preferences` endpoint. Setting is shown in SettingsView for all users (not admin-only). + - `in_app`: PDF opens in a modal/overlay containing `