Phase 9e: Account-Page mit DSGVO-Self-Service
Neuer User-JWT-Pfad GET/POST /api/v1/me/{export,delete} — gespiegelte
DSGVO-Logik aus dem Service-Key-Pfad, aber gegen die eigene User-ID
gated. buildUserExport extrahiert in dsgvo.ts und wird von beiden
Routern geteilt.
/account-Page zeigt User-ID, Logout, JSON-Daten-Export (Download als
Blob), und einen rot-markierten Account-Delete-Knopf mit "LÖSCHEN"-
Confirmation. Logout im Header verlinkt jetzt auf /account statt
direkt clear() — der User sieht zuerst, was an seinem Account hängt.
Andere mana-Apps werden nicht mit gelöscht — der UI-Hinweistext zeigt
auf die spätere Verein-DSGVO-Sammelanfrage über mana-admin.
48 API-Tests grün (+2 neue auth-gate-Tests für /me), web type-check
374 files 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aff4d9536a
commit
03117d5869
7 changed files with 316 additions and 52 deletions
30
apps/web/src/lib/api/me.ts
Normal file
30
apps/web/src/lib/api/me.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { api } from './client.ts';
|
||||
|
||||
export interface UserExport {
|
||||
user_id: string;
|
||||
exported_at: string;
|
||||
app: string;
|
||||
app_version: string;
|
||||
data: {
|
||||
decks: unknown[];
|
||||
cards: unknown[];
|
||||
reviews: unknown[];
|
||||
study_sessions: unknown[];
|
||||
tags: unknown[];
|
||||
media_refs: unknown[];
|
||||
import_jobs: unknown[];
|
||||
};
|
||||
}
|
||||
|
||||
/** Lädt den vollständigen DSGVO-Export der eigenen Daten (User-JWT). */
|
||||
export function exportMe() {
|
||||
return api<UserExport>('/api/v1/me/export');
|
||||
}
|
||||
|
||||
/** Löscht alle Cards-Daten des eingeloggten Users (User-JWT). */
|
||||
export function deleteMe() {
|
||||
return api<{ deleted: true; user_id: string; counts: { decks: number; import_jobs: number } }>(
|
||||
'/api/v1/me/delete',
|
||||
{ method: 'POST' }
|
||||
);
|
||||
}
|
||||
|
|
@ -36,15 +36,13 @@
|
|||
|
||||
<div class="flex items-center gap-3 text-sm">
|
||||
{#if devUser.id}
|
||||
<span class="text-[var(--color-muted)]"
|
||||
>{devUser.id}
|
||||
</span>
|
||||
<button
|
||||
class="rounded border px-2 py-1 text-xs hover:bg-[var(--color-border)] border-[var(--color-border)]"
|
||||
onclick={() => devUser.clear()}
|
||||
<a
|
||||
href="/account"
|
||||
class="truncate max-w-[180px] text-[var(--color-muted)] hover:text-[var(--color-fg)]"
|
||||
title={devUser.id}
|
||||
>
|
||||
Logout (dev)
|
||||
</button>
|
||||
{devUser.id}
|
||||
</a>
|
||||
{:else}
|
||||
<button
|
||||
class="rounded bg-[var(--color-primary)] px-3 py-1 text-[var(--color-primary-fg)]"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue