--- description: Drizzle schema, migrations, and multitenancy rules globs: - packages/database/**/*.ts - apps/**/server/**/*.ts - apps/collab-server/src/**/*.ts - apps/mcp-server/src/**/*.ts alwaysApply: false --- # Database — Drizzle + Postgres Schema source of truth: [packages/database/src/schema](mdc:packages/database/src/schema), re-exported from [packages/database/src/schema/index.ts](mdc:packages/database/src/schema/index.ts). Drizzle config: [packages/database/drizzle.config.ts](mdc:packages/database/drizzle.config.ts). ## Multitenancy is non-negotiable - Every tenant-scoped table has a `workspace_id` (UUID, not null) column with an index. - Every query against such tables **must** filter by `workspace_id`. The id comes from the authenticated session — never trust a client-provided value without checking it against the session's workspace memberships. - New tables holding user data: include `workspace_id`, add the index, add it to relations. ## Schema authoring - Keep one table per file in `src/schema/`. Re-export from `src/schema/index.ts`. - Define relations in [packages/database/src/schema/relations.ts](mdc:packages/database/src/schema/relations.ts). - Use `uuid().defaultRandom()` for primary keys, `timestamp({ withTimezone: true })` for time columns, and `.notNull()` aggressively. ## Migrations - After any schema change, run `pnpm db:generate` from the repo root and commit the new SQL file in [packages/database/migrations](mdc:packages/database/migrations). - **Never edit existing migrations.** Write a new one to fix or evolve. - `pnpm db:push` is for local prototyping only. Production goes through `pnpm db:migrate`. ## Client usage - Server-only. Never import the client into a Client Component, the browser bundle, or `packages/shared`. - Import from `@tasks/database` (or `@tasks/database/schema`, `@tasks/database/client`, `@tasks/database/markdown-backlog`) — these are the published export paths. ## Markdown backlog tables - `markdown_backlog_items` mirrors files under `plans/`, scoped by `workspace_id`. `cursor_sync_mappings` holds the Cursor-side ids. See [config/CursorSync.md](mdc:config/CursorSync.md) and [docs/Glossary.md](mdc:docs/Glossary.md) before changing either.