Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
with:
bun-version: 1.4.2
- run: bun install --frozen-lockfile
- run: bun run db:check
- run: bun run test:unit
env:
DATABASE_URL: postgres://ci:ci@db.localtest.me:5432/unused
Expand Down
22 changes: 18 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
| SDK tests | `bun run test-sdk` |
| Lint | `bun run lint` |
| Generate OpenAPI | `bun run generate:openapi` |
| New DB migration | `bun run db:generate --name <change>` |
| Check migrations match schema | `bun run db:check` |

### Restricted Commands
- `bun run dev` / `bun run build` - Ask before running
- `bunx drizzle-kit generate/push` - Prompt user to run manually
- `bun run db:migrate:prod` / `db:baseline:prod` - User runs these; prepare the command and say so (`--yes=<host>` skips the prompt)
- `drizzle-kit push` / `drizzle-kit export` - Never use against or to build any database
- `npx tsc` - Never run (breaks project state)

## Package Manager
Expand All @@ -35,7 +38,8 @@ app/api/
│ └── [[...slugs]]/route.ts
└── v2/ # Legacy Next.js routes

lib/db/schema.ts # Drizzle schema (type source of truth)
lib/db/schema.ts # Drizzle schema (source of truth)
drizzle/migrations/ # Numbered SQL migrations (drizzle/archive is history, never applied)
features/ # Feature-specific logic
```

Expand All @@ -59,10 +63,20 @@ import type { InferSelectModel } from "drizzle-orm";
- **Route params**: `params: Promise<{ id: string }>`, then `const { id } = await params`

### Database
- **Drizzle ORM only** - No raw SQL
- **Drizzle ORM only** in application code - No raw SQL (migration files in `drizzle/migrations/` are SQL)
- **Use `structuredEmails`** - NOT deprecated `receivedEmails`/`parsedEmails`
- Always scope queries by `userId` for multi-tenant safety

### Database Changes
- `lib/db/schema.ts` is the source of truth. Every schema change ships as a numbered SQL file in `drizzle/migrations/`, created with `bun run db:generate --name <change>` (or `--custom` for SQL drizzle can't express, like triggers), reviewed and committed in the same PR. Hand-edit the SQL when needed, e.g. to backfill a new column.
- Pending migrations run in one transaction, so `CREATE INDEX CONCURRENTLY` can't go in a migration file. For an index on a large table, ask the user.
- An enum value added with `ALTER TYPE ... ADD VALUE` can't be used in the same run (same transaction). Use the new value in a migration that ships with a later deploy.
- Never edit or renumber a migration that has been applied anywhere; add a new one. If main gained a migration since you generated yours, delete yours and regenerate it on top.
- Apply order: `bun run db:migrate:preview <branch>` for the PR's Vercel preview database, then `bun run db:migrate:prod` before merging or deploying code that depends on the change (code that selects whole rows breaks while a column is missing). Ship additive changes first (nullable column or new table, deploy, backfill), and constraints or drops in a later migration.
- Agents may generate migrations and apply them with `db:migrate:local` and `db:migrate:preview` (needs a `vercel link`ed checkout and `PROD_DATABASE_HOST` so it can refuse the production host). Production is applied by the user: prepare the `db:migrate:prod` command and say so.
- Neon preview branches forked before production was baselined have no migration history: run `bun run db:baseline:preview <branch>` (dry run, then `--apply`) before `db:migrate:preview`. `db:baseline:local` does the same for an old local database.
- `bun run db:check` must pass (CI runs it).

### Naming Conventions
- Files: `kebab-case.ts`
- React components: `PascalCase.tsx`
Expand Down Expand Up @@ -160,7 +174,7 @@ All list endpoints return:
2. Don't use deprecated tables (`receivedEmails`/`parsedEmails`)
3. Don't forget user scoping in DB queries
4. Don't use `t.Union()` for Elysia responses
5. Don't run drizzle-kit commands directly
5. Don't change the database schema without a migration in `drizzle/migrations/`

## User Ban System

Expand Down
6 changes: 1 addition & 5 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
out: './drizzle',
out: './drizzle/migrations',
schema: './lib/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions drizzle/archive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Archived migration history

These files are the migration history from before October 2026. They are kept for reference only and are never applied. The chain was broken: it had more SQL files than journal entries, duplicate numbers (0044, 0048, 0050, 0054, 0059, 0060), hand-written files outside the journal, a journal entry with no file and missing snapshots, and production was updated with `drizzle-kit push` instead, so `drizzle.__drizzle_migrations` stayed empty. `schema.ts` and `relations.ts` are an old `drizzle-kit pull` output. The live history starts again at `drizzle/migrations/0000_baseline.sql`, which reproduces the production schema as of 2026-10-21.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading