Create a database migration for: $ARGUMENTS
Current State
- •Existing migrations: !
ls worker/src/db/migrations/ - •Total migration count: !
ls worker/src/db/migrations/ | wc -l - •Schema: !
head -50 worker/src/db/schema.sql
Determine Database Target
nhimbe uses two databases:
- •MongoDB Atlas — primary database, source of truth (via
MONGODB_URIsecret) - •D1 (SQLite) — edge processing, fast reads, caching
Infer the target from $ARGUMENTS:
- •If the migration involves core data (events, users, registrations, reviews, referrals, analytics) → MongoDB
- •If the migration involves edge caching, denormalized read views, or Worker-local data → D1
- •If unclear, default to MongoDB and ask for clarification
Steps — D1 (SQLite) Migration
- •
Determine the next migration number. List all files in
worker/src/db/migrations/. Count total files (both numbered and unnumbered legacy files). The next number is total count + 1, zero-padded to 3 digits. Format:NNN_description.sql(e.g.,006_add_notifications.sql).Legacy SQL files (unnumbered) are treated as migrations 001-005 in chronological order. New migrations always get the next sequential number.
- •
Read existing schema (
worker/src/db/schema.sql) and recent migrations to understand current tables and columns. - •
Write the migration SQL file to
worker/src/db/migrations/NNN_description.sql:sql-- Migration NNN: <description> -- Add new table / alter existing table CREATE TABLE IF NOT EXISTS new_table ( id TEXT PRIMARY KEY, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Add indexes CREATE INDEX IF NOT EXISTS idx_new_table_field ON new_table(field); - •
Update
worker/src/db/schema.sqlto include the new table/column definitions. - •
Update
worker/src/types.tsif the migration adds or modifies fields that need TypeScript type changes. - •
Report what was created and the command to run it:
bashcd worker && wrangler d1 execute mukoko-nhimbe-db --file=./src/db/migrations/NNN_description.sql
D1 Conventions
- •Migration files are plain SQL (
.sqlextension) - •D1 is SQLite — use SQLite syntax (e.g.,
TEXTnotVARCHAR,datetime('now')notNOW()) - •
ALTER TABLEin SQLite only supportsADD COLUMNandRENAME(noDROP COLUMN,ALTER COLUMN) - •IDs are
TEXT PRIMARY KEY(application-generated UUIDs) - •Timestamps are
TEXT DEFAULT (datetime('now'))(ISO 8601 strings) - •Booleans are
INTEGERorBOOLEAN(0/1 in SQLite) - •JSON stored as
TEXT(parsed withJSON()in queries or application-side) - •Use
CREATE INDEX IF NOT EXISTSfor idempotent migrations - •Index naming:
idx_tableName_field - •Table names use snake_case (e.g.,
event_views,ai_conversations) - •Always add
IF NOT EXISTS/IF EXISTSguards for idempotency
Steps — MongoDB Migration
- •
Determine the next migration number. Same numbering as D1 (they share the sequence). Format:
NNN_description.ts(e.g.,006_add_notifications.ts). - •
Read existing migrations to understand current collections, indexes, and data shapes.
- •
Write the migration TypeScript file to
worker/src/db/migrations/NNN_description.ts:typescript// Migration NNN: <description> import { Db } from "mongodb"; export async function up(db: Db): Promise<void> { // Create collections, indexes, insert seed data } export async function down(db: Db): Promise<void> { // Reverse the up() changes } - •
Update
worker/src/types.tsif the migration adds or modifies collections/fields that need TypeScript type changes. - •
Report what was created and any manual steps needed.
MongoDB Conventions
- •Migration files are TypeScript with
up()anddown()exports - •Every
up()must have a correspondingdown()for rollback - •IDs are
string(application-generated UUIDs or MongoDB ObjectIds) - •Timestamps are
Dateobjects (not ISO strings) - •Use
createIndex()for new indexes, notensureIndex()(deprecated) - •Index naming:
idx_collectionName_field - •Collections use camelCase (e.g.,
eventViews,aiConversations) - •Embedded documents preferred over joins for data accessed together
- •Arrays of references (
ObjectId[]) for many-to-many relationships - •Always set
{ unique: true }on indexes that enforce uniqueness (e.g.,users.email,users.handle,events.slug)