| name | tzurot-db-vector |
| description | Database migration procedures. Invoke with /tzurot-db-vector for Prisma migrations, drift fixes, and pgvector operations. |
| lastUpdated | 2026-02-09 |
Database & Vector Procedures
Invoke with /tzurot-db-vector for migration and database operations.
Rules for queries and caching are in .claude/rules/03-database.md - they apply automatically.
Migration Procedure
1. Create Migration
pnpm ops db:safe-migrate
pnpm ops db:safe-migrate --name <migration_name>
This command:
- Tries
prisma migrate dev --create-only (interactive path)
- Falls back to
prisma migrate diff if stdin is not a TTY (non-interactive)
- Removes known drift patterns from
prisma/drift-ignore.json
- Reports what was sanitized
- Shows the clean migration for review
All pnpm ops db:* commands work in non-interactive environments.
2. Review SQL (CRITICAL)
The safe-migrate command auto-sanitizes these, but always verify:
DROP INDEX "idx_memories_embedding" — removed (IVFFlat vector index)
DROP INDEX "memories_chunk_group_id_idx" — removed (partial index)
CREATE INDEX "memories_chunk_group_id_idx" without WHERE — removed (non-partial)
3. Apply Migration
pnpm ops db:migrate
pnpm ops test:generate-schema
pnpm ops db:migrate --env dev
pnpm ops db:migrate --env prod --force
db:migrate uses prisma migrate deploy (not migrate dev) for all environments.
This avoids interactive prompts and drift-detection loops from sanitized indexes.
Drift Detection & Fix
pnpm ops db:check-drift
pnpm ops db:fix-drift 20251213200000_add_tombstones
When safe to fix: Formatting/whitespace changes only
When NOT to fix: Actual SQL logic was changed → create new migration
Database Inspection
pnpm ops db:inspect
pnpm ops db:inspect --table memories
pnpm ops db:inspect --indexes
Vector Operations
Store Embedding
const embeddingStr = `[${embedding.join(',')}]`;
await prisma.$executeRaw`
INSERT INTO memories (id, "personalityId", content, embedding, "createdAt")
VALUES (gen_random_uuid(), ${id}::uuid, ${content}, ${embeddingStr}::vector, NOW())
`;
Similarity Search
const results = await prisma.$queryRaw<SimilarMemory[]>`
SELECT id, content, 1 - (embedding <-> ${embeddingStr}::vector) as similarity
FROM memories
WHERE "personalityId" = ${personalityId}::uuid
ORDER BY embedding <-> ${embeddingStr}::vector
LIMIT ${limit}
`;
Protected Indexes (CRITICAL)
| Index | Type | Why Protected |
|---|
idx_memories_embedding | IVFFlat vector | Prisma doesn't support Unsupported type indexes |
memories_chunk_group_id_idx | Partial B-tree | Prisma can't represent WHERE clauses |
Recover If Dropped
CREATE INDEX IF NOT EXISTS idx_memories_embedding
ON memories USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 50);
DROP INDEX IF EXISTS "memories_chunk_group_id_idx";
CREATE INDEX "memories_chunk_group_id_idx" ON "memories"("chunk_group_id")
WHERE "chunk_group_id" IS NOT NULL;
PGLite Schema Regeneration
After any migration:
pnpm ops test:generate-schema
References