132 lines
6.5 KiB
Markdown
132 lines
6.5 KiB
Markdown
---
|
|
phase: 24-search-history-branching
|
|
plan: "00"
|
|
subsystem: db-schema-shared-types
|
|
tags: [migrations, drizzle, types, validators, test-stubs]
|
|
dependency_graph:
|
|
requires: []
|
|
provides:
|
|
- 0050_add_branch_columns migration
|
|
- 0051_add_message_search_vector migration
|
|
- 0052_create_chat_message_bookmarks migration
|
|
- chatMessageBookmarks Drizzle schema
|
|
- ChatMessageSearchResult shared type
|
|
- ChatBookmark shared type
|
|
- searchMessagesSchema validator
|
|
- branchConversationSchema validator
|
|
- Wave 0 test stubs for searchMessages, toggleBookmark, branchConversation, exportConversation
|
|
affects:
|
|
- packages/db
|
|
- packages/shared
|
|
- server/src/__tests__
|
|
tech_stack:
|
|
added: []
|
|
patterns:
|
|
- AnyPgColumn type annotation for self-referential FK (matches issues.ts, goals.ts pattern)
|
|
- it.todo() for Wave 0 test scaffolding (matches Phase 21 convention)
|
|
key_files:
|
|
created:
|
|
- packages/db/src/migrations/0050_add_branch_columns.sql
|
|
- packages/db/src/migrations/0051_add_message_search_vector.sql
|
|
- packages/db/src/migrations/0052_create_chat_message_bookmarks.sql
|
|
- packages/db/src/schema/chat_message_bookmarks.ts
|
|
modified:
|
|
- packages/db/src/migrations/meta/_journal.json
|
|
- packages/db/src/schema/chat_conversations.ts
|
|
- packages/db/src/schema/chat_messages.ts
|
|
- packages/db/src/schema/index.ts
|
|
- packages/shared/src/types/chat.ts
|
|
- packages/shared/src/validators/chat.ts
|
|
- packages/shared/src/index.ts
|
|
- server/src/__tests__/chat-service.test.ts
|
|
- server/src/__tests__/chat-routes.test.ts
|
|
decisions:
|
|
- Used AnyPgColumn type annotation for parentConversationId self-referential FK to resolve TypeScript circular reference — matches existing pattern in issues.ts, goals.ts, execution_workspaces.ts
|
|
- content_search tsvector column intentionally omitted from Drizzle schema — it is a Postgres generated stored column queried via raw sql`` only
|
|
completed_date: "2026-04-01"
|
|
duration: ~5min
|
|
tasks: 2
|
|
files: 9
|
|
---
|
|
|
|
# Phase 24 Plan 00: DB Migrations, Schema, Types, and Test Stubs Summary
|
|
|
|
**One-liner:** Three SQL migrations (branch columns, tsvector search, bookmarks table), Drizzle schema updates, and shared TypeScript types/validators for chat search, bookmarks, and branching with Wave 0 it.todo test stubs.
|
|
|
|
## Tasks Completed
|
|
|
|
| Task | Name | Commit | Key Files |
|
|
|------|------|--------|-----------|
|
|
| 1 | DB migrations and Drizzle schema updates | 430bbbb8 | 0050-0052 SQL files, chat_conversations.ts, chat_message_bookmarks.ts, schema/index.ts |
|
|
| 2 | Shared types, validators, and Wave 0 test stubs | e881270c | types/chat.ts, validators/chat.ts, shared/index.ts, chat-service.test.ts, chat-routes.test.ts |
|
|
|
|
## What Was Built
|
|
|
|
### Task 1: DB Migrations and Drizzle Schema
|
|
|
|
**Migration 0050_add_branch_columns.sql:** Adds `parent_conversation_id` (self-referential UUID FK with ON DELETE SET NULL) and `branch_from_message_id` to `chat_conversations`, plus a GIN-style index for parent lookups.
|
|
|
|
**Migration 0051_add_message_search_vector.sql:** Adds `content_search` as a Postgres-generated STORED tsvector column (using `to_tsvector('english', content)`) with a GIN index for full-text search.
|
|
|
|
**Migration 0052_create_chat_message_bookmarks.sql:** Creates the `chat_message_bookmarks` table with `company_id`, `message_id` (ON DELETE CASCADE), `conversation_id` (ON DELETE CASCADE), plus compound indexes for efficient per-company lookups.
|
|
|
|
**Drizzle schema changes:**
|
|
- `chat_conversations.ts`: Added `parentConversationId` and `branchFromMessageId` columns with `AnyPgColumn` type annotation to resolve TypeScript circular reference. Added `parentIdx` to index object.
|
|
- `chat_messages.ts`: Added comment noting the generated tsvector column — it is intentionally absent from the Drizzle schema.
|
|
- `chat_message_bookmarks.ts`: New schema file with two compound indexes.
|
|
- `schema/index.ts`: Added `chatMessageBookmarks` re-export.
|
|
|
|
### Task 2: Shared Types, Validators, and Test Stubs
|
|
|
|
**New types in packages/shared/src/types/chat.ts:**
|
|
- `ChatMessageSearchResult` — ranked search result with message, conversation, role, and rank fields
|
|
- `ChatMessageSearchResponse` — list wrapper
|
|
- `ChatBookmark` — bookmark record shape
|
|
- `ChatBookmarkWithMessage` — bookmark with embedded `ChatMessage` and conversation title
|
|
- `ChatBookmarkListResponse` — list wrapper
|
|
- `ChatBookmarkToggleResponse` — `{ bookmarked: boolean }` for toggle endpoint
|
|
|
|
**Extended existing types:**
|
|
- `ChatConversation` — added `parentConversationId: string | null` and `branchFromMessageId: string | null`
|
|
- `ChatConversationListItem` — same two fields added
|
|
|
|
**New validators in packages/shared/src/validators/chat.ts:**
|
|
- `searchMessagesSchema` — `q` (min 2, max 200) + optional `limit` (1-50, coerced)
|
|
- `branchConversationSchema` — `branchFromMessageId` as UUID string
|
|
- Inferred types: `SearchMessages`, `BranchConversation`
|
|
|
|
**Wave 0 test stubs (chat-service.test.ts):**
|
|
- `describe("searchMessages")` — 3 `it.todo` entries
|
|
- `describe("toggleBookmark")` — 2 `it.todo` entries
|
|
- `describe("branchConversation")` — 2 `it.todo` entries
|
|
- `describe("exportConversation")` — 2 `it.todo` entries
|
|
|
|
**Wave 0 test stubs (chat-routes.test.ts):**
|
|
- `describe("GET /companies/:id/messages/search")` — 2 `it.todo` entries
|
|
- `describe("POST /conversations/:id/bookmarks")` — 1 `it.todo` entry
|
|
- `describe("POST /conversations/:id/branch")` — 1 `it.todo` entry
|
|
- `describe("GET /conversations/:id/export")` — 2 `it.todo` entries
|
|
|
|
## Verification
|
|
|
|
- `pnpm --filter @paperclipai/db build` — PASSED
|
|
- `pnpm --filter @paperclipai/shared build` — PASSED
|
|
- All 7 acceptance criteria for Task 1 — PASSED
|
|
- All 10 acceptance criteria for Task 2 — PASSED
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] Self-referential FK causes TypeScript circular reference**
|
|
- **Found during:** Task 1 verification (db build)
|
|
- **Issue:** TypeScript error TS7022/TS7024: `chatConversations` implicitly has type `any` because `parentConversationId` references the table being defined
|
|
- **Fix:** Import `AnyPgColumn` from `drizzle-orm/pg-core` and annotate the reference callback as `(): AnyPgColumn => chatConversations.id` — matches the existing pattern in `issues.ts`, `goals.ts`, `execution_workspaces.ts`, and `heartbeat_runs.ts`
|
|
- **Files modified:** `packages/db/src/schema/chat_conversations.ts`
|
|
- **Commit:** 430bbbb8
|
|
|
|
## Known Stubs
|
|
|
|
None — all Wave 0 test stubs are intentional `it.todo()` scaffolding per plan specification. They are placeholders for Plans 01-03 to implement.
|
|
|
|
## Self-Check: PASSED
|