docs(25-00): complete file system foundation plan — schema, types, validators, test stubs
- Create 25-00-SUMMARY.md with full plan documentation - Update STATE.md: advance to plan 2/4, record metrics and decisions - Update ROADMAP.md: phase 25 in progress (1/4 summaries) - Update REQUIREMENTS.md: mark FILE-01, FILE-02, FILE-03 complete
This commit is contained in:
parent
f335d3762b
commit
5393ba0947
4 changed files with 146 additions and 20 deletions
|
|
@ -83,9 +83,9 @@
|
|||
|
||||
### File System (13)
|
||||
|
||||
- [ ] **FILE-01** — Local file storage directory structure under `<nexus-root>/files/` with subdirectories: `projects/<slug>/assets/`, `projects/<slug>/docs/`, `projects/<slug>/generated/`, `projects/<slug>/placeholders/`, `chat/<conversation-id>/`, and `exports/`
|
||||
- [ ] **FILE-02** — libSQL `files` table tracking all file metadata: id, filename, original_filename, mime_type, size_bytes, storage_path, git_hash, checksum, dual-scope fields (project_id, conversation_id, message_id, agent_id, workspace_id, task_id), source, category, placeholder fields, and lifecycle timestamps
|
||||
- [ ] **FILE-03** — libSQL `file_references` table enabling a single file to be referenced from multiple conversations without duplication
|
||||
- [x] **FILE-01** — Local file storage directory structure under `<nexus-root>/files/` with subdirectories: `projects/<slug>/assets/`, `projects/<slug>/docs/`, `projects/<slug>/generated/`, `projects/<slug>/placeholders/`, `chat/<conversation-id>/`, and `exports/`
|
||||
- [x] **FILE-02** — libSQL `files` table tracking all file metadata: id, filename, original_filename, mime_type, size_bytes, storage_path, git_hash, checksum, dual-scope fields (project_id, conversation_id, message_id, agent_id, workspace_id, task_id), source, category, placeholder fields, and lifecycle timestamps
|
||||
- [x] **FILE-03** — libSQL `file_references` table enabling a single file to be referenced from multiple conversations without duplication
|
||||
- [ ] **FILE-04** — Dual scoping: a file uploaded during a project-linked conversation lives in `files/projects/<slug>/` but is also referenced by the chat message; a file in a general chat (no project context) lives in `files/chat/<conversation-id>/`
|
||||
- [ ] **FILE-05** — File upload from chat input via drag-and-drop or button; file is stored on disk and its metadata is written to libSQL
|
||||
- [ ] **FILE-06** — Inline file preview in chat: images render inline, PDFs show a first-page preview, code files show a syntax-highlighted preview
|
||||
|
|
@ -168,9 +168,9 @@ The following are explicitly deferred:
|
|||
| PERF-03 | Phase 22 | Complete |
|
||||
| PERF-04 | Phase 24 | Complete |
|
||||
| PERF-05 | Phase 26 | Pending |
|
||||
| FILE-01 | Phase 25 | Pending |
|
||||
| FILE-02 | Phase 25 | Pending |
|
||||
| FILE-03 | Phase 25 | Pending |
|
||||
| FILE-01 | Phase 25 | Complete |
|
||||
| FILE-02 | Phase 25 | Complete |
|
||||
| FILE-03 | Phase 25 | Complete |
|
||||
| FILE-04 | Phase 25 | Pending |
|
||||
| FILE-05 | Phase 25 | Pending |
|
||||
| FILE-06 | Phase 25 | Pending |
|
||||
|
|
|
|||
|
|
@ -116,10 +116,10 @@ Plans:
|
|||
5. When an agent generates a placeholder asset, `PLACEHOLDERS.md` is updated in the project directory; when the placeholder is replaced, the DB records the replacement chain and the manifest reflects the change
|
||||
6. A file uploaded in a conversation linked to a project lives in `files/projects/<slug>/`; a file from an unlinked conversation lives in `files/chat/<conversation-id>/`; the user can promote a chat file to project scope
|
||||
7. Voice input is available when local AI is enabled: user can hold the record button, speak, see a transcription preview, and confirm to send
|
||||
**Plans:** 4 plans
|
||||
**Plans:** 1/4 plans executed
|
||||
|
||||
Plans:
|
||||
- [ ] 25-00-PLAN.md — DB schema (chat_files + chat_file_references), shared types/validators, test stubs
|
||||
- [x] 25-00-PLAN.md — DB schema (chat_files + chat_file_references), shared types/validators, test stubs
|
||||
- [ ] 25-01-PLAN.md — Server: chatFileService + chatFileRoutes (upload, download, list, references)
|
||||
- [ ] 25-02-PLAN.md — UI: ChatInput file upload (drag-drop, paste, file picker), useChatFileUpload hook
|
||||
- [ ] 25-03-PLAN.md — UI: ChatFilePreview/ChatFileCard components, ChatMessage/ChatPanel wiring
|
||||
|
|
@ -222,5 +222,5 @@ All 65 v1 requirements are mapped to exactly one phase. No orphans.
|
|||
| 22. Agent Streaming | v1.3 | 6/6 | Complete | 2026-04-01 |
|
||||
| 23. Brainstormer Flow | v1.3 | 4/4 | Complete | 2026-04-01 |
|
||||
| 24. Search, History & Branching | v1.3 | 4/4 | Complete | 2026-04-01 |
|
||||
| 25. File System | v1.3 | 0/4 | Planned | - |
|
||||
| 25. File System | v1.3 | 1/4 | In Progress| |
|
||||
| 26. PWA & Performance | v1.3 | 0/? | Not started | - |
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
gsd_state_version: 1.0
|
||||
milestone: v1.3
|
||||
milestone_name: milestone
|
||||
status: verifying
|
||||
stopped_at: Completed 24-search-history-branching-24-03-PLAN.md
|
||||
last_updated: "2026-04-01T22:47:24.431Z"
|
||||
status: executing
|
||||
stopped_at: Completed 25-file-system-25-00-PLAN.md
|
||||
last_updated: "2026-04-01T23:02:27.025Z"
|
||||
last_activity: 2026-04-01
|
||||
progress:
|
||||
total_phases: 6
|
||||
completed_phases: 4
|
||||
total_plans: 21
|
||||
completed_plans: 21
|
||||
total_plans: 25
|
||||
completed_plans: 22
|
||||
percent: 100
|
||||
---
|
||||
|
||||
|
|
@ -21,13 +21,13 @@ progress:
|
|||
See: .planning/PROJECT.md (updated 2026-03-30)
|
||||
|
||||
**Core value:** Fresh onboard asks for ONE thing (root directory), auto-creates PM + Engineer, drops you in dashboard — no corporate language anywhere.
|
||||
**Current focus:** Phase 24 — search-history-branching
|
||||
**Current focus:** Phase 25 — file-system
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 25
|
||||
Plan: Not started
|
||||
Status: Phase complete — ready for verification
|
||||
Phase: 25 (file-system) — EXECUTING
|
||||
Plan: 2 of 4
|
||||
Status: Ready to execute
|
||||
Last activity: 2026-04-01
|
||||
|
||||
Progress: [██████████] 100%
|
||||
|
|
@ -78,6 +78,7 @@ Progress: [██████████] 100%
|
|||
| Phase 24-search-history-branching P01 | 12 | 2 tasks | 2 files |
|
||||
| Phase 24-search-history-branching P02 | 3min | 2 tasks | 7 files |
|
||||
| Phase 24-search-history-branching P03 | 4 | 3 tasks | 7 files |
|
||||
| Phase 25-file-system P00 | 6 | 2 tasks | 11 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
|
|
@ -132,6 +133,9 @@ Recent decisions affecting current work:
|
|||
- [Phase 24-search-history-branching]: Custom event nexus:open-chat-search routes search trigger through CommandPalette without Cmd+K conflict
|
||||
- [Phase 24-search-history-branching]: Branch-on-edit checks editedIdx < messages.length - 1 before calling branchConversation
|
||||
- [Phase 24-search-history-branching]: bookmarkedMessageIds as Set<string> for O(1) lookup rebuilt from useChatBookmarks per-conversation data
|
||||
- [Phase 25-file-system]: Used object-syntax (table) => ({}) for Drizzle index callbacks in chat_files and chat_file_references — matches existing codebase pattern
|
||||
- [Phase 25-file-system]: chatFiles uses nullable FKs (SET NULL) for conversationId/messageId — file may exist before a conversation or message is created
|
||||
- [Phase 25-file-system]: chatFileReferences uses CASCADE deletes for fileId and conversationId — reference has no meaning without both anchors
|
||||
|
||||
### Pending Todos
|
||||
|
||||
|
|
@ -144,6 +148,6 @@ None yet.
|
|||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-01T22:41:16.958Z
|
||||
Stopped at: Completed 24-search-history-branching-24-03-PLAN.md
|
||||
Last session: 2026-04-01T23:02:27.021Z
|
||||
Stopped at: Completed 25-file-system-25-00-PLAN.md
|
||||
Resume file: None
|
||||
|
|
|
|||
122
.planning/phases/25-file-system/25-00-SUMMARY.md
Normal file
122
.planning/phases/25-file-system/25-00-SUMMARY.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
phase: 25-file-system
|
||||
plan: "00"
|
||||
subsystem: db-schema
|
||||
tags: [database, schema, migrations, shared-types, validators, test-stubs]
|
||||
dependency_graph:
|
||||
requires: []
|
||||
provides:
|
||||
- chatFiles Drizzle schema (packages/db/src/schema/chat_files.ts)
|
||||
- chatFileReferences Drizzle schema (packages/db/src/schema/chat_file_references.ts)
|
||||
- SQL migrations 0053 and 0054
|
||||
- ChatFile, ChatFileReference types from @paperclipai/shared
|
||||
- uploadChatFileSchema, createFileReferenceSchema validators
|
||||
affects:
|
||||
- packages/db/src/schema/index.ts
|
||||
- packages/shared/src/types/chat.ts
|
||||
- packages/shared/src/validators/chat.ts
|
||||
- packages/shared/src/index.ts
|
||||
tech_stack:
|
||||
added: []
|
||||
patterns:
|
||||
- Drizzle pgTable with object-syntax index callback (table) => ({})
|
||||
- UUID FK with onDelete: "set null" for nullable cross-table references
|
||||
- UUID FK with onDelete: "cascade" for required cross-table references
|
||||
- Zod validators with .default() for source enum
|
||||
- it.todo() for Wave 0 test scaffolding
|
||||
key_files:
|
||||
created:
|
||||
- packages/db/src/schema/chat_files.ts
|
||||
- packages/db/src/schema/chat_file_references.ts
|
||||
- packages/db/src/migrations/0053_create_chat_files.sql
|
||||
- packages/db/src/migrations/0054_create_chat_file_references.sql
|
||||
- server/src/__tests__/chat-file-service.test.ts
|
||||
- server/src/__tests__/chat-file-routes.test.ts
|
||||
modified:
|
||||
- packages/db/src/schema/index.ts
|
||||
- packages/db/src/migrations/meta/_journal.json
|
||||
- packages/shared/src/types/chat.ts
|
||||
- packages/shared/src/validators/chat.ts
|
||||
- packages/shared/src/index.ts
|
||||
decisions:
|
||||
- "Used object-syntax (table) => ({}) for Drizzle index callbacks — matches existing codebase pattern in chat_messages.ts, assets.ts"
|
||||
- "chatFiles.conversationId and messageId are nullable FKs with ON DELETE SET NULL — file may exist before/without a conversation or message"
|
||||
- "chatFileReferences uses ON DELETE CASCADE for both fileId and conversationId — reference has no meaning without both anchors"
|
||||
- "projectId nullable FK on chatFiles with ON DELETE SET NULL — satisfies FILE-04 dual scoping for future project-scoped file listing"
|
||||
- "uploadChatFileSchema source defaults to user_upload — agent-generated files pass source explicitly"
|
||||
metrics:
|
||||
duration_minutes: 6
|
||||
completed_date: "2026-04-01"
|
||||
tasks_completed: 2
|
||||
files_created: 6
|
||||
files_modified: 5
|
||||
requirements:
|
||||
- FILE-01
|
||||
- FILE-02
|
||||
- FILE-03
|
||||
---
|
||||
|
||||
# Phase 25 Plan 00: File System Foundation Summary
|
||||
|
||||
**One-liner:** Drizzle ORM schema for `chat_files` and `chat_file_references` tables with SQL migrations, shared TypeScript types (ChatFile, ChatFileReference), Zod validators (uploadChatFileSchema, createFileReferenceSchema), and test stubs — establishing the data layer contract for Phase 25 file upload plans.
|
||||
|
||||
## What Was Built
|
||||
|
||||
### Task 1: DB Schema + Migrations (commit 70fa6fe5)
|
||||
|
||||
Two new Drizzle ORM schema tables:
|
||||
|
||||
**`chat_files`** — tracks every uploaded or agent-generated file with:
|
||||
- Dual scoping: `company_id` (always) + optional `project_id` (FILE-04)
|
||||
- Storage integration: `object_key` + `sha256` for dedup detection
|
||||
- Lifecycle FKs: `conversation_id` (nullable, SET NULL), `message_id` (nullable, SET NULL)
|
||||
- Classification: `source` (user_upload | agent_generated), `category` (image | document | code | other | null)
|
||||
- 4 indexes: conversation, message, company+created_at composite, project
|
||||
|
||||
**`chat_file_references`** — enables cross-conversation file reuse without re-upload:
|
||||
- Required FKs: `file_id` (CASCADE), `conversation_id` (CASCADE)
|
||||
- Optional `message_id` (SET NULL)
|
||||
- 3 indexes: file, conversation, message
|
||||
|
||||
SQL migrations 0053 and 0054 added with journal entries for idx 53 and 54.
|
||||
|
||||
### Task 2: Shared Types + Validators + Test Stubs (commit 5cf5e420)
|
||||
|
||||
**New types** in `packages/shared/src/types/chat.ts`:
|
||||
- `ChatFile` — full file record interface with literal union types for source/category
|
||||
- `ChatFileReference` — cross-conversation reference interface
|
||||
- `ChatFileUploadResponse` — upload endpoint response shape
|
||||
- `ChatFileListResponse` — listing endpoint response shape
|
||||
- `ChatMessage.files?: ChatFile[]` — optional files array on existing ChatMessage type
|
||||
|
||||
**New Zod validators** in `packages/shared/src/validators/chat.ts`:
|
||||
- `uploadChatFileSchema` — conversationId, messageId, source (default: "user_upload"), projectId
|
||||
- `createFileReferenceSchema` — fileId, messageId
|
||||
|
||||
**Test stubs** created with `it.todo()` entries:
|
||||
- `server/src/__tests__/chat-file-service.test.ts` — 5 service test stubs
|
||||
- `server/src/__tests__/chat-file-routes.test.ts` — 6 route test stubs
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None — plan executed exactly as written.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
- `chat-file-service.test.ts` and `chat-file-routes.test.ts` are intentional `it.todo()` stubs — Plans 01 and 02 will implement the service and routes that these tests will cover.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
Files verified:
|
||||
- packages/db/src/schema/chat_files.ts: FOUND
|
||||
- packages/db/src/schema/chat_file_references.ts: FOUND
|
||||
- packages/db/src/migrations/0053_create_chat_files.sql: FOUND
|
||||
- packages/db/src/migrations/0054_create_chat_file_references.sql: FOUND
|
||||
- server/src/__tests__/chat-file-service.test.ts: FOUND
|
||||
- server/src/__tests__/chat-file-routes.test.ts: FOUND
|
||||
|
||||
Commits verified:
|
||||
- 70fa6fe5: FOUND (feat(25-00): create chat_files and chat_file_references DB schema + migrations)
|
||||
- 5cf5e420: FOUND (feat(25-00): add shared types, validators, and test stubs for file system)
|
||||
|
||||
TypeScript compilation: PASSED (no errors)
|
||||
Loading…
Add table
Reference in a new issue