From 18a7ee1fa518bbd9c560fc41941bd372abd04904 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 6 May 2026 10:29:30 +0200 Subject: [PATCH] docs: remove accidentally committed spec file Spec file was pre-staged from a prior session and bundled into the previous commit. Specs belong in Gitea issues, not committed to the repo. Co-Authored-By: Claude Sonnet 4.6 --- .../2026-05-06-reader-dashboard-design.md | 165 ------------------ 1 file changed, 165 deletions(-) delete mode 100644 docs/superpowers/specs/2026-05-06-reader-dashboard-design.md diff --git a/docs/superpowers/specs/2026-05-06-reader-dashboard-design.md b/docs/superpowers/specs/2026-05-06-reader-dashboard-design.md deleted file mode 100644 index 8456d3e4..00000000 --- a/docs/superpowers/specs/2026-05-06-reader-dashboard-design.md +++ /dev/null @@ -1,165 +0,0 @@ -# Reader Dashboard — Design Spec - -**Date:** 2026-05-06 -**Status:** Approved for implementation planning - ---- - -## Problem - -The archive has two distinct user groups: - -- **Contributors** — transcribe, annotate, upload. Comfortable with the current dashboard (MissionControlStrip, EnrichmentBlock, enrichment queue, activity feed). -- **Readers** — browse and consume finished content. Older, less technical. Currently overwhelmed by contribution-focused UI they cannot use and do not need. - ---- - -## Solution - -Introduce a **permission-gated reader dashboard** that replaces the current dashboard for users without `WRITE_ALL` or `ANNOTATE_ALL` (including pure readers and story writers). The contributor dashboard remains unchanged. - ---- - -## Detection Logic - -``` -isReader = !canWrite && !canAnnotate -showDrafts = canBlogWrite // overlays on reader dashboard only -``` - -`BLOG_WRITE` users land on the **reader dashboard** (not the contributor dashboard), because story writers are conceptually closer to readers than to transcribers. The drafts module appears on top of the reader layout when `canBlogWrite` is true. - -`canWrite`, `canAnnotate`, `canBlogWrite` are already derived in `+layout.server.ts` and available in `$page.data` on all routes. No new backend work required for detection. - ---- - -## Reader Dashboard Layout - -Five zones, rendered top-to-bottom: - -### 1. Greeting -Unchanged from current dashboard — personalized, time-based greeting. Warm entry point for less technical users. - -### 2. Stats Strip -Three linked stat tiles in a single row: - -| Tile | Value | Link | -|---|---|---| -| Dokumente | Total document count | `/documents` | -| Personen | Total person count | `/persons` | -| Geschichten | Total published story count | `/geschichten` | - -Each tile is a full-area anchor (``). Values come from the existing stats endpoint already called by the current dashboard. - -### 3. Drafts Module *(conditional — BLOG_WRITE only)* -Shown only when `canBlogWrite` is true, between the stats strip and the person chips. - -- Section heading: "Meine Entwürfe" -- Lists all draft stories authored by the current user, sorted by `updated_at DESC` -- Each entry shows: story title + "Entwurf · zuletzt bearbeitet vor X" relative timestamp -- Each entry links to `/geschichten/[id]/edit` -- Empty state: "Keine Entwürfe" (no empty-state CTA needed — they can create from `/geschichten`) - -This module appears on the reader dashboard because a user can hold `READ_ALL + BLOG_WRITE` without `WRITE_ALL`. - -### 4. Person Chips -Top **4** persons by total document count, each linking to `/persons/[id]`. Followed by an overflow link "Alle N Personen →" pointing to `/persons`. - -- Chip content: display name + document count (e.g., "Käthe Raddatz · 23 Dok.") -- Layout: `flex flex-wrap gap-2` — chips reflow gracefully at narrower viewports -- Data source: persons list endpoint, sorted by document count DESC, limit 4 - -Rationale: readers most often browse by person rather than searching for a specific document. Surfacing the most-documented family members at the top answers "where do I start?" - -### 5. Two-Column Content Row -Side-by-side at desktop; stacks to single column on mobile (below `md` breakpoint). - -**Left column — "Zuletzt aktualisiert" (flex: 3)** - -5 most recently updated documents, sorted by `updated_at DESC`. No status filter — uploads and transcription updates are both relevant. - -Each row shows: -- Document thumbnail placeholder (or actual thumbnail if available) -- Document title (linked to `/documents/[id]`) -- Sender name (linked to `/persons/[id]`) if present; omitted if document has no sender + relative timestamp - -**Right column — "Geschichten" (flex: 2)** - -3 most recently published stories. - -Each entry shows: -- Story title (italic serif, linked to `/geschichten/[id]`) -- First ~150 characters of body text as excerpt -- Relative publication timestamp - ---- - -## What Is Hidden from Readers - -| Component | Reason | -|---|---| -| `MissionControlStrip` | Transcription queue — contributor-only | -| `EnrichmentBlock` | Incomplete-document workflow — contributor-only | -| `DashboardResumeStrip` | Contribution resume metric — meaningless to readers | -| `DashboardFamilyPulse` | Contribution-focused activity metrics | -| `DashboardActivityFeed` | Replaced by the simpler "Zuletzt aktualisiert" feed | -| `DropZone` | Already gated on `canWrite` — unchanged | - ---- - -## Backend Changes - -The reader dashboard reuses data from endpoints already called by the existing dashboard where possible. New or adapted calls: - -| Data | Endpoint | Notes | -|---|---|---| -| Stats (docs, persons, stories) | Existing stats endpoint | Already fetched | -| Top 4 persons by doc count | `GET /api/persons?sort=documentCount,desc&size=4` | Verify sort param exists; add if not | -| Recent 5 documents | `GET /api/documents?sort=updatedAt,desc&size=5` | Verify sort param exists; add if not | -| Recent 3 stories | `GET /api/geschichten?published=true&sort=updatedAt,desc&size=3` | Verify sort param and published filter | -| Draft stories (BLOG_WRITE only) | `GET /api/geschichten?published=false&authorId=currentUser&size=10` | Verify author filter exists; add if not | - -The `+page.server.ts` load function should branch on `isReader`: fetch the reader data set instead of the contributor data set. This avoids loading transcription queues, enrichment data, and weekly stats for users who will never see them. - ---- - -## Frontend Changes - -- `+page.server.ts`: add `isReader` flag derived from layout data; branch fetch logic -- `+page.svelte`: conditional render — reader layout vs. current contributor layout -- New components (all in `src/lib/shared/dashboard/`): - - `ReaderStatsStrip.svelte` — the three linked stat tiles - - `ReaderPersonChips.svelte` — top-N person chips + overflow link - - `ReaderRecentDocs.svelte` — recent documents feed - - `ReaderRecentStories.svelte` — recent stories feed - - `ReaderDraftsModule.svelte` — draft stories (rendered conditionally on `canBlogWrite`) - ---- - -## Non-Functional Requirements - -- **NFR-PERF-001**: Reader dashboard must load in ≤ 2 s on broadband (time-to-interactive). Achieved by fetching only the 4 lean endpoints above instead of the current 10. -- **NFR-A11Y-001**: All stat tiles and person chips must be keyboard-navigable (`` elements, not `
`). -- **NFR-RESP-001**: Two-column row stacks to single column at `< md` (768 px). Person chips wrap via `flex-wrap`. -- **NFR-I18N-001**: All new section headings and labels must have keys in `messages/{de,en,es}.json`. - ---- - -## Out of Scope - -- Mobile-specific reader dashboard (responsive reflow is sufficient for now) -- Admin dashboard variant -- Any change to the contributor dashboard -- Personalization / "favourite persons" feature (possible future enhancement) -- Notification or messaging features for readers - ---- - -## Open Questions - -| ID | Question | Blocks | -|---|---|---| -| OQ-01 | Does `GET /api/persons` support `sort=documentCount,desc`? | ReaderPersonChips data | -| OQ-02 | Does `GET /api/documents` support `sort=updatedAt,desc`? | ReaderRecentDocs data | -| OQ-03 | Does the stories endpoint support `published=false` + author filter for drafts? | ReaderDraftsModule data | -| OQ-04 | Should the "Zuletzt aktualisiert" label distinguish uploads from transcription updates (e.g., badge)? | ReaderRecentDocs UX |