Een desktop-first fullstack webapplicatie voor solo developers en kleine Scrum Teams die meerdere softwareprojecten parallel beheren. De app organiseert werk hiërarchisch (product → PBI → story → taak), biedt gesplitste planningsschermen met drag-and-drop, en integreert met Claude Code via een REST API en MCP https://scrum4-me.vercel.app
Find a file
Janpeter Visser b6249a41c0
feat(PBI-67): IDEA_REVIEW_PLAN + geconsolideerde WIP-fixes (#203)
* fix(ci): docs:check-links groen — exclude docs/old/ + archiveer stale plans

CI faalde sinds #191 (docs cleanup) op pre-existing broken links:
- docs/old/ bevat archief-docs met by-design stale paden
- docs/plans/PBI-79*, M9*, M11* hadden geprojecteerde paden naar
  ../backlog/index.md (verplaatst naar docs/old/backlog/) en naar
  app-bestanden die nooit met de juiste relatieve prefix waren geschreven
- docs/adr/0000* verwees naar docs-restructure-ai-lookup.md (verplaatst)
- docs/glossary.md verwees naar /docs/backlog/index.md (verplaatst)

Fixes:
- scripts/check-doc-links.mjs: skip docs/old/ recursief
- Move docs/plans/{PBI-79,M9,M11}*.md → docs/old/plans/ (allemaal merged PBIs;
  plans waren historisch)
- docs/adr/0000-record-architecture-decisions.md: update pad naar archief
- docs/glossary.md: verwijder dode "backlog index"-link

Verificatie: `npm run docs:check-links` → ✓ All doc links valid (105 files)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(sprint-conflicts): stories uit CLOSED/ARCHIVED/FAILED sprints zijn weer eligible

Bug: bij sprint-aanmaken (en story-toevoegen aan een actieve sprint) gaf de
backend "Geen eligible stories voor deze sprint" zodra je stories aanvinkte
die ooit in een sprint hadden gezeten — ook als die sprint allang gesloten
of gearchiveerd was. partitionByEligibility checkte alleen story.sprint_id,
nooit sprint.status, terwijl getBlockingSprintMap in dezelfde file wél al
filterde op sprint: { status: 'OPEN' }. Inconsistent.

Fix: partitionByEligibility en isEligibleForSprint wegen nu sprint.status
mee. Een story blokkeert alleen als hij in een ANDERE sprint zit DIE NOG
OPEN is. Stories uit CLOSED/ARCHIVED/FAILED sprints worden weer vrij voor
planning — story.sprint_id blijft als historische referentie staan tot de
volgende updateMany hem overschrijft naar de nieuwe sprint.

Neveneffect: een DONE story in een gesloten sprint krijgt nu reason='DONE'
i.p.v. het misleidende reason='IN_OTHER_SPRINT'.

Tests: 3 nieuwe scenario's in __tests__/lib/sprint-conflicts.test.ts
(CLOSED/ARCHIVED/FAILED → eligible, DONE-in-CLOSED → reason=DONE).
De oude test 'does NOT mark crossSprint for stories in CLOSED other sprint'
is vervangen omdat hij het bug-gedrag vastlegde.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(sprint-switcher): repareer mock om CI te unblocken

Twee pre-existing mock-bugs die op main al rood waren maar geen gevolgen
hadden tot de CI-monitor erop sloeg in deze PR:

1. Mock-state miste `entities.settings`. Sinds PBI-79 (commit d587be2)
   selecteert SprintSwitcher ook `s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal`,
   maar de testmock leverde alleen `{ context }`. → undefined-crash op
   `entities.settings` reading.

2. Mock factory exporteerde alleen `setActiveSprintAction`, maar de
   productie roept `switchActiveSprintAction` aan. Door `vi.mock` werden
   alle andere exports `undefined`, waardoor `actionMock` nooit kon
   triggeren.

Out-of-scope-fix t.o.v. de sprint-eligibility-fix in dit PR — apart commit
zodat reviewer dit als losse cleanup kan zien. CI is nu groen lokaal:
3/3 sprint-switcher tests + 839/839 full suite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(ideas): upload-plan knop — short-circuit van Make-Plan AI-flow

Voegt een 'Upload plan' knop toe in idea-row-actions (verschijnt in zowel
list als idea-detail). Klik → file picker → kies .md → server-side parse +
opslaan; idea-status springt naar PLAN_READY. Vandaaruit de bestaande
'Maak PBI' knop voor materialize.

Server (uploadPlanMdAction):
- Toegestaan vanuit DRAFT, GRILLED, PLAN_FAILED, PLAN_READY
- DRAFT → skip-grill: status gaat direct naar PLAN_READY
- PLAN_READY overschrijft het bestaande plan (consistent met
  updatePlanMdAction, geen confirmation)
- Geblokkeerd in GRILLING/PLANNING (job loopt), PLANNED (al gematerialiseerd)
- Parse-failure → 422 + details (NIET opslaan, zodat een onparseerbaar plan
  nooit in de DB belandt)
- Empty / >100k chars → 422
- Schrijft IdeaLog NOTE met from_status + length
- Rate-limit + demo-guard + ownership-check via loadOwnedIdea (zelfde
  patroon als updatePlanMdAction)

UI (idea-row-actions.tsx):
- Hidden <input type=file accept=".md,.markdown,text/markdown,text/plain">
- FileReader → text → action
- Toast bij success + router.refresh()
- Blocked-tooltip in andere statussen

Tests: 10 nieuwe in __tests__/actions/ideas-crud.test.ts dekkend voor:
happy paths (DRAFT/GRILLED/PLAN_READY-overwrite/PLAN_FAILED), blocks
(PLANNED/GRILLING), validation (empty/oversized/parse-fail), 404.
Full suite groen: 849/849.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add reviews for Bootstrap-wizard plans v3.2 to v3.4

- Review v3.2: Addressed executor model, fire-and-forget issues, and PAT handling.
- Review v3.3: Improved transaction handling, stale recovery, and ID generation.
- Review v3.4: Finalized GitHub permissions, catalog versioning, and E2E verification queries.
- Updated recommendations for each version to enhance implementation readiness.

* fix(ideas): respecteer YAML-volgorde bij plan-materialize

Tasks erven nu story-priority i.p.v. eigen task.priority bij
materializeIdeaPlanAction. Worker sorteert op `priority ASC, sort_order ASC`;
gemixte task-priorities binnen één story zouden anders de YAML-volgorde
verstoren (e.g. tasks met priority 1/1/1/2/1/2 → worker-volgorde 1,2,3,5,4,6
i.p.v. 1,2,3,4,5,6).

- actions/ideas.ts: priority = s.priority bij task-create
- lib/schemas/idea.ts: task.priority optional (geaccepteerd, genegeerd)
- lib/idea-prompts/make-plan.md: documenteer dat task.priority genegeerd wordt
- __tests__/lib/idea-schemas.test.ts: test dat omitted task.priority slaagt

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(make-plan): documenteer backtick-format voor implementation_plan-paden

verify_task_against_plan extraheert paden uit implementation_plan via twee
regex-patronen (backticks + bullet). Paden inline in genummerde tekst-stappen
worden niet herkend → planPaths.length=0 → bij diff >50 regels DIVERGENT.

Voeg sectie "Bestandspaden in implementation_plan — verplicht format" toe
die uitlegt welke formats werken (backticks, bullets) en welke niet (inline).
Plus verband met verify_required-keuze: default ALIGNED_OR_PARTIAL behouden
voor ADR-stubs en multi-file edits.

Voorkomt herhaling van T-963 cancelled_by_self-symptoom waar implementatie
slaagde maar verifier DIVERGENT teruggaf.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plans): M8 bootstrap-wizard upload-variant v1.4 — backtick-paden

Upload-variant van het volledige technische plan (docs/plans/M8-bootstrap-wizard.md),
bedoeld voor de "Upload plan"-functie. Genereert 1 PBI + 4 Stories + 22 Tasks
via materializeIdeaPlanAction.

v1.4-aanpassingen tov eerdere generatie-iteratie:
- Alle bestandspaden in implementation_plan in backticks (path-extractor matchen)
- Expliciete "Bestanden:" blok per task vóór de stappen
- Alle tasks op verify_required: ALIGNED_OR_PARTIAL (was deels ALIGNED — te strict
  voor ADR-stubs en multi-file edits)

Fixt forward-only: T-963 cancelled_by_self door DIVERGENT verifier-verdict.
Re-upload van dit bestand produceert tasks die door verify_task_against_plan
als ALIGNED of PARTIAL geclassificeerd kunnen worden.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* PBI-67: Add review-plan support to Idea model and job config

- Add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum
- Add IDEA_REVIEW_PLAN config to job-config.ts with model=opus, thinking_budget=6000
- Create migration record for schema changes (applied via db push)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* PBI-67 Phase 2: Add update-idea-plan-reviewed MCP tool

- Create src/tools/update-idea-plan-reviewed.ts: saves review-log and transitions idea status to PLAN_REVIEWED
- Add PLAN_REVIEW_RESULT to IdeaLogType enum (both repos)
- Register tool in src/index.ts
- Update Prisma schemas (both repos): add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum (MCP schema)
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum (MCP schema)
- Tool includes transaction safety and convergence metrics logging

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* feat(PBI-67): IDEA_REVIEW_PLAN Phases 3-6 — server actions, UI components, prompt & tests

- Phase 3: startReviewPlanJobAction, cancelIdeaJobAction, status transitions
  (REVIEWING_PLAN / PLAN_REVIEWED / PLAN_REVIEW_FAILED), status colors,
  job-card/jobs-column filters, idea-list status tabs
- Phase 4: review-plan-job.md prompt (multi-model orchestration with codex
  injection + active plan revision via update_idea_plan_md after each round),
  runbook, 13 unit tests
- Phase 5: ReviewLogViewer component (rounds, convergence, approval, issues),
  idea-detail integration, proper ReviewLog TypeScript types exported from component
- Phase 6.1: wait-for-job discriminator wired (IDEA_REVIEW_PLAN), plan-revision
  step made mandatory in prompt (was previously optional/missing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 17:59:27 +02:00
.github/workflows chore(ci): gate auto-deploy behind AUTO_DEPLOY_ENABLED repo-variable (#154) 2026-05-07 20:17:15 +02:00
.husky docs: AI-optimized docs restructure (Phases 1–8) (#61) 2026-05-03 03:21:59 +02:00
.icons chore: middleware.ts verwijderd, icon-bron toegevoegd, versie 0.2.0 2026-04-24 23:05:00 +02:00
__tests__ feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
actions feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
app feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
components feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
docs feat(PBI-67): IDEA_REVIEW_PLAN + geconsolideerde WIP-fixes (#203) 2026-05-14 17:59:27 +02:00
hooks fix(PBI-59): map jobs_initial SSE payload by job_id, not id (#155) 2026-05-07 20:22:07 +02:00
lib fix(ideas): make nextIdeaCode self-correcting against counter drift (#200) 2026-05-14 12:46:47 +02:00
prisma feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
public Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
scripts feat(PBI-67): IDEA_REVIEW_PLAN — iterative multi-model plan review (#199) 2026-05-14 03:35:02 +02:00
stores feat(PBI-79): Product Backlog sprint-membership via vinkjes (#190) 2026-05-11 18:56:46 +02:00
tests feat(PBI-74): Zustand product-workspace rearchitecture (Stories 1-8) (#180) 2026-05-10 02:25:19 +02:00
.env.example feat(PBI-66): wekelijkse sync van model_prices via Anthropic /v1/models (#167) 2026-05-08 09:38:33 +02:00
.gitattributes chore: .gitattributes toevoegen voor consistente LF regeleindes 2026-04-24 23:06:21 +02:00
.gitignore chore: ignore .claude/worktrees in git (#166) 2026-05-08 09:29:59 +02:00
AGENTS.md Agent batch-flow: lokaal committen, push + PR aan het eind (#66) 2026-05-03 15:51:24 +02:00
CHANGELOG.md docs(cleanup): archief verouderde plannen, backlog en root-duplicaten (#191) 2026-05-11 19:46:00 +02:00
CLAUDE.md feat(PBI-80): demo-user mag eigen UI-voorkeuren wijzigen (#194) 2026-05-12 20:03:40 +02:00
components.json feat: ST-001–ST-005 foundation — scaffolding, Prisma, schema, seed, env 2026-04-22 21:04:48 +02:00
eslint.config.mjs Load/render workspace alignment (#182) 2026-05-10 07:34:58 +02:00
instrumentation-client.ts feat(ops): Sentry error-monitoring (v1-readiness item 2) 2026-05-04 13:24:19 +02:00
instrumentation.ts feat(ops): Sentry error-monitoring (v1-readiness item 2) 2026-05-04 13:24:19 +02:00
next.config.ts feat(ops): Sentry error-monitoring (v1-readiness item 2) 2026-05-04 13:24:19 +02:00
package-lock.json feat(PBI-76): user-settings DB-store infrastructure (Phase 0) (#185) 2026-05-10 12:44:32 +02:00
package.json feat: shared backlog filter popover + sprint header polish (v1.3.3) (#184) 2026-05-10 11:12:04 +02:00
postcss.config.mjs Initial commit from Create Next App 2026-04-22 20:25:19 +02:00
prisma.config.ts fix: url en directUrl uit schema.prisma verplaatst naar prisma.config.ts (Prisma v7) 2026-04-24 14:26:44 +02:00
proxy.ts proxy: add /ideas to protectedRoutes; verify demo-guard for /api/ideas (M12 T-501) 2026-05-04 19:56:41 +02:00
README.md docs(cleanup): archief verouderde plannen, backlog en root-duplicaten (#191) 2026-05-11 19:46:00 +02:00
sentry.edge.config.ts feat(ops): Sentry error-monitoring (v1-readiness item 2) 2026-05-04 13:24:19 +02:00
sentry.server.config.ts feat(ops): Sentry error-monitoring (v1-readiness item 2) 2026-05-04 13:24:19 +02:00
tsconfig.json Initial commit from Create Next App 2026-04-22 20:25:19 +02:00
vercel.json feat(T-553): vercel.json git.deploymentEnabled=false + GitHub-labels 2026-05-05 23:31:34 +02:00
vitest.config.ts Load/render workspace alignment (#182) 2026-05-10 07:34:58 +02:00

Scrum4Me Agile Project Management Tool

Portfolio samenvatting

Scrum4Me is een moderne fullstack webapplicatie voor agile projectmanagement.
De applicatie is gebouwd als portfolio-project om mijn vaardigheden in moderne softwareontwikkeling, cloud deployment en AI-assisted development te demonstreren.

Doel

Veel teams missen overzicht en flexibiliteit in agile workflows.
Scrum4Me biedt een lichtgewicht, web-based oplossing voor het beheren van sprints, taken en teamprocessen.

Mijn rol

  • Architectuur en ontwerp
  • Fullstack development (frontend + backend)
  • Database ontwerp
  • Implementatie van authenticatie en API's
  • CI/CD en deployment
  • AI-assisted development workflow

Functionaliteiten

  • Agile dashboards en product backlogs
  • PBI-, story-, sprint- en taakbeheer
  • Authenticatie en gebruikersbeheer
  • Teamtoegang via eigenaar of gekoppelde Developer
  • API tokens voor externe integraties
  • REST API voor Claude Code workflows
  • Drag-and-drop interactie voor planning
  • Story-activiteitenlog voor plannen, testresultaten en commits
  • Profielfoto, bio en rolbeheer

Technologie stack

  • Next.js 16 (App Router)
  • React 19
  • TypeScript
  • Prisma ORM
  • PostgreSQL (Neon)
  • iron-session en bcryptjs
  • Zustand
  • dnd-kit
  • Tailwind CSS en shadcn/ui
  • Sharp voor avatarverwerking
  • Vercel Analytics
  • Vercel hosting
  • GitHub Actions / CI-CD

Documentation

Architectuur (kort)

  • Frontend en backend via Next.js App Router
  • Server Components voor data loading
  • Server Actions voor UI-mutaties
  • Route Handlers voor de externe REST API
  • Database via Prisma + PostgreSQL
  • Auth via versleutelde sessiecookies
  • Producttoegang via eigenaar of product_members
  • Deployment via Vercel met Neon als database

Live demo

Voeg hier je Vercel link toe.

Screenshots

Voeg hier screenshots toe van dashboard, product backlog, sprint planning en instellingen.

Wat ik geleerd heb

  • Werken met moderne fullstack architectuur in Next.js
  • Databaseontwerp met Prisma en PostgreSQL
  • Server Actions combineren met REST API Route Handlers
  • Beveiliging van cross-user en cross-scope toegang
  • AI-assisted development integreren in een eigen workflow
  • Cloud deployment en verificatie via Vercel
  • Documentatie en agent-instructies verbeteren op basis van code review

Toekomstige verbeteringen

  • Multi-user samenwerking verder uitbreiden
  • Notificaties
  • Performance optimalisatie
  • Uitbreiding AI-functionaliteit
  • Meer integratietests voor autorisatie en API-flows

Repository

https://github.com/madhura68/Scrum4Me


Technische aanvulling

Deze sectie bevat de praktische projectinformatie die nodig is om de app lokaal te draaien, te deployen en veilig door te ontwikkelen.

Lokale setup

  1. Installeer dependencies:
npm ci
  1. Maak lokale environment variabelen:
cp .env.example .env.local

Vul daarna DATABASE_URL en SESSION_SECRET in. DIRECT_URL is optioneel lokaal, maar handig voor migraties in cloudomgevingen.

  1. Synchroniseer of migreer de database:
npx prisma db push
  1. Genereer Prisma Client:
npx prisma generate
  1. Seed testdata indien nodig:
npx prisma db seed
  1. Start de app:
npm run dev

Testing

Unit tests (Vitest, geen database vereist):

npm test

Verwacht: alle 445 tests slagen, 0 failures.

API curl-tests (vereist lopende dev server + API token):

# Zie scripts/README.md voor setup-instructies
bash scripts/test-api.sh

De curl-tests dekken alle 7 API-endpoints: auth (401), demo-blokkering (403), inputvalidatie (400) en happy paths. Zie docs/qa/api-test-plan.md voor het volledige testplan.

Database

Het schema staat in prisma/schema.prisma; uitgebreide documentatie in docs/architecture/data-model.md.

Gebruik npx prisma db push om schema-wijzigingen naar de database te synchroniseren. npx prisma generate (of prisma generate --generator client in CI) genereert de Prisma Client.

De app draait standaard op http://localhost:3000.

Scripts

npm run dev      # lokale development server
npm run lint     # ESLint
npm test         # Vitest test suite
npm run build    # productiebuild zoals Vercel die verwacht

Environment variables

Zie .env.example.

Variabele Verplicht Doel
DATABASE_URL Ja PostgreSQL connection string voor Prisma
DIRECT_URL Nee Directe Neon connection string voor migraties (Prisma directUrl)
SESSION_SECRET Ja Minimaal 32 tekens; gebruikt door iron-session
CRON_SECRET Productie Bearer-secret voor /api/cron/* routes — required als crons aan staan
NEXT_PUBLIC_VAPID_PUBLIC_KEY Nee VAPID public key voor Web Push — genereer met npx web-push generate-vapid-keys
VAPID_PRIVATE_KEY Nee VAPID private key voor Web Push
VAPID_SUBJECT Nee Contact URI voor Web Push (bijv. mailto:admin@example.com)
INTERNAL_PUSH_SECRET Nee Bearer-secret voor /api/internal/push/* routes (min 32 tekens)
NEXT_PUBLIC_SENTRY_DSN Nee Sentry DSN — zonder is de SDK een no-op
SENTRY_ORG / SENTRY_PROJECT / SENTRY_AUTH_TOKEN Nee Source-map upload tijdens build
NODE_ENV Nee Wordt door Node/Vercel gezet

Vercel Analytics gebruikt geen project-specifieke environment variabele in deze app; de component staat in app/layout.tsx.

Commit Guidelines

We follow a strict commit structure to keep the project maintainable and reviewable.

Rules

  • 1 commit = 1 logical change
  • Do not mix:
    • features + docs
    • features + config
    • schema + UI
  • Keep commits small and focused
  • Prefer multiple small commits over one large commit

Commit format

We use a simplified conventional commit style:

  • feat: new feature
  • fix: bug fix
  • docs: documentation only
  • chore: config / tooling / cleanup
  • refactor: code improvement without behavior change

Examples

Good:

feat(db): add user profile fields
feat(api): add avatar upload endpoint
feat(ui): add profile editor
docs: document profile feature

Bad:

feat: add profile + update docs + fix config

API-overzicht

Alle API-endpoints vereisen:

Authorization: Bearer <token>
Methode Endpoint Doel
GET /api/health Liveness; ?db=1 doet ook een DB-ping (geen auth)
GET /api/products Actieve producten waarvoor de tokengebruiker eigenaar of teamlid is
GET /api/products/:id/next-story Hoogst geprioriteerde open story uit de actieve sprint
GET /api/products/:id/claude-context Bundled product / actieve sprint / next-story (met tasks) / open ideas voor MCP
GET /api/sprints/:id/tasks?limit=10 Eerste taken van een sprint
PATCH /api/stories/:id/tasks/reorder Taakvolgorde aanpassen; alle IDs moeten bij de story horen
POST /api/stories/:id/log Implementatieplan, testresultaat of commit vastleggen
PATCH /api/tasks/:id Taakstatus of implementation_plan bijwerken
GET / POST /api/ideas · GET / PATCH /api/ideas/:id Idea CRUD (M12 — vervangt voormalige /api/todos)
GET /api/jobs/:id/sub-tasks sprint_task_executions van een SPRINT_IMPLEMENTATION-job
GET /api/users/:id/avatar Avatar van een specifieke gebruiker
POST / GET /api/profile/avatar Eigen avatar uploaden of opvragen

Daarnaast leveren /api/realtime/{backlog,solo,jobs,notifications} SSE-streams en zijn er auth-helpers /api/auth/pair/* (QR-pairing, M10), interne push-routes onder /api/internal/push/*, en cron-handlers (/api/cron/cleanup-agent-artifacts, /api/cron/expire-questions).

Security-regels

  • Server Actions en Route Handlers vertrouwen nooit op losse client-ID's zonder scope-check.
  • Producttoegang loopt via eigenaar of product_members.
  • Bulk-mutaties valideren eerst dat alle IDs bij dezelfde toegankelijke parent horen.
  • Denormalized fields zoals story.product_id worden afgeleid van de database-parent, niet van form-data.
  • Demo-gebruikers krijgen 403 op schrijfoperaties.

Deployment

De productieomgeving is gericht op Vercel + Neon.

  1. Zet DATABASE_URL, eventueel DIRECT_URL, en SESSION_SECRET in Vercel.
  2. Zorg dat de Neon-database gemigreerd is.
  3. Push naar main; Vercel deployt automatisch.
  4. Controleer na deployment:
    • login en dashboard
    • /api/products met een API-token
    • avatar-upload
    • Vercel Analytics in het Vercel dashboard

Documentatie