chore: SQLite verwijderd — alleen PostgreSQL via Neon

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-25 12:15:19 +02:00
parent ffe3815598
commit b541379964
10 changed files with 26 additions and 811 deletions

View file

@ -55,7 +55,7 @@ Tailwind CSS + shadcn/ui
MD3 kleurensysteem via app/styles/theme.css
Zustand (client state)
dnd-kit (drag-and-drop)
Prisma v7 + PostgreSQL (Neon) | SQLite (lokaal)
Prisma v7 + PostgreSQL (Neon)
iron-session (auth cookies)
bcryptjs + Zod + Sonner
```
@ -87,7 +87,7 @@ Lees het relevante patroon vóór je begint. Nooit uit het hoofd schrijven.
## Env vars
```bash
DATABASE_URL="" # postgresql://... of file:./dev.db
DATABASE_URL="" # postgresql://...
DIRECT_URL="" # alleen bij Neon/cloud
SESSION_SECRET="" # openssl rand -base64 32
```

View file

@ -2,11 +2,10 @@
## lib/prisma.ts
Detecteert automatisch SQLite (lokaal, `file:`) of PostgreSQL (Neon/Vercel).
PostgreSQL via `pg` + `@prisma/adapter-pg` (Neon/Vercel).
```ts
import { PrismaClient } from '@prisma/client'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
@ -14,14 +13,6 @@ function createPrismaClient() {
const url = process.env.DATABASE_URL
if (!url) throw new Error('DATABASE_URL is not set')
if (url.startsWith('file:')) {
const adapter = new PrismaBetterSqlite3({ url })
return new PrismaClient({
adapter,
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
})
}
const pool = new Pool({ connectionString: url })
const adapter = new PrismaPg(pool)
return new PrismaClient({

View file

@ -7,7 +7,7 @@
## Architectuursamenvatting
Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt gerenderd en gedeployed op Vercel. De database is PostgreSQL via Neon (cloud) of SQLite (lokaal), aangestuurd via Prisma v7. Authenticatie is custom username/password via iron-session — geen externe auth-provider, geen e-mail. De REST API voor Claude Code-integratie loopt via Next.js Route Handlers, beveiligd met API-tokens. Drag-and-drop in de planningsschermen wordt afgehandeld door dnd-kit. De volledige app draait ook lokaal zonder externe accounts.
Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt gerenderd en gedeployed op Vercel. De database is PostgreSQL via Neon, aangestuurd via Prisma v7. Authenticatie is custom username/password via iron-session — geen externe auth-provider, geen e-mail. De REST API voor Claude Code-integratie loopt via Next.js Route Handlers, beveiligd met API-tokens. Drag-and-drop in de planningsschermen wordt afgehandeld door dnd-kit.
---
@ -21,8 +21,7 @@ Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt ger
| Client state | Zustand | Minimale boilerplate voor ephemere UI-staat (selectie, optimistische drag-and-drop volgorde); leeft naast Server Components zonder conflict; eenvoudig uitbreidbaar naar v2 teamgebruik |
| Styling | Tailwind CSS + shadcn/ui | Snelle iteratie; toegankelijke componentprimitieven; desktop-first layouts goed ondersteund |
| Database (cloud) | PostgreSQL via Neon | Serverless Postgres, gratis tier voldoende voor MVP; native PostgreSQL zonder vendor lock-in |
| Database (lokaal) | SQLite via Prisma SQLite-adapter | Geen externe accounts nodig voor lokale ontwikkeling; `prisma db push` initialiseert schema |
| ORM | Prisma v7 | Type-safe queries; ondersteunt zowel PostgreSQL als SQLite via adapter; migraties zijn deterministisch |
| ORM | Prisma v7 | Type-safe queries; PostgreSQL via adapter; migraties zijn deterministisch |
| Authenticatie | Custom — iron-session + bcrypt | Username/password zonder e-mail vereist geen externe auth-provider; iron-session beheert versleutelde cookies server-side |
| Drag-and-drop | dnd-kit | Actief onderhouden, React-native hooks, 60fps bij grote lijsten, ondersteuning voor meerdere containers |
| REST API | Next.js Route Handlers (`/app/api/`) | Naast Server Actions nodig voor Claude Code-integratie; Route Handlers zijn volledig HTTP-compatibel |
@ -43,7 +42,7 @@ Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt ger
| Context API (React) | Veroorzaakt onnodige re-renders bij drag-and-drop updates; Zustand's selector-gebaseerde subscriptions zijn granulairder |
| WebSockets / real-time | Geen real-time vereisten in v1; polling of page-refresh volstaat |
| Redis | Geen caching- of queuerequirements op deze schaal |
| Docker (lokale dev) | Prisma + SQLite maakt lokale setup trivial zonder containers |
| Docker (lokale dev) | Neon gratis tier volstaat voor lokale ontwikkeling; Docker voegt geen waarde toe |
| Supabase (als database) | Neon geeft directe PostgreSQL-toegang zonder Supabase-specifieke abstractielagen; past beter bij Prisma-first aanpak |
| tRPC | REST API is vereist voor Claude Code-integratie; tRPC werkt alleen vanuit TypeScript-clients |
@ -672,7 +671,7 @@ interface SprintStore {
| Variabele | Doel | Waar te vinden |
|---|---|---|
| `DATABASE_URL` | Prisma database-verbinding | Neon dashboard (cloud) of lokaal `file:./dev.db` (SQLite) |
| `DATABASE_URL` | Prisma database-verbinding | Neon dashboard → Connection string (pooled) |
| `DIRECT_URL` | Directe verbinding voor migraties (Neon) | Neon dashboard → Connection string (unpooled) |
| `SESSION_SECRET` | Versleutelingssleutel voor iron-session | Genereer met `openssl rand -base64 32` |
| `NODE_ENV` | Omgevingsmodus | Automatisch gezet door Vercel / Node |
@ -682,7 +681,6 @@ interface SprintStore {
# Database
DATABASE_URL="postgresql://user:password@host/dbname?sslmode=require"
DIRECT_URL="postgresql://user:password@host/dbname?sslmode=require"
# Lokaal (SQLite): DATABASE_URL="file:./dev.db"
# Sessie
SESSION_SECRET="vervang-dit-met-openssl-rand-base64-32-output"
@ -698,7 +696,7 @@ NODE_ENV="development"
**Hosting:** Vercel (Hobby — gratis voor v1)
**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):** SQLite — `npx prisma db push` initialiseert schema
**Database (lokaal):** Neon (gratis tier) — `npx prisma db push` synchroniseert schema
**Seeding:** `npx prisma db seed` laadt de testdata uit het Product Backlog document
### Deployment checklist (pre-launch)

View file

@ -34,8 +34,8 @@ De MVP is klaar wanneer Lars — de primaire persona — de volledige cyclus kan
- Done when: `npm run dev` start zonder fouten; `npm run lint` geeft geen errors; shadcn `Button` rendert op een testpagina
- [ ] **ST-002** Prisma v7 setup + `prisma.config.ts`
- Installeer Prisma v7 + `@prisma/adapter-pg`; schrijf `prisma.config.ts` met `DATABASE_URL` via Zod-gevalideerde env; configureer SQLite-adapter voor lokale modus; schrijf `lib/prisma.ts` singleton
- Done when: `npx prisma db push` slaagt met SQLite lokaal; Prisma Client importeerbaar in een testbestand zonder fouten
- Installeer Prisma v7 + `@prisma/adapter-pg`; schrijf `prisma.config.ts` met `DATABASE_URL` via Zod-gevalideerde env; schrijf `lib/prisma.ts` singleton
- Done when: `npx prisma db push` slaagt; Prisma Client importeerbaar in een testbestand zonder fouten
- [ ] **ST-003** Database schema migratie (volledige initiële migratie)
- Schrijf het volledige `schema.prisma` op basis van het architectuurdocument: `User`, `UserRole`, `ApiToken`, `Product`, `Pbi`, `Story`, `StoryLog`, `Sprint`, `Task`, `Todo`; alle enums, indexes, cascade deletes

View file

@ -361,13 +361,12 @@ Gebruikers kunnen API-tokens aanmaken, labelen en intrekken via de instellingenp
**Persona:** Lars (lokaal, geen vendor lock-in), Dina (cloud)
**Omschrijving:**
De app is deployable op Vercel + Neon PostgreSQL én volledig lokaal draaibaar met SQLite of lokale PostgreSQL. Eén codebase, database-adapter als abstractielaag via Prisma.
De app is deployable op Vercel + Neon PostgreSQL en lokaal draaibaar met een Neon-database. Eén codebase, PostgreSQL via Prisma.
**Acceptatiecriteria:**
- [ ] `npm run dev` start de app lokaal zonder externe accounts
- [ ] Lokale modus gebruikt SQLite als standaard database (via Prisma)
- [ ] `DATABASE_URL` in `.env.local` schakelt tussen lokale en cloud database
- [ ] `npx prisma db push` initialiseert het schema in beide modi
- [ ] `npm run dev` start de app lokaal met Neon-database
- [ ] `DATABASE_URL` in `.env.local` verwijst naar Neon connection string
- [ ] `npx prisma db push` initialiseert het schema
- [ ] `next build` slaagt voor Vercel-deployment zonder aanpassingen
- [ ] `.env.example` documenteert alle vereiste en optionele environment variables
- [ ] README bevat stap-voor-stap instructies voor zowel lokale als cloud setup
@ -421,7 +420,7 @@ De app is deployable op Vercel + Neon PostgreSQL én volledig lokaal draaibaar m
| Offline support | Niet vereist voor v1 |
| Taal | Nederlands voor UI-teksten; Engels voor code, API en technische documentatie |
| Toegankelijkheid | Keyboard-navigatie voor alle primaire acties; WCAG AA voor de sprint planning flow |
| Database | Prisma ORM; PostgreSQL (cloud) of SQLite (lokaal) |
| Database | Prisma ORM; PostgreSQL via Neon |
| Deployment | Vercel (cloud) of lokaal via `npm run dev` |
| Sessiebeheer | Server-side sessie of JWT; geen opslag van gevoelige data in localStorage |

View file

@ -417,7 +417,7 @@ Acceptatiecriteria:
- Environment variables zijn gedocumenteerd in `.env.example`
**S-09-02: Lokale modus**
Als Developer wil ik de app volledig lokaal kunnen draaien met een lokale SQLite- of PostgreSQL-database, zodat er geen externe afhankelijkheid nodig is.
Als Developer wil ik de app lokaal kunnen draaien met een Neon PostgreSQL-database, zodat de lokale setup overeenkomt met productie.
Acceptatiecriteria:
- `npm run dev` start de app lokaal zonder Vercel of Neon account
- Database wordt aangemaakt via `prisma db push`

View file

@ -1,5 +1,4 @@
import { PrismaClient } from '@prisma/client'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
@ -7,14 +6,6 @@ function createPrismaClient() {
const url = process.env.DATABASE_URL
if (!url) throw new Error('DATABASE_URL is not set')
if (url.startsWith('file:')) {
const adapter = new PrismaBetterSqlite3({ url })
return new PrismaClient({
adapter,
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
})
}
const pool = new Pool({ connectionString: url })
const adapter = new PrismaPg(pool)
return new PrismaClient({

759
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,13 +17,9 @@
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@libsql/client": "^0.17.2",
"@prisma/adapter-better-sqlite3": "^7.8.0",
"@prisma/adapter-libsql": "^7.8.0",
"@prisma/adapter-pg": "^7.8.0",
"@prisma/client": "^7.8.0",
"bcryptjs": "^2.4.3",
"better-sqlite3": "^12.9.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dotenv": "^17.4.2",
@ -51,7 +47,6 @@
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/bcryptjs": "^2.4.6",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^20",
"@types/pg": "^8.20.0",
"@types/react": "^19",

View file

@ -14,19 +14,11 @@ async function main() {
const url = process.env.DATABASE_URL
if (!url) throw new Error('DATABASE_URL is not set. Check .env.local')
if (url.startsWith('file:')) {
// SQLite (local development)
const { PrismaBetterSqlite3 } = await import('@prisma/adapter-better-sqlite3')
const adapter = new PrismaBetterSqlite3({ url })
prisma = new PrismaClient({ adapter })
} else {
// PostgreSQL (Neon / production)
const { Pool } = await import('pg')
const { PrismaPg } = await import('@prisma/adapter-pg')
const pool = new Pool({ connectionString: url })
const adapter = new PrismaPg(pool)
prisma = new PrismaClient({ adapter })
}
console.log('Seeding database...')
@ -204,7 +196,7 @@ async function main() {
priority: 1,
stories: [
{ title: 'Cloud deployment (Vercel + Neon)', description: 'Als Developer wil ik de app deployen op Vercel met een Neon PostgreSQL-database.', acceptance_criteria: '- next build slaagt zonder fouten\n- Database-migraties worden uitgevoerd via Prisma', priority: 1 },
{ title: 'Lokale modus', description: 'Als Developer wil ik de app volledig lokaal kunnen draaien met een lokale SQLite-database.', acceptance_criteria: '- npm run dev start de app lokaal\n- Database wordt aangemaakt via prisma db push', priority: 1 },
{ title: 'Lokale modus', description: 'Als Developer wil ik de app lokaal kunnen draaien met een Neon PostgreSQL-database.', acceptance_criteria: '- npm run dev start de app lokaal\n- DATABASE_URL verwijst naar Neon connection string', priority: 1 },
{ title: 'API-token authenticatie', description: 'Als Developer wil ik een API-token kunnen genereren in de app.', acceptance_criteria: '- Gebruiker kan een API-token aanmaken\n- Token wordt eenmalig getoond\n- Alle API-endpoints vereisen een geldig token', priority: 1 },
],
},