Document Prisma ERD generation

This commit is contained in:
Janpeter Visser 2026-04-25 17:08:55 +02:00
parent b5e967d8d3
commit 4ec0683f88
9 changed files with 3997 additions and 25 deletions

View file

@ -116,17 +116,40 @@ Vul daarna `DATABASE_URL` en `SESSION_SECRET` in. `DIRECT_URL` is optioneel loka
npx prisma db push
```
4. Seed testdata indien nodig:
4. Genereer Prisma Client en de ERD:
```bash
npm run db:erd
```
Deze command voert `prisma generate` uit. Daardoor worden zowel de Prisma Client als `docs/erd.svg` opnieuw opgebouwd.
5. Seed testdata indien nodig:
```bash
npx prisma db seed
```
5. Start de app:
6. Start de app:
```bash
npm run dev
```
## Database
![ERD](./docs/erd.svg)
De databasevisualisatie wordt gegenereerd uit `prisma/schema.prisma` via `prisma-erd-generator`.
Handmatige generatie:
```bash
npm run db:erd
```
Tijdens lokale development draait `npm run dev` naast Next.js ook `npm run db:erd:watch`. Bij wijzigingen in `prisma/schema.prisma` wordt `docs/erd.svg` automatisch opnieuw gegenereerd.
Gebruik `npx prisma db push` alleen om het schema naar de database te synchroniseren. Gebruik `npm run db:erd` om Prisma Client en de ERD te genereren.
De app draait standaard op `http://localhost:3000`.
@ -137,6 +160,7 @@ npm run dev # lokale development server
npm run lint # ESLint
npm test # Vitest test suite
npm run build # productiebuild zoals Vercel die verwacht
npm run db:erd # Prisma Client + docs/erd.svg genereren
```
### Environment variables

View file

@ -1,7 +1,26 @@
import Link from 'next/link'
import { cookies } from 'next/headers'
import { getIronSession } from 'iron-session'
import { AppIcon } from '@/components/shared/app-icon'
import { SessionData, sessionOptions } from '@/lib/session'
import packageJson from '@/package.json'
const buildDate = process.env.NEXT_PUBLIC_BUILD_DATE
? new Date(process.env.NEXT_PUBLIC_BUILD_DATE).toLocaleDateString('nl-NL', {
day: 'numeric',
month: 'short',
year: 'numeric',
})
: '—'
const version = process.env.NEXT_PUBLIC_APP_VERSION ?? packageJson.version
export default async function LandingPage() {
const session = process.env.SESSION_SECRET
? await getIronSession<SessionData>(await cookies(), sessionOptions)
: null
const isLoggedIn = Boolean(session?.userId)
export default function LandingPage() {
return (
<div className="h-screen bg-background text-foreground flex flex-col overflow-hidden">
@ -12,6 +31,29 @@ export default function LandingPage() {
Scrum4Me
</Link>
<nav className="ml-auto flex items-center gap-2">
{isLoggedIn ? (
<>
<Link
href="/dashboard"
className="px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors"
>
Producten
</Link>
<Link
href="/todos"
className="px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors"
>
Todo&apos;s
</Link>
<Link
href="/settings"
className="px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors"
>
Instellingen
</Link>
</>
) : (
<>
<Link
href="/login"
className="px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors"
@ -24,6 +66,8 @@ export default function LandingPage() {
>
Registreren
</Link>
</>
)}
</nav>
</header>
@ -279,10 +323,7 @@ export default function LandingPage() {
{/* ── Footer ─────────────────────────────────────────────────── */}
<footer className="shrink-0 border-t border-border bg-surface-container-low px-6 py-4 flex items-center justify-between text-xs text-muted-foreground">
<span>© {new Date().getFullYear()} Scrum4Me</span>
<div className="flex gap-4">
<Link href="/login" className="hover:text-foreground transition-colors">Inloggen</Link>
<Link href="/register" className="hover:text-foreground transition-colors">Registreren</Link>
</div>
<span>v{version} · gebouwd op {buildDate}</span>
</footer>
</div>

View file

@ -23,7 +23,7 @@ export function NavBar({ isDemo }: NavBarProps) {
return (
<header className="bg-surface-container-low border-b border-border h-14 flex items-center px-4 gap-4 shrink-0">
{/* Logo */}
<Link href="/dashboard" className="flex items-center gap-2 font-medium text-foreground">
<Link href="/" className="flex items-center gap-2 font-medium text-foreground">
<AppIcon size={24} />
<span className="text-primary font-semibold">Scrum4Me</span>
{isDemo && (

1
docs/erd.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 317 KiB

View file

@ -39,3 +39,35 @@ export default defineConfig({
migrations: { path: 'prisma/migrations' },
})
```
## Prisma generators
`prisma/schema.prisma` bevat twee generators:
```prisma
generator client {
provider = "prisma-client-js"
}
generator erd {
provider = "prisma-erd-generator"
output = "../docs/erd.svg"
}
```
`prisma generate` bouwt dus twee artifacts:
- Prisma Client in `node_modules/@prisma/client`
- het ERD-diagram in `docs/erd.svg`
## Commands
| Command | Gebruik |
|---|---|
| `npx prisma db push` | Schema synchroniseren naar de database |
| `npx prisma db seed` | Seeddata laden |
| `npm run db:erd` | `prisma generate`: Prisma Client en `docs/erd.svg` genereren |
| `npm run db:erd:watch` | `prisma/schema.prisma` watchen en ERD opnieuw genereren |
| `npm run dev` | Next.js dev server plus ERD watcher starten |
Belangrijk: `db push` schrijft naar de database, maar genereert geen ERD. Gebruik na schemawijzigingen `npm run db:erd` of laat `npm run dev` de watcher draaien.

View file

@ -770,6 +770,7 @@ NODE_ENV="development"
**CI/CD:** GitHub Actions → lint + typecheck + `prisma validate` op elke PR; Vercel deploy automatisch bij merge naar `main`
**Database (cloud):** Neon — migraties via `prisma migrate deploy` in de Vercel build-stap
**Database (lokaal):** Neon (gratis tier) — `npx prisma db push` synchroniseert schema
**Prisma generatie:** `npm run db:erd` voert `prisma generate` uit en bouwt zowel Prisma Client als `docs/erd.svg`
**Seeding:** `npx prisma db seed` laadt de testdata uit het Product Backlog document
### Deployment checklist (pre-launch)

3866
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,18 @@
{
"name": "scrum4me",
"version": "0.2.0",
"version": "0.3.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "concurrently \"next dev\" \"npm run db:erd:watch\"",
"build": "next build",
"start": "next start",
"lint": "eslint",
"test": "vitest run",
"test:watch": "vitest",
"prepare": "husky",
"postinstall": "prisma generate"
"postinstall": "prisma generate",
"db:erd": "prisma generate",
"db:erd:watch": "chokidar \"prisma/schema.prisma\" -c \"npm run db:erd\""
},
"dependencies": {
"@base-ui/react": "^1.4.1",
@ -47,6 +49,7 @@
"*.{ts,tsx,mjs}": "eslint --fix"
},
"devDependencies": {
"@mermaid-js/mermaid-cli": "^11.12.0",
"@tailwindcss/postcss": "^4",
"@types/bcryptjs": "^2.4.6",
"@types/node": "^20",
@ -54,10 +57,13 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitest/coverage-v8": "^4.1.5",
"chokidar-cli": "^3.0.0",
"concurrently": "^9.2.1",
"eslint": "^9",
"eslint-config-next": "16.2.4",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"prisma-erd-generator": "^2.4.2",
"tailwindcss": "^4",
"tsx": "^4.21.0",
"typescript": "^5",

View file

@ -2,6 +2,11 @@ generator client {
provider = "prisma-client-js"
}
generator erd {
provider = "prisma-erd-generator"
output = "../docs/erd.svg"
}
datasource db {
provider = "postgresql"
}