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:
parent
d92e548f88
commit
b71a1a7328
14 changed files with 713 additions and 1 deletions
34
app/(app)/settings/page.tsx
Normal file
34
app/(app)/settings/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
37
app/(app)/settings/tokens/page.tsx
Normal file
37
app/(app)/settings/tokens/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue