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 7ae8a24372
Sprint: pbi-55 (#156)
* ST-cmovs79lt: Schema + migratie PushSubscription model

Voeg PushSubscription model toe aan prisma/schema.prisma met
snake_case-conventie, relation field op User, en bijbehorende
migratie (push_subscriptions tabel, FK + index op user_id).

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

* ST-cmovs7e3o: web-push dependency + VAPID env vars feature-gated

Voeg web-push + @types/web-push toe aan package.json.
Registreer NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY,
VAPID_SUBJECT en INTERNAL_PUSH_SECRET als .optional() in lib/env.ts.
Documenteer alle vier in .env.example en README.

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

* ST-cmovs7jgr: lib/push-server.ts met sendPushToUser + stale-cleanup

Server-only push-lib met VAPID feature-gate, send naar alle
subscriptions van een user, en automatische cleanup bij 404/410.
Unit tests: success-pad, 410 verwijdert sub, 404 verwijdert sub,
andere errors loggen zonder delete.

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

* ST-cmovs7ouz: lib/push-client.ts client-side push helpers + stub actions/push.ts

Client-side helpers: isPushSupported, isIOSSafari, isStandalonePWA,
urlBase64ToUint8Array, subscribeToPush, unsubscribeFromPush.
Stub actions/push.ts zodat imports resolven (implementatie volgt
in volgende taak). Unit tests voor urlBase64ToUint8Array.

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

* ST-cmovs7ut4: actions/push.ts subscribeToPushAction + unsubscribeFromPushAction

Vervangt stub met volledige implementatie: requireUser via getSession,
demo-block, Zod-validatie, upsert met user_id-scoping en user-scoped
deleteMany. Tests (8): idempotentie, demo-block, unauthenticated, invalid input.

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

* ST-cmovs80c1: POST /api/internal/push/send met constant-time Bearer check

Route: 503 als INTERNAL_PUSH_SECRET uitstaat, 401 bij verkeerd secret
(timingSafeEqual), 400 bij invalid JSON, 422 bij Zod-fout, 204 bij succes.
push-server.ts: env-import vervangen door process.env om SESSION_SECRET
validatie tijdens build te omzeilen. Tests aangepast.

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

* ST-cmovs862j: Admin test-send route + public/sw.js service worker

POST /api/internal/push/test-send: requireAdmin check (redirect bij
niet-admin), optioneel body met defaults, roept sendPushToUser aan, 204.
public/sw.js: push-handler met showNotification, notificationclick met
same-origin guard, focus bestaand venster of openWindow.

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

* ST-cmovs8jvq: PushToggle component met 3 states + iOS-banner

Client component met states loading/unsupported/ios-needs-install/
denied/subscribed/unsubscribed. useEffect detecteert initial status,
permission-prompt alleen via user-click. iOS-banner NL, denied-uitleg,
subscribe/unsubscribe knoppen met sonner-toasts.

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

* ST-cmovs8psg: notifications-sheet + iOS meta-tags in layout

notifications-sheet.tsx: PushToggle onderin met sectie
'Notificatie-instellingen' en visuele scheidslijn.
app/layout.tsx: appleWebApp.capable, statusBarStyle en
mobile-web-app-capable meta-tags toegevoegd via Next.js Metadata API.
manifest.json had al display: standalone.

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

* ST-cmovs8vxj: docs/patterns/web-push.md pattern-documentatie

Architectuur-diagram, payload-shape, foutcodes, VAPID-config,
iOS-quirks, demo-users blokkade, trigger-voorbeelden (server +
HTTP) en admin-testroute curl-voorbeeld.

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 21:46:01 +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__ Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
actions Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
app Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
components Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
docs Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +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 Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
prisma Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
public Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
scripts PBI-58: Developer manual + in-app /manual page (#148) 2026-05-07 18:00:10 +02:00
stores fix(PBI-59): jobs sorted newest-first, unified on created_at (#157) 2026-05-07 20:58:27 +02:00
.env.example Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
.gitattributes chore: .gitattributes toevoegen voor consistente LF regeleindes 2026-04-24 23:06:21 +02:00
.gitignore docs: AI-optimized docs restructure (Phases 1–8) (#61) 2026-05-03 03:21: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 chore: bump version to 1.0.0 2026-05-04 14:25:15 +02:00
CLAUDE.md docs(T-557): deploy-control runbook + CLAUDE.md verwijzing 2026-05-05 23:36:48 +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 fix: lint errors en warnings opgelost voor CI 2026-04-24 14:09:03 +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 Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +02:00
package.json Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +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 Sprint: pbi-55 (#156) 2026-05-07 21:46:01 +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 feat: ST-601-ST-612 M6 polish, beveiliging en launch-ready 2026-04-24 12:36:23 +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 en de ERD:
npm run db:erd

Deze command voert lokaal prisma generate uit. Daardoor worden zowel de Prisma Client als docs/assets/erd.svg opnieuw opgebouwd.

In CI en deployment wordt bewust alleen de Prisma Client gegenereerd met prisma generate --generator client. Het ERD-diagram gebruikt Mermaid/Puppeteer en wordt daarom niet in GitHub Actions of Vercel gegenereerd.

  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

ERD

De databasevisualisatie wordt lokaal gegenereerd uit prisma/schema.prisma via prisma-erd-generator.

Handmatige generatie:

npm run db:erd

Optioneel: npm run db:erd:watch parallel aan npm run dev om bij wijzigingen in prisma/schema.prisma docs/assets/erd.svg automatisch opnieuw te genereren.

Gebruik npx prisma db push alleen om het schema naar de database te synchroniseren. Gebruik npm run db:erd om lokaal Prisma Client en de ERD te genereren. Gebruik in CI uitsluitend npx prisma generate --generator 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
npm run db:erd   # Prisma Client + docs/assets/erd.svg genereren

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/products Actieve producten waarvoor de tokengebruiker eigenaar of teamlid is
GET /api/products/:id/next-story Volgende story uit de actieve sprint
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 implementatieplan bijwerken
POST /api/todos Todo aanmaken binnen een productcontext

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