--- 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)