docs: update README for Drizzle ORM migration
CI / check (push) Successful in 28s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m35s

- Document Drizzle ORM as primary data layer with CLI usage examples
- Add Prisma compatibility facade section (backwards compatibility)
- Document legacy Prisma CLI removal (migrate dev, studio, db push no longer used)
- Update architecture tree with src/db/ and scripts/ directories
- Update migration count (19 SQL files)
- Add contributing guidelines for Drizzle-based code
This commit is contained in:
openhands committed 2026-07-31 14:26:09 +02:00
1 parent beae86194d
commit 9a8905c726
1 file changed
+52 -13
+52 -13
View File
@@ -58,21 +58,45 @@ APP_URL=http://localhost:3000
See `.env.example` for all optional variables (RCON, email, Redis, OAuth, PayPal, etc.).
### 4. Type Generation (Optional for Development)
### 4. ORM Setup & Type Generation
#### Drizzle ORM (Primary Data Layer)
Drizzle ORM is the runtime data layer. The connection is a singleton in `src/lib/db.ts`:
```ts
import { db } from "@/lib/db";
import { users } from "@/db/schema";
import { eq } from "drizzle-orm/expressions";
const found = await db.select()
.from(users)
.where(eq(users.username, "hello"));
```
**Drizzle CLI** (`drizzle-kit`) is used for local development tasks — it is a devDependency and is never bundled in production.
| Command | What it does |
| ------- | ------------ |
| `npx drizzle-kit generate --dialect mysql --schema src/db/schema.ts --out src/db/migrations` | Inspect the Drizzle schema and emit migration SQL |
| `npx drizzle-kit studio` | Open a local DB browser (dev only) |
| `npx drizzle-kit introspect` | Reverse-engineer an existing DB into a Drizzle schema |
> The CMS does **not** use `drizzle-kit push` — the database is owned by the emulator and is never auto-migrated. CMS-owned tables are created via the SQL migration runner (step 5).
#### Prisma Compatibility Facade (Backwards Compatibility)
A Prisma-compatible facade at `@/lib/prisma` allows existing code to keep calling `prisma.users.findMany()` without refactoring. At runtime, the facade routes every query through Drizzle. **There is zero Prisma client or query-engine overhead in production.**
Generate the Prisma type stubs used for type-checking the facade:
```bash
pnpm prisma:generate
```
Generates TypeScript types in `src/generated/prisma/`. This is only needed for developer type-checking of the `prisma` facade — it does not add any Prisma runtime overhead in production. The facade (`src/lib/prisma-facade.ts`) routes all queries through Drizzle ORM at runtime.
This creates `src/generated/prisma/` (a local, `gitignore`d build artifact) with TypeScript types only. It is never shipped in the production bundle.
Alternatively, you can work with Drizzle directly via the typed schema in `src/db/schema.ts`:
```ts
import { db } from "@/lib/db";
import { users } from "@/db/schema";
const result = await db.select().from(users).where(eq(users.username, "hello"));
```
> **Legacy CLI command removed:** The `prisma` CLI is now a devDependency used **only** for type generation. Old commands such as `prisma migrate dev`, `prisma studio`, or `prisma db push` are no longer applicable — use the SQL migration runner (`pnpm db:migrate`) or Drizzle CLI instead.
### 5. Run CMS Migrations
@@ -140,10 +164,18 @@ The CMS runs behind an nginx reverse proxy on the default port 3000. Static asse
| `pnpm test` | Run all tests (Vitest) |
| `pnpm db:migrate` | Apply pending SQL migrations |
| `pnpm db:migrate:status` | Show migration status |
| `pnpm prisma:generate` | Regenerate Prisma type stubs (dev only, not prod) |
| `pnpm analyze` | Build + open bundle analyzer |
| `pnpm jobs:worker` | Start background task worker (systemd / PM2) |
| `pnpm biome:check` | Lint and format code |
**Drizzle CLI (dev only, run with `npx`):**
| Command | Description |
| ------- | ----------- |
| `drizzle-kit generate` | Generate migration SQL from Drizzle schema |
| `drizzle-kit studio` | Local Drizzle Studio database browser |
| `drizzle-kit introspect` | Reverse-engineer DB → Drizzle schema |
---
## Performance Features
@@ -171,12 +203,17 @@ The CMS runs behind an nginx reverse proxy on the default port 3000. Static asse
```
├── prisma/
│ ├── schema.prisma # ~190 models (emulator + CMS) — used for type generation only
│ └── migrations/ # 16 SQL migrations for CMS tables
│ ├── schema.prisma # ~190 models (emulator + CMS) — used for type generation only (legacy)
│ └── migrations/ # 19 SQL migrations for CMS tables (idempotent, never re-run)
├── scripts/
│ ├── apply-migrations.ts # SQL migration runner (apply + status)
│ ├── jobs-worker.ts # Background task scheduler
│ ├── merge-config.cjs # Utility: merge split config files
│ └── generate-drizzle-schema.mjs # One-off: generate src/db/schema.ts from schema.prisma
├── src/
│ ├── db/
│ │ ├── schema.ts # Drizzle ORM schema (176 tables — runtime data layer)
│ │ └── migrations/ # Drizzle migration files (if used)
│ │ └── migrations/ # Drizzle migration files (local dev only)
│ ├── app/ # Next.js App Router (pages & API routes)
│ ├── actions/ # Server Actions
│ ├── components/ # UI components
@@ -206,7 +243,7 @@ The CMS runs behind an nginx reverse proxy on the default port 3000. Static asse
| Component | Type | Migrations |
| ------------------------------------------------- | ----------------------- | ----------------------------------- |
| Emulator tables (`users`, `items`, `rooms`, etc.) | Existing Polaris schema | None — CMS reads/writes only |
| CMS tables (`website_*`, `radio_*`, etc.) | CMS-owned | `prisma/migrations/*.sql` (16 files) |
| CMS tables (`website_*`, `radio_*`, etc.) | CMS-owned | `prisma/migrations/*.sql` (19 files) |
| Migration tracking | `cms_migrations` table | Auto-created by migration runner |
### ORM Architecture
@@ -282,6 +319,8 @@ pnpm biome:check # Lint and format
2. Follow existing code conventions (Server Components where possible, minimal client boundaries)
3. Use the `src/lib/motion.ts` animation variants for consistent animations
4. SQL migrations in `prisma/migrations/` must be idempotent
5. For new database code, use the Drizzle runtime directly (`import { db } from "@/lib/db"`) — see [ORM Setup](#4-orm-setup--type-generation)
6. Avoid `any` — use `eslint-disable` or `biome-ignore` comments only when unavoidable (e.g., Prisma facade compatibility)
---