feat: ST-401-ST-410 M4 REST API, tokenbeleer en activiteitenlog

- api-auth.ts was al aanwezig; demo-check toegevoegd per endpoint (ST-401)
- Token aanmaken (SHA-256 hash, eenmalig tonen), intrekken, max 10 (ST-402)
- GET /api/products actieve productenlijst (ST-403)
- GET /api/products/:id/next-story hoogst geprioriteerde open story (ST-404)
- GET /api/sprints/:id/tasks met limit parameter (ST-405)
- PATCH /api/stories/:id/tasks/reorder met ID-validatie (ST-406)
- POST /api/stories/:id/log met discriminatedUnion per type (ST-407)
- PATCH /api/tasks/:id status bijwerken met cross-user bescherming (ST-408)
- POST /api/todos via API aanmaken (ST-409)
- StoryLog component met kleurcodering per type in story slide-over (ST-410)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-24 11:56:29 +02:00
parent d92e548f88
commit b71a1a7328
14 changed files with 713 additions and 1 deletions

View file

@ -0,0 +1,34 @@
import { cookies } from 'next/headers'
import { getIronSession } from 'iron-session'
import { SessionData, sessionOptions } from '@/lib/session'
import Link from 'next/link'
export default async function SettingsPage() {
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
return (
<div className="p-6 max-w-2xl mx-auto w-full space-y-6">
<h1 className="text-xl font-medium text-foreground">Instellingen</h1>
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-3">
<h2 className="text-sm font-medium text-foreground">Account</h2>
<p className="text-sm text-muted-foreground">
Ingelogd als <span className="text-foreground font-medium">{session.userId}</span>
{session.isDemo && <span className="ml-2 text-warning text-xs">(demo)</span>}
</p>
</div>
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-3">
<div className="flex items-center justify-between">
<h2 className="text-sm font-medium text-foreground">API Tokens</h2>
<Link href="/settings/tokens" className="text-xs text-primary hover:underline">
Beheren
</Link>
</div>
<p className="text-sm text-muted-foreground">
Gebruik API tokens om Scrum4Me te koppelen aan Claude Code.
</p>
</div>
</div>
)
}

View file

@ -0,0 +1,37 @@
import { cookies } from 'next/headers'
import { getIronSession } from 'iron-session'
import { SessionData, sessionOptions } from '@/lib/session'
import { prisma } from '@/lib/prisma'
import { TokenManager } from '@/components/settings/token-manager'
import Link from 'next/link'
export default async function TokensPage() {
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
const tokens = await prisma.apiToken.findMany({
where: { user_id: session.userId },
orderBy: { created_at: 'desc' },
})
return (
<div className="p-6 max-w-2xl mx-auto w-full">
<div className="flex items-center gap-3 mb-6">
<Link href="/settings" className="text-muted-foreground hover:text-foreground text-sm">
Instellingen
</Link>
<span className="text-muted-foreground">/</span>
<h1 className="text-xl font-medium text-foreground">API Tokens</h1>
</div>
<TokenManager
tokens={tokens.map(t => ({
id: t.id,
label: t.label,
created_at: t.created_at.toISOString(),
revoked_at: t.revoked_at?.toISOString() ?? null,
}))}
isDemo={session.isDemo ?? false}
/>
</div>
)
}