docs(21-01): complete chat foundation plan — schema, types, service, routes

- 24 tests passing (service + routes)
- 9 new files created, 6 modified
- Requirements HIST-01, HIST-05, HIST-06, CHAT-04, CHAT-05, CHAT-06 marked complete

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Mikkel Georgsen 2026-04-01 13:04:25 +02:00
parent 5c969bb9da
commit 252dc9a814

View file

@ -0,0 +1,105 @@
---
phase: 21-chat-foundation
plan: 01
subsystem: chat-api
tags: [db-schema, rest-api, drizzle, service-layer, tdd]
dependency_graph:
requires: []
provides:
- chat_conversations Drizzle table and migration
- chat_messages Drizzle table and migration
- ChatConversation and ChatMessage TypeScript interfaces
- createConversationSchema, updateConversationSchema, createMessageSchema Zod validators
- chatService factory with full CRUD
- chatRoutes factory with 11 REST endpoints
affects:
- packages/db (new schema tables)
- packages/shared (new types + validators)
- server (new service + routes + app mounting)
tech_stack:
added:
- Drizzle ORM schema for chat_conversations and chat_messages
patterns:
- Factory function service pattern (chatService(db))
- Factory function route pattern (chatRoutes(db))
- Cursor-based pagination (updatedAt DESC)
- Auto-title on first message (idempotent: WHERE title IS NULL)
key_files:
created:
- packages/db/src/schema/chat_conversations.ts
- packages/db/src/schema/chat_messages.ts
- packages/db/src/migrations/0047_fixed_johnny_storm.sql
- packages/shared/src/types/chat.ts
- packages/shared/src/validators/chat.ts
- server/src/services/chat.ts
- server/src/routes/chat.ts
- server/src/__tests__/chat-service.test.ts
- server/src/__tests__/chat-routes.test.ts
modified:
- packages/db/src/schema/index.ts
- packages/shared/src/index.ts
- packages/shared/src/types/index.ts
- packages/shared/src/validators/index.ts
- server/src/routes/index.ts
- server/src/app.ts
decisions:
- "Used isNull(chatConversations.title) with AND condition for idempotent title-setting on first message"
- "listConversations fetches limit+1 to determine hasMore without extra COUNT query"
- "addMessage reads conversation after insert to check title IS NULL — keeps update idempotent"
metrics:
duration_minutes: 4
completed_date: "2026-04-01"
tasks_completed: 2
files_created: 9
files_modified: 6
---
# Phase 21 Plan 01: Chat Foundation — DB Schema, Types, Service, Routes Summary
**One-liner:** PostgreSQL chat schema with Drizzle ORM, Zod validators, cursor-paginated service, and 11-endpoint REST API — all TDD, 24 tests passing.
## What Was Built
Two new Drizzle schema tables (`chat_conversations`, `chat_messages`) with a generated migration (0047), shared TypeScript interfaces and Zod validators in `@paperclipai/shared`, a `chatService` factory with full CRUD including auto-title on first message and cursor-based pagination, and `chatRoutes` factory with 11 REST endpoints mounted in `app.ts`.
## Tasks Completed
| Task | Description | Commit |
|------|-------------|--------|
| 1 | DB schema, shared types, validators, service + service tests | 0152d958 |
| 2 | REST API routes and route tests | 22547a9c |
## Test Results
- `chat-service.test.ts`: 12 tests, all passing
- `chat-routes.test.ts`: 12 tests, all passing
- Total: 24 tests, 0 failures
## API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/companies/:companyId/conversations | List conversations (cursor paginated) |
| POST | /api/companies/:companyId/conversations | Create conversation |
| GET | /api/conversations/:id | Get conversation |
| PATCH | /api/conversations/:id | Update conversation title |
| DELETE | /api/conversations/:id | Soft delete conversation |
| POST | /api/conversations/:id/archive | Archive conversation |
| POST | /api/conversations/:id/unarchive | Unarchive conversation |
| POST | /api/conversations/:id/pin | Pin conversation |
| POST | /api/conversations/:id/unpin | Unpin conversation |
| GET | /api/conversations/:id/messages | List messages (cursor paginated) |
| POST | /api/conversations/:id/messages | Add message (auto-sets title if null) |
## Deviations from Plan
None — plan executed exactly as written.
## Known Stubs
None — all service methods are fully implemented with real Drizzle ORM calls.
## Self-Check: PASSED
- All 8 created files found on disk
- Commits 0152d958 and 22547a9c verified in git log