feat: full feature buildout — streaming, i18n, mastery map, admin, jobs
Progressive lesson streaming via onSegment callback (fixes SSE for non-English users — locale was shadowed in lesson-reader useEffect). Adds: BullMQ workers, Redis stream buffer, token budget enforcement, Langfuse tracing, golden-eval runner, Playwright e2e scaffolding, lesson depth/locale/preferences schema, mastery map UI, admin panel (blueprints/users/reports/quality/misconceptions), image queries, source citations, view transitions, reading animations, i18n (next-intl), PDF export, surprise endpoint, and 402 passing unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
|
||||
type Report = { id: string; checkpointId: string; gradeId: string | null; reason: string; notes: string | null; createdAt: Date };
|
||||
type Report = {
|
||||
id: string;
|
||||
checkpointId: string;
|
||||
gradeId: string | null;
|
||||
reason: string;
|
||||
notes: string | null;
|
||||
createdAt: Date;
|
||||
intentKey: string;
|
||||
blueprintTitle: string;
|
||||
segmentOrd: number;
|
||||
depth: string;
|
||||
locale: string;
|
||||
};
|
||||
|
||||
export default function AdminReportsClient({ reports }: { reports: Report[] }) {
|
||||
const router = useRouter();
|
||||
@@ -34,9 +47,15 @@ export default function AdminReportsClient({ reports }: { reports: Report[] }) {
|
||||
<span style={s.date}>{new Date(r.createdAt).toLocaleDateString()}</span>
|
||||
</div>
|
||||
{r.notes && <p style={s.notes}>{r.notes}</p>}
|
||||
<p style={{ fontSize: '0.8125rem', color: 'var(--color-ink-faint)', fontFamily: 'var(--font-display)' }}>
|
||||
checkpoint {r.checkpointId.slice(0, 8)}…
|
||||
</p>
|
||||
<Link
|
||||
href={`/learn/${r.intentKey}?depth=${r.depth}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={s.lessonLink}
|
||||
>
|
||||
{r.blueprintTitle} · segment {r.segmentOrd + 1} ↗
|
||||
</Link>
|
||||
<p style={s.checkpointMeta}>checkpoint {r.checkpointId.slice(0, 8)}…</p>
|
||||
<div style={{ display: 'flex', gap: 'var(--space-2)', marginTop: 'var(--space-3)' }}>
|
||||
<button disabled={busy === r.id} onClick={() => act(r.id, 'dismiss')} style={s.btn}>Dismiss</button>
|
||||
<button disabled={busy === r.id} onClick={() => act(r.id, 're-verify')} style={s.btn}>Flag for re-verify</button>
|
||||
@@ -56,5 +75,7 @@ const s = {
|
||||
tag: { fontFamily: 'var(--font-display)', fontSize: '0.75rem', fontWeight: 600, padding: '2px 8px', background: 'var(--color-accent-subtle)', color: 'var(--color-accent)', borderRadius: '3px' },
|
||||
date: { fontSize: '0.8125rem', color: 'var(--color-ink-faint)', fontFamily: 'var(--font-display)' },
|
||||
notes: { fontSize: '0.9375rem', color: 'var(--color-ink-muted)' },
|
||||
lessonLink: { fontFamily: 'var(--font-display)', fontSize: '0.9375rem', fontWeight: 500, color: 'var(--color-accent)', textDecoration: 'none' },
|
||||
checkpointMeta: { fontSize: '0.75rem', color: 'var(--color-ink-faint)', fontFamily: 'var(--font-display)' },
|
||||
btn: { padding: 'var(--space-1) var(--space-4)', background: 'var(--color-surface)', border: '1px solid var(--color-border)', borderRadius: '4px', cursor: 'pointer', fontFamily: 'var(--font-display)', fontSize: '0.875rem', color: 'var(--color-ink)' },
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user