Files
everythingbutwork/_bmad-output/planning-artifacts/epics.md
T
dejanandClaude Opus 4.7 4f33509a0f
ci / quality (push) Has been cancelled
ci / build (push) Has been cancelled
Initial commit: everythingbutwork MVP
Internes Project-Management-Tool für ToolCTRL — ergänzend zu Plane (Tickets)
und Outline (Doku). Umfasst Puls-Übersicht, Tagesrhythmus (Lock-in + Reflexion),
Bereichs-Detail-Views (Entwicklung/Vertrieb/Marketing), Pflicht-Minimum-Check
und Blocker-Lifecycle gemäß Projektmanagement-Leitfaden v3.0.

Stack: pnpm-Monorepo · Vite + React 18 + Tailwind · Fastify + tRPC v11 +
Drizzle ORM · Postgres 16 · Authentik OIDC (Phase 2, Dev-Auto-Login aktiv).

Planungs-Artefakte unter _bmad-output/planning-artifacts/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 22:47:26 +02:00

967 lines
56 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
stepsCompleted: [1, 2, 3, 4]
status: 'complete'
completedAt: '2026-05-25'
inputDocuments:
- prds/prd-projectmanagement-2026-05-25/prd.md
- prds/prd-projectmanagement-2026-05-25/addendum.md
- architecture.md
- ux-design-specification.md
- prds/prd-projectmanagement-2026-05-25/.decision-log.md
workflowType: 'epics-and-stories'
project_name: 'ToolCTRL Unternehmens-Cockpit'
user_name: 'Dejancosic'
date: '2026-05-25'
---
# ToolCTRL Unternehmens-Cockpit - Epic Breakdown
## Overview
Dieses Dokument zerlegt das PRD (49 FRs, 16 NFRs), die Architektur (komplett, Vite + React + Fastify + tRPC + Drizzle + Postgres + Authentik) und die UX-Spec (15 Custom-Components, Brand-Tokens, 5 User Journeys) in implementierbare Epics und Stories.
## Requirements Inventory
### Functional Requirements
> 49 FRs aus PRD §6, organisiert in 10 Feature-Gruppen (A–J).
**A: Unternehmens-Puls (Startseite)**
- **FR-1** Übersichtsleiste aller Areas (Entwicklung, Vertrieb, Marketing) inkl. aggregiertem Ampelstatus und Anzahl heute-fehlender Updates pro Area.
- **FR-1a** Ampel-Aggregation Algorithmus pro Area: Rot wenn ≥ 1 Projekt rot; Gelb wenn ≥ 1 Projekt gelb und kein rotes; Grün wenn alle grün; Grau wenn keine aktiven Projekte. Pflicht-Minimum-Verstöße heben Ampel mindestens auf Gelb.
- **FR-2** Bereichsübergreifende Liste aller offenen Blocker, sortiert nach Alter.
- **FR-3** Heute-Quote „X von Y Mitarbeitern haben heute gepingt" mit Klick auf Liste der fehlenden Personen.
- **FR-4** Anzeige des nächsten Jourfixe-Termins (statisch konfigurierbar, Default Di 11:00).
- **FR-5** Pro Bereich definierter Key-Metrics-Katalog:
- Entwicklung: # Projekte gesamt / im Plan / gefährdet / blockiert / # überzogene Meilensteine.
- Vertrieb: gewichteter Pipeline-Wert (Σ value × probability) / # offene Deals / gewonnene Deals (Quartal, # + EUR) / # offene GTM-Schritte.
- Marketing: Reichweite (Periode) / # aktive Kampagnen / Leads / MQLs / Übergaben an Vertrieb.
- **FR-6** Klick auf Bereich-Kachel öffnet Bereichs-Detail-View.
- **FR-7** Pflicht-Minimum-Übersicht im Puls: Liste aller aktiven Projekte mit roten/gelben Pflicht-Minimum-Punkten.
**B: Bereichs-Detail Entwicklung**
- **FR-8** Liste aller aktiven Projekte, gruppiert nach Projektart (Kundenprojekt / Internes Projekt — Leitfaden §1).
- **FR-9** Pro Projekt-Kachel: Name, Verantwortliche/r (P1), Ampelstatus + Trend (↗︎/→/↘︎), Deadline-Progress-Bar, # offene Meilensteine, Pflicht-Minimum-Score (z. B. „5/6").
- **FR-10** Projekt-Detail mit Kopfzeile (Name, P1, Projektart, Arbeitsmodus, Ampel + Trend), Pflicht-Minimum-Anzeige, Verlinkungen (Outline-Steckbrief, Plane-Board, Risikoliste), optional DoD-Text, Meilenstein-Checkliste, Update-Feed.
- **FR-11** Meilensteine als grobe Cockpit-Sicht (Titel, Fälligkeit, Status: offen/erledigt/überzogen). Wahrheit bleibt im Outline-Steckbrief.
**C: Bereichs-Detail Vertrieb**
- **FR-12** 5-Spalten Kanban: Lead → Erstgespräch → Demo → Angebot → Abschluss, mit Drag-and-Drop.
- **FR-13** Deal-Karten: Name, Verantwortlicher, Wert (€), Stage-Wahrscheinlichkeit (0-100 %), Tage in aktueller Stage.
- **FR-14** Vertriebs-Header-KPIs: gewichteter Pipeline-Wert, gewonnene Deals (# + EUR, laufendes Quartal), aktiver Deal-Count, ⌀ Stage-Verweildauer.
- **FR-15** Pro Produkt eine sortierbare GTM-Schritt-Liste (Schritt, Verantwortlicher, Status).
- **FR-16** Vertrieb-Update-Feed (Filter Bezug = Deal oder Vertrieb-allgemein).
**D: Bereichs-Detail Marketing**
- **FR-17** Horizontaler Lead-Funnel mit 5 Stufen (Reichweite → Website → Leads → MQL → Übergabe) + Conversion-%.
- **FR-18** Liste aktiver Kampagnen mit Status (Aktiv / Pausiert / Beendet), Reichweite, Verantwortlicher.
- **FR-19** Crosslink-Banner Marketing↔Vertrieb: „Marketing hat X Leads übergeben in [Zeitraum], Vertrieb hat daraus Y Deals erzeugt (Z €)".
- **FR-20** Marketing-Update-Feed (Filter Bezug = Kampagne oder Marketing-allgemein).
**E: Tagesrhythmus**
- **FR-21** „Einstempeln"-Aktion auf Puls (großer CTA), öffnet ToDo-Eingabe für heute.
- **FR-22** ToDo-Liste: 1-N Items, pro Item Titel (max. 200 Z) + optionaler Bezug.
- **FR-23** Eingestempelt = Tag „begonnen", Person verschwindet aus „heute fehlt"-Liste.
- **FR-24** Sichtbarkeit innerhalb des Tages: nur binäre Anwesenheit für Kollegen, ToDo-Inhalte privat. P1 sieht ToDos seiner Projekte.
- **FR-25** ToDos editierbar bis zur Reflexion.
- **FR-26** Reflexions-Formular: ToDos abhaken/verwerfen (mit Grund), Freitext (max. 1000 Z), Ampel (Grün/Gelb/Rot mit Leitfaden-Semantik), Trend (Pflicht bei Bezug=Projekt), optional Blocker, optional URL.
- **FR-27** Reflexion → Tag „voll abgeschlossen", Streak +1.
- **FR-28** Reflexion 30 min editierbar; Reflexions-Erinnerung ab konfigurierbarer Zeit (Default 17:00).
- **FR-29** Konsolidierter Vortags-Eintrag wird am nächsten Werktag morgen publiziert (sichtbar für Kollegen).
- **FR-30** Feed-Sortierung: neueste oben. Pagination 50/Seite.
- **FR-31** Reflexion setzt automatisch Ampel + Trend des verlinkten Projekts/Deals/Kampagne.
- **FR-32** Rückwirkende Erfassung max. 1 Werktag zurück.
- **FR-33** Tages-Status pro Person: 🟢 voll / 🟡 halb / ⚪ nicht angefangen / 🟣 abwesend.
**F: Streak / Anwesenheit / Disziplin**
- **FR-34** Pro Person aktuelle Streak (aufeinanderfolgende „volle" Werktage).
- **FR-35** „Heute fehlt"-Liste auf Puls — nach 11:00 für nicht-eingestempelte, nach 17:00 für „halb"-Status.
- **FR-36** Werktage = Mo-Fr (Feiertage Phase 2).
- **FR-37** Person markiert sich für Tag/Zeitraum als „Abwesend" (Urlaub/Krankheit), zählt nicht gegen Streak.
**G: Pflicht-Minimum-Check (Leitfaden §9)**
- **FR-38** Pro aktivem Projekt 6-Punkte-Checkliste sichtbar:
1. Projektsteckbrief in Outline freigegeben → erfüllt wenn `outline_steckbrief_url` gepflegt UND als „freigegeben" markiert.
2. P1 gesetzt.
3. Plane-Board mit zerlegter Arbeit → erfüllt wenn `plane_project_url` gepflegt.
4. Meilensteine mit groben Terminen → erfüllt wenn ≥ 1 Meilenstein.
5. Status-Ampel aktuell → erfüllt wenn letzte Reflexion mit Projektbezug ≤ 7 Werktage alt.
6. Abschluss-Retrospektive (nur bei beendeten Projekten).
- **FR-39** MVP: Punkte 1, 2, 3, 4 manuell als Cockpit-Checkbox; Punkt 5 automatisch aus Reflexions-Zeitstempel; Punkt 6 im Abschluss-Workflow.
- **FR-40** Projekte mit unerfülltem Pflicht-Punkt prominent auf Puls.
**H: Blocker**
- **FR-41** Blocker entsteht inline in Reflexion oder via „Neuer Blocker"-Button.
- **FR-42** Blocker-Felder: Titel, Beschreibung, Verantwortlicher, Ersteller, Bereich(e), Datum offen, Status.
- **FR-43** Blocker erscheint auf Puls, in betroffenen Bereichs-Detail-Views und in Projekt-Detail.
- **FR-44** Auflösung mit Auflöser, Datum, Kommentar. Nur P1 des bezogenen Projekts darf auflösen; bei projektlosen Blockern auch Ersteller/Verantwortlicher.
**I: Projekt-Abschluss**
- **FR-45** P1 setzt Projekt auf „abgeschlossen".
- **FR-46** Beim Abschluss fordert Cockpit Lessons-Learned-URL an.
- **FR-47** Abgeschlossene Projekte verschwinden aus Puls, bleiben in Archiv-Sicht pro Bereich.
**J: Navigation, Suche & Filter**
- **FR-48** Globale TopNav: Puls / Entwicklung / Vertrieb / Marketing / Mein heute / Eigenes Profil / Archiv.
- **FR-49** Volltextsuche → Phase 2; MVP: Filter im Feed nach Bereich/Bezug.
### NonFunctional Requirements
> 16 NFRs aus PRD §7.
**Performance**
- **NFR-1** Puls-Seite < 1,5 s bei 6-15 Nutzern und 90 Tagen Historie.
- **NFR-2** Tagesupdate-Speichern < 500 ms.
**Verfügbarkeit**
- **NFR-3** Mo-Fr 8-19: 99 %.
- **NFR-4** Wartungsfenster außerhalb Kernzeit kommunizierbar.
**Security & Privacy**
- **NFR-5** Alle Routen hinter Authentik-OIDC.
- **NFR-6** Keine externe PII in Deal-Karten.
- **NFR-7** Audit-Trail für jede mutierende Operation (actor / timestamp / payload).
**Bedienbarkeit & Visual**
- **NFR-8** Brand-konform: weiß primär, schwarz sekundär, ToolCTRL Brand Identity.
- **NFR-9** Tagesupdate-Schreib-Workflow ≤ 3 Klicks ab Puls.
- **NFR-10** Desktop-first, mobil-lesbar (nicht mobil-schreibbar).
- **NFR-11** Deutsch durchgängig, keine i18n.
**Voice & Tone**
- **NFR-12** Tonalität locker/direkt/deutsch, kurze Imperative ("Stark.", "Wie läuft es?", "Du hast heute noch nicht gepingt.").
- **NFR-13** Keine Corporate-Sprech, keine englischen Floskeln (Fachbegriffe aus Leitfaden ausgenommen).
**Datenhaltung & Erweiterbarkeit**
- **NFR-14** Postgres als Persistenz.
- **NFR-15** Tägliches Backup.
- **NFR-16** Datenmodell erweiterbar ohne Migrationen > 2 h.
### Additional Requirements
> Aus Architektur-Spec abgeleitete technische Anforderungen.
- **AR-1** **Starter / Bootstrap**: Custom Monorepo (pnpm-Workspaces) mit `apps/web` (Vite + React + TS + Tailwind), `apps/api` (Fastify + tRPC + Drizzle), `packages/db` (Drizzle-Schema), `packages/shared` (Zod + Types). Erste Story nutzt die in der Architektur §"Initialization Commands" beschriebenen Setup-Befehle.
- **AR-2** **Datenmodell** in `packages/db/schema.ts` mit allen 14 Entitäten (User, Area, Project, Milestone, Deal, GtmStep, Campaign, LeadHandover, DayEntry, Todo, Blocker, AbsenceDay, AuditEvent, Session) gemäß Addendum §1.2 und Architektur §Project Structure. UUID v7 als ID-Primary.
- **AR-3** **Auth-Flow**: `openid-client` v6+ direkt im Fastify, Authorization Code + PKCE gegen Authentik. Server-Side-Session in Postgres, HttpOnly + SameSite=Lax + Secure Cookie. Default-Bereich aus Authentik-Group-Claim.
- **AR-4** **tRPC Procedure-Typen**: `publicProcedure`, `protectedProcedure`, `dayEntryVisibleProcedure` (Sichtbarkeitsfilter pre/post `published_at`), `projectOwnerProcedure` (P1-Check).
- **AR-5** **Audit-Middleware** (`withAudit`) um jede schreibende tRPC-Mutation, schreibt parallel in `audit_event`.
- **AR-6** **Background-Jobs** via System-Cron → authentifizierter Fastify-Endpoint (`POST /internal/cron/*` mit Bearer-Token):
- `publish-day-entries` (tägl. 00:05 Europe/Berlin)
- `recompute-pflicht-minimum-5` (stündlich)
- `recompute-streaks` (tägl. 00:10)
- `pg-dump-backup` (tägl. 02:00)
- **AR-7** **Werktag-Logik** zentral in `apps/api/src/lib/werktag.ts` (Mo-Fr Europe/Berlin). Frontend bekommt vorberechnete Werte, niemals eigene Datumsmagie.
- **AR-8** **Ampel-Aggregation** in `apps/api/src/lib/ampel.ts` (FR-1a-Algorithmus).
- **AR-9** **Pflicht-Minimum-Berechnung** in `apps/api/src/lib/pflicht-minimum.ts`, lazy beim Read.
- **AR-10** **Hosting**: Docker-Compose mit `web`-Container (Caddy-served `apps/web/dist`), `api`-Container (Node 22+), `postgres:16`-Container, `caddy`-Container als Reverse-Proxy auf `cockpit.tool-ctrl.de`.
- **AR-11** **CI/CD**: Gitea Actions Pipeline (Typecheck, Lint, Vitest, Build, Docker-Image-Push, Deploy-Trigger).
- **AR-12** **Tests**: Vitest (Unit + tRPC-Procedures), Playwright (E2E auf UJ-1, UJ-2, UJ-5). Lighthouse-A11y-Score ≥ 95.
- **AR-13** **Logging**: strukturierte JSON-Logs via `pino` → stdout.
- **AR-14** **Healthcheck**: `GET /api/health` (Postgres-Ping + Authentik-Reachability) für Docker-Healthcheck.
- **AR-15** **Konventionen-Datei** `CONVENTIONS.md` im Repo-Root (spiegelt Architektur §Implementation Patterns), Pflicht-Lesen vor Story-Bearbeitung.
- **AR-16** **Backup-Strategie**: `pg_dump` täglich auf separates Volume, Retention 14 Tage. Restore-Drill quartalsweise dokumentiert in `docs/operations.md`.
### UX Design Requirements
> Aus UX-Spec abgeleitete UI/Visual/A11y-Anforderungen.
**Brand-Tokens & Visual Foundation**
- **UX-DR1** Brand-Tokens als CSS-Variablen in `apps/web/src/styles/globals.css` definieren und in `tailwind.config.ts` als Theme spiegeln. Werte gemäß UX-Spec §Visual Design Foundation:
- `--color-bg: #ffffff`, `--color-surface: #fafafa`, `--color-surface-elevated: #ffffff`
- `--color-border: #e5e5e5`, `--color-border-strong: #d4d4d4`
- `--color-ink: #0a0a0a`, `--color-ink-muted: #525252`, `--color-ink-faint: #a3a3a3`
- `--color-brand: #0a0a0a`, `--color-brand-fg: #ffffff`
- Ampel: green `#15803d`/`#dcfce7`, amber `#a16207`/`#fef3c7`, red `#b91c1c`/`#fee2e2`
- Trend: up `#15803d`, flat `#525252`, down `#b91c1c`
- **UX-DR2** Typografie: Inter (UI, variable) + JetBrains Mono (Werte) selbst-gehostet via `@fontsource/inter` und `@fontsource/jetbrains-mono`. 7-Stufen-Type-Scale aus UX-Spec §Typography.
- **UX-DR3** Spacing-Skala, Radii und Schatten gemäß UX-Spec §Spacing & Layout — als Tailwind-Theme-Erweiterung.
- **UX-DR4** Container-Max-Width 1.280 px, 12-Spalten-Grid mit 24 px Gap; Puls auf Desktop 3-Spalten.
**Custom-Component-Library (`apps/web/src/components/ui/`)**
- **UX-DR5** `Button` mit 3 Varianten (primary/secondary/ghost) + Destructive + Icon-Only, 3 Größen (sm/md/lg).
- **UX-DR6** `Card` mit Compound-API (`Card.Root`, `Card.Header`, `Card.Body`, `Card.Footer`).
- **UX-DR7** `Input`, `Textarea` (mit Zeichen-Counter), `Select` (via Radix), `Checkbox` (via Radix mit animiertem Häkchen).
- **UX-DR8** `AmpelButton` (3-Wege-Toggle Grün/Gelb/Rot, große Klick-Targets), `TrendButton` (3-Wege ↗︎/→/↘︎).
- **UX-DR9** `Dialog` (via Radix mit Brand-Header und `radius-xl`), `Tooltip` (via Radix, schwarzer Bubble), `Toast` (via Sonner, Bottom-Right, schwarzer Pill).
- **UX-DR10** `SkeletonCard` — graue Card-Skelette identischer Geometrie wie echte Cards.
- **UX-DR11** `AmpelBadge` — Status-Pill mit Farbpunkt + Label + optionalem Trend-Pfeil.
- **UX-DR12** `PflichtMinimumIndicator` — sechs kleine Quadrate horizontal, gefüllt/leer.
- **UX-DR13** `KeyCaret` — SVG-Komponente für das Brand-`^`-Element, einbindbar in Header/Logo/Toast.
**Layout & Navigation**
- **UX-DR14** TopNav fest mit `cockpit ^` Logo links, Tabs (Puls / Entwicklung / Vertrieb / Marketing / Mein heute / Archiv), rechts Streak-Badge + Avatar. Aktiver Tab mit 2 px schwarzem Underline.
- **UX-DR15** Breadcrumbs in Detail-Views (`Puls › Entwicklung › Projekt X`), klickbar pro Segment.
- **UX-DR16** Tastatur-Shortcuts: `g p`, `g h`, `g e`, `g v`, `g m`, `g a`, `n` (Neuer Blocker), `?` (Cheatsheet), `Esc` (Modal schließen).
**Voice & Tone (Mikrocopy)**
- **UX-DR17** Zentrale Mikrocopy-Datei `apps/web/src/lib/voice.ts` mit allen UI-Strings. Beispiele: „Stark.", „Wie läuft es?", „Du hast heute noch nicht gepingt.", „Reflektiert.", „Blocker offen.". Pflicht-Anwendung in allen Komponenten.
**User-Journey-Flows**
- **UX-DR18** UJ-1 Tagesrhythmus: `/mein-heute` (Morgen-Einstempeln + ToDo-Editor) und `/reflexion` (Abend-Reflexion mit Tagesplan-Echo).
- **UX-DR19** UJ-2 Jourfixe: Puls-Layout muss alle 3 Bereiche in einem Scroll abdeckbar machen.
- **UX-DR20** UJ-5 Projekt anlegen: Modal mit Pflicht-Feldern (Name, P1, Projektart, Arbeitsmodus, Steckbrief-URL, Plane-URL).
**Responsive & Accessibility**
- **UX-DR21** Drei Sicht-Ebenen: Desktop (≥ 1280 px, 3-Spalten Puls), Tablet (≥ 768 px, 2-Spalten), Mobile (< 768 px, Single-Column + Bottom-Tab-Bar, lesbar).
- **UX-DR22** WCAG 2.1 AA durchgängig. Keyboard-First (Tab, Enter, Space, Esc). Sichtbarer Fokus-Ring (`outline: 2px solid var(--color-ink)`, 2 px Offset).
- **UX-DR23** Skip-Link „Zum Hauptinhalt springen" oben. Saubere Heading-Hierarchie. Live-Regionen für Toasts.
- **UX-DR24** `prefers-reduced-motion` → Fade-Animationen auf 0 ms.
- **UX-DR25** axe-core in Vitest pro Komponente; `@axe-core/playwright` für E2E. ESlint-`jsx-a11y` mit `recommended` aktiviert.
**Interaktions-Patterns**
- **UX-DR26** Optimistic Updates bei Checkbox-Abhaken und Ampel-Setzen (Rollback bei API-Fehler).
- **UX-DR27** Skeleton-Cards beim Initial-Load — nie leerer Bildschirm, nie Spinner alleine.
- **UX-DR28** Empty-States als Voice-konforme Tropfen-Information (z. B. „Hier erscheinen die Updates des Tages, sobald jemand reflektiert hat.").
- **UX-DR29** Reflexions-Erinnerung im Header ab 17:00 (dezenter Pill, klickbar).
- **UX-DR30** Vortrags-Reveal: Fade-In ≤ 200 ms beim ersten Laden am Werktag X+1.
### FR Coverage Map
| FR | Epic | Kurztitel |
|---|---|---|
| FR-1, FR-1a, FR-2, FR-3, FR-4, FR-5, FR-6, FR-7 | Epic 3 | Puls & Übersicht |
| FR-8, FR-9, FR-10, FR-11 | Epic 4 | Bereich Entwicklung |
| FR-12, FR-13, FR-14, FR-15, FR-16 | Epic 4 | Bereich Vertrieb |
| FR-17, FR-18, FR-19, FR-20 | Epic 4 | Bereich Marketing |
| FR-21 – FR-33 | Epic 2 | Tagesrhythmus |
| FR-34, FR-35, FR-36, FR-37 | Epic 2 + Epic 3 | Streak + Anwesenheit |
| FR-38, FR-39, FR-40 | Epic 5 | Pflicht-Minimum |
| FR-41, FR-42, FR-43, FR-44 | Epic 5 | Blocker |
| FR-45, FR-46, FR-47 | Epic 6 | Projekt-Abschluss |
| FR-48 | Epic 1 | Navigation (Top-Nav) |
| FR-49 | Phase 2 | Volltextsuche |
**NFR-Abdeckung:** NFR-5/7/8/9 ⇒ Epic 1 · NFR-1/2 ⇒ über alle Epics validiert · NFR-3/4/14/15/16 ⇒ Epic 6 · NFR-10/11/12/13 ⇒ Epic 1 + Epic 2 (Voice-Anker etabliert)
## Epic List
> 6 Epics, jedes liefert ein eigenständig nutzbares Stück. Reihenfolge folgt der in `architecture.md` § "Decision Impact Analysis → Implementation Sequence" festgelegten Story-Sequenz.
### Epic 1: Fundament — Login, Shell, Brand
**Ziel:** Eine Person kann sich via Authentik einloggen und landet in einer leeren, brand-konformen Cockpit-Shell mit funktionierender Navigation. Es passiert noch nichts Fachliches — aber das Fundament steht.
**Was nach Epic 1 nutzbar ist:**
- Login/Logout funktioniert
- TopNav steht (Puls-Tab, Profil, Streak-Badge-Slot leer)
- Brand-Theme aktiv (Farben, Typografie, KeyCaret-Logo)
- Healthcheck + Docker-Compose laufen lokal
**FRs:** FR-48
**NFRs:** NFR-5, NFR-7, NFR-8, NFR-9 (vorbereitet), NFR-11, NFR-12, NFR-13, NFR-14
**AR:** AR-1, AR-2 (Schema-Skeleton User+Session+AuditEvent), AR-3, AR-4 (Procedure-Typen-Skeleton), AR-5 (Audit-Wrapper), AR-10, AR-15, AR-13 (pino), AR-14 (Healthcheck)
**UX-DR:** UX-DR1, UX-DR2, UX-DR3, UX-DR4, UX-DR5, UX-DR6, UX-DR7, UX-DR13, UX-DR14, UX-DR15, UX-DR16, UX-DR17, UX-DR22, UX-DR23, UX-DR24, UX-DR25
### Epic 2: Tagesrhythmus — Einstempeln, ToDos, Reflexion
**Ziel:** Eine Person kann morgens einstempeln + ToDos schreiben, abends reflektieren mit Ampel/Trend, und am nächsten Werktag wird der konsolidierte Eintrag für Kollegen sichtbar. Das Herz des Cockpits.
**Was nach Epic 2 nutzbar ist:**
- Person kann den vollen Tagesrhythmus durchlaufen (UJ-1)
- Streak und Tages-Status erscheinen im Profil und in der „Heute fehlt"-Liste (basal — volle Puls-Visualisierung kommt in Epic 3)
- Cron-Job publiziert Vortags-Einträge
**FRs:** FR-21 – FR-33, FR-34, FR-36, FR-37
**AR:** AR-2 (Schema DayEntry, Todo, AbsenceDay), AR-4 (`dayEntryVisibleProcedure`), AR-5, AR-6 (publish-day-entries cron + recompute-streaks cron), AR-7
**UX-DR:** UX-DR8 (AmpelButton, TrendButton), UX-DR9 (Dialog für AbwesendDialog), UX-DR10 (SkeletonCard), UX-DR18 (`/mein-heute` + `/reflexion`), UX-DR26 (optimistic), UX-DR27 (Skeleton), UX-DR28 (Empty-State), UX-DR29 (17:00-Hinweis), UX-DR30 (Vortrags-Reveal Fade-In)
### Epic 3: Puls & Bereichs-Übersicht
**Ziel:** Eine Person öffnet das Cockpit und sieht in unter 60 Sekunden den Unternehmens-Puls: alle drei Bereiche mit aggregiertem Ampelstatus, Heute-Quote, bereichsübergreifende Blocker, Jourfixe-Hinweis. Vortrags-Einträge im Feed.
**Was nach Epic 3 nutzbar ist:**
- Puls-Seite ist die Heimat (UJ-2, UJ-3)
- „Heute fehlt"-Liste klickbar mit Personen
- Bereichs-Strip mit Ampel-Aggregation
- Feed konsolidierter Vortrags-Einträge
**FRs:** FR-1, FR-1a, FR-2, FR-3, FR-4, FR-5 (Schema-Layout, KPIs werden mit Echtdaten in Epic 4 gefüllt), FR-6, FR-7 (Pflicht-Minimum-Slot, gefüllt in Epic 5), FR-35
**AR:** AR-8 (Ampel-Aggregation), AR-7 (Werktage)
**UX-DR:** UX-DR11 (AmpelBadge), UX-DR19 (Puls-Layout 3-Spalten)
### Epic 4: Projekte, Deals, Kampagnen — Bereichs-Details
**Ziel:** Eine Person kann Projekte (Entwicklung), Deals (Vertrieb) und Kampagnen (Marketing) anlegen und pflegen. Bereichs-Detail-Views zeigen Listen, Kanban, Lead-Funnel, Crosslinks. Reflexionen (aus Epic 2) setzen Projekt-Ampeln korrekt.
**Was nach Epic 4 nutzbar ist:**
- Projekte/Deals/Kampagnen können angelegt, geändert und gelistet werden (UJ-5)
- Sales-Kanban funktioniert (Drag-and-Drop, Stage-Wechsel)
- Lead-Funnel + Crosslink-Banner zeigen Aggregate
- KPIs im Puls-Bereichs-Strip (FR-5) zeigen Echtdaten
**FRs:** FR-8, FR-9, FR-10, FR-11, FR-12, FR-13, FR-14, FR-15, FR-16, FR-17, FR-18, FR-19, FR-20, FR-31
**AR:** AR-2 (Schema Project, Milestone, Deal, GtmStep, Campaign, LeadHandover)
**UX-DR:** UX-DR9 (Dialog für Projekt-Anlegen), UX-DR20 (Projekt-Anlege-Modal)
### Epic 5: Pflicht-Minimum & Blocker
**Ziel:** Die 6 Leitfaden-Pflicht-Punkte pro Projekt werden sichtbar gemacht. Blocker können erfasst, gelistet und (nur durch P1) aufgelöst werden.
**Was nach Epic 5 nutzbar ist:**
- Pflicht-Minimum-Indikator in Projekt-Card und -Detail (FR-7 wird voll funktional auf dem Puls)
- Blocker-Lebenszyklus komplett (Erfassen via Reflexion-Inline oder „+ Neuer Blocker"-Button, Anzeige im Puls/Bereich/Projekt, Auflösung)
- Frühwarn-Mechanik aktiv
**FRs:** FR-38, FR-39, FR-40, FR-41, FR-42, FR-43, FR-44
**AR:** AR-4 (`projectOwnerProcedure`), AR-6 (recompute-pflicht-minimum-5 cron), AR-9
**UX-DR:** UX-DR12 (PflichtMinimumIndicator)
### Epic 6: Projekt-Abschluss, Archiv & Production
**Ziel:** Projekte können abgeschlossen werden (mit Lessons-Learned-Link), Archiv-Sicht existiert. Production-Pipeline ist scharf: CI/CD, tägliches Backup, Healthcheck-Monitoring, A11y-Tests im CI.
**Was nach Epic 6 nutzbar ist:**
- Volle Projekt-Lebensspanne von Anlage bis Lessons-Learned
- Cockpit ist deploybar und beobachtbar
- Backup + Restore-Drill dokumentiert
- A11y-Score ≥ 95 im CI gemessen
**FRs:** FR-45, FR-46, FR-47
**NFRs:** NFR-1, NFR-2, NFR-3, NFR-4, NFR-10 (Responsive-Validierung), NFR-15, NFR-16
**AR:** AR-6 (pg-dump-backup), AR-11 (Gitea Actions), AR-12 (Tests, Playwright), AR-14 (Healthcheck-Erweiterung), AR-16 (Backup + Restore-Drill)
**UX-DR:** UX-DR21 (Responsive-Sichtbarkeitsprüfung), UX-DR25 (axe-core + jsx-a11y in CI)
---
**Phase-2-Backlog (nicht im MVP, nicht in Epics):**
- FR-49 Volltextsuche
- Plane-/Outline-API-Sync
- Mobile schreibbar
- Reaktionen / Kommentare auf Updates
- Element/Matrix/Mail-Reminders
- Loki/Grafana, Sentry, Feiertags-Kalender, Dark Mode
---
## Epic 1: Fundament — Login, Shell, Brand
Eine Person kann sich via Authentik einloggen und landet in einer leeren, brand-konformen Cockpit-Shell mit funktionierender Navigation. Es passiert noch nichts Fachliches — aber das Fundament steht und alle weiteren Epics können darauf aufsetzen.
### Story 1.1: Repo-Bootstrap und Tooling
Als **Entwickler**,
ich möchte **ein lauffähiges Monorepo mit Vite-Frontend, Fastify-Backend, Drizzle-DB-Package und Shared-Package**,
sodass **alle Folge-Stories auf einem konsistenten Setup aufsetzen können**.
**Acceptance Criteria:**
**Given** ein leeres `cockpit/`-Repo,
**When** `pnpm install` und `pnpm typecheck` ausgeführt werden,
**Then** alle 4 Workspaces (`apps/web`, `apps/api`, `packages/db`, `packages/shared`) sind installiert und typecheckbar
**And** `pnpm --filter web dev` startet Vite auf Port 5173
**And** `pnpm --filter api dev` startet Fastify auf Port 3000
**And** `CONVENTIONS.md` ist im Repo-Root vorhanden und spiegelt die Patterns aus `architecture.md` § Implementation Patterns
**And** ESLint und Prettier sind konfiguriert und liefern keinen Fehler beim Start.
### Story 1.2: Postgres + Drizzle-Schema-Skeleton mit User, Session, AuditEvent
Als **Entwickler**,
ich möchte **eine laufende Postgres-Instanz und das Drizzle-Schema für die drei Fundament-Entitäten**,
sodass **Auth und Audit auf einer realen DB-Schicht funktionieren können**.
**Acceptance Criteria:**
**Given** Docker auf dem Dev-Host,
**When** `docker compose -f docker-compose.dev.yml up postgres` läuft,
**Then** Postgres 16 ist auf Port 5432 erreichbar
**And** `packages/db/schema.ts` definiert die Tabellen `user`, `session`, `audit_event` mit UUID-v7-IDs, snake_case-Spalten und `timestamptz`-Zeitstempeln
**And** `pnpm --filter db migrate:generate` erzeugt eine Migration `0000_init.sql`
**And** `pnpm --filter db migrate` führt sie aus und die drei Tabellen existieren in der DB.
### Story 1.3: Authentik-OIDC-Login-Flow
Als **Mitarbeiter**,
ich möchte **mich via Authentik (SSO) einloggen und nach dem Login automatisch auf der Cockpit-Heimseite landen**,
sodass **ich ohne separate Account-Anlage Zugang zum Cockpit bekomme**.
**Acceptance Criteria:**
**Given** ich öffne `cockpit.tool-ctrl.de` ohne Session,
**When** das Backend mich an `auth.tool-ctrl.de` weiterleitet und ich mich dort erfolgreich einlogge,
**Then** werde ich auf `/puls` zurückgeleitet
**And** ein HttpOnly + SameSite=Lax + Secure Cookie `session_id` ist gesetzt
**And** in der DB existiert eine `session`-Zeile mit `expires_at` 24 h in der Zukunft
**And** in der DB existiert eine `user`-Zeile mit `authentik_sub`, `name`, `email` und (sofern Group-Claim vorhanden) `default_area_id`
**And** ein erneutes Aufrufen jeder geschützten Route innerhalb der Session-Gültigkeit funktioniert ohne erneuten Login
**And** `POST /api/auth/logout` invalidiert die Session in der DB und löscht das Cookie.
### Story 1.4: tRPC-Bootstrap mit `protectedProcedure` und Audit-Wrapper
Als **Entwickler**,
ich möchte **die tRPC-v11-Infrastruktur mit Context, `protectedProcedure` und `withAudit`-Wrapper laufen haben**,
sodass **alle fachlichen Stories direkt typsicher Procedures bauen können**.
**Acceptance Criteria:**
**Given** Story 1.3 ist gemerged,
**When** ein Client `trpc.user.me` ohne Session aufruft,
**Then** liefert das Backend `TRPCError(UNAUTHORIZED)` mit deutscher Message
**And** mit gültiger Session liefert es das `User`-Objekt aus der DB
**And** `withAudit` wrapt jede Mutation und schreibt parallel in `audit_event` in derselben Transaktion (verifiziert via Test)
**And** der Frontend-tRPC-Client in `apps/web/src/lib/trpc.ts` ist konfiguriert mit zentralem `onError`-Toast und nutzt die `AppRouter`-Typdefinition aus `packages/shared`.
### Story 1.5: Brand-Tokens, Tailwind-Theme und Voice-Datei
Als **UI-Entwickler**,
ich möchte **die ToolCTRL-Brand-Tokens als CSS-Variablen und Tailwind-Theme-Erweiterung aktiv haben**,
sodass **alle weiteren UI-Komponenten brand-konform stylebar sind**.
**Acceptance Criteria:**
**Given** Story 1.1 ist mergeable,
**When** ich `apps/web/src/styles/globals.css` lade,
**Then** sind alle Farb-Tokens, Spacing-, Radii- und Schatten-Variablen aus der UX-Spec definiert
**And** `tailwind.config.ts` spiegelt diese Tokens als Theme-Erweiterung
**And** `@fontsource/inter` und `@fontsource/jetbrains-mono` sind installiert und geladen
**And** `apps/web/src/lib/voice.ts` existiert mit allen Mikrocopy-Strings aus UX-Spec § Voice & Tone als exportierte Konstanten
**And** eine Test-Route `/dev/tokens` (nur in `import.meta.env.DEV`) zeigt eine Palette aller Tokens als visuelle Referenz.
### Story 1.6: TopNav-Shell mit Logo, Tabs, Profil-Slot und Keyboard-Shortcuts
Als **Mitarbeiter**,
ich möchte **eine sichtbare, navigierbare Cockpit-Shell mit Brand-Logo, Hauptnavigation und Profil-Bereich**,
sodass **ich die App-Struktur sofort verstehe**.
**Acceptance Criteria:**
**Given** ich bin eingeloggt,
**When** ich `cockpit.tool-ctrl.de` öffne,
**Then** sehe ich oben links `cockpit ^` (KeyCaret-SVG + Lockup) und in der Mitte die TopNav-Tabs `Puls`, `Entwicklung`, `Vertrieb`, `Marketing`, `Mein heute`, `Archiv`
**And** rechts erscheint mein Avatar (Initialen) und ein Streak-Badge-Platzhalter
**And** der aktive Tab zeigt einen 2 px dicken schwarzen Underline
**And** Tastatur-Shortcuts `g p`, `g h`, `g e`, `g v`, `g m`, `g a` springen auf die jeweilige Route
**And** `?` öffnet einen Cheatsheet-Dialog (alle Shortcuts gelistet)
**And** WCAG 2.1 AA wird erfüllt (axe-core-Test grün), Fokus-Ring sichtbar auf jedem Tab.
### Story 1.7: Healthcheck, Docker-Compose und CI-Skeleton
Als **DevOps**,
ich möchte **`docker compose up` startet Web + API + Postgres + Caddy lokal und der Healthcheck antwortet**,
sodass **Deployments und CI auf einer reproduzierbaren Basis aufsetzen können**.
**Acceptance Criteria:**
**Given** `docker-compose.yml` und `Caddyfile` existieren,
**When** `docker compose up -d --build` läuft,
**Then** sind alle vier Container `web`, `api`, `postgres`, `caddy` healthy
**And** `GET /api/health` liefert `200 OK` mit JSON `{ "status": "ok", "db": "ok", "authentik": "ok" }`
**And** `GET /` liefert die SPA-Index (statisch via Caddy)
**And** ein minimales Gitea-Actions-Workflow `ci.yml` läuft Typecheck, Lint und Vitest auf jedem Push.
---
## Epic 2: Tagesrhythmus — Einstempeln, ToDos, Reflexion
Eine Person kann den vollen Tagesrhythmus durchlaufen: morgens einstempeln + ToDos schreiben, abends reflektieren, am nächsten Werktag wird der Eintrag konsolidiert. Das ist die Kern-Erfahrung des Cockpits.
### Story 2.1: DayEntry- und Todo-Schema, AbsenceDay, Werktag-Helper
Als **Entwickler**,
ich möchte **die DB-Tabellen für Tageseinträge, ToDos und Abwesenheiten plus die Werktag-Logik im Backend**,
sodass **die Tagesrhythmus-Procedures auf einer korrekten Datenbasis arbeiten**.
**Acceptance Criteria:**
**Given** Epic 1 ist abgeschlossen,
**When** die Migration `0001_day_rhythm.sql` läuft,
**Then** existieren in der DB die Tabellen `day_entry`, `todo`, `absence_day`, `blocker` gemäß Addendum § 1.2
**And** `apps/api/src/lib/werktag.ts` bietet `isWerktag(date)`, `nextWerktag(date)`, `werktagsDistance(a, b)` mit Mo-Fr-Logik in `Europe/Berlin`
**And** Vitest-Tests decken Grenzfälle ab (Wochenende, Tageswechsel um Mitternacht).
### Story 2.2: Einstempeln + ToDo-Eingabe auf „Mein heute"
Als **Mitarbeiter**,
ich möchte **mich morgens einstempeln und meine ToDos für heute eintippen**,
sodass **mein Tag begonnen ist und ich für Kollegen als „eingestempelt" sichtbar bin**.
**Acceptance Criteria:**
**Given** ich öffne `/mein-heute` als noch nicht eingestempelte Person,
**When** ich auf „Einstempeln" klicke und 3 ToDos eintippe (Enter erzeugt neue Zeile, optionaler Bezug per Inline-Select),
**Then** wird beim Klick auf „Eingestempelt" ein `day_entry` mit `status='begun'` und `checked_in_at` angelegt sowie 3 `todo`-Zeilen
**And** ich werde auf `/puls` weitergeleitet
**And** im „Heute fehlt"-Modul auf dem Puls erscheine ich nicht mehr (Kollegen sehen nur binäre Anwesenheit, nicht die ToDo-Inhalte — vgl. FR-24)
**And** ein „Eingestempelt."-Toast erscheint 2 s in Bottom-Right
**And** der Median-Speed-Test (manuelle Stoppuhr) zeigt ≤ 60 s für 3 ToDos (CM1a).
### Story 2.3: Tagsüber ToDos editieren, „Mein heute" als private Sicht
Als **Mitarbeiter**,
ich möchte **meine ToDos im Verlauf des Tages ergänzen oder ändern können**,
sodass **mein Tagesplan realitätsnah bleibt — und kein Kollege das mitliest, bevor ich reflektiert habe**.
**Acceptance Criteria:**
**Given** ich bin eingestempelt mit 3 ToDos,
**When** ich `/mein-heute` erneut öffne,
**Then** sehe ich meine ToDos editierbar (hinzufügen, ändern, löschen) bis zur Reflexion
**And** Edits werden gespeichert via tRPC-Mutation `todo.update`/`todo.create`/`todo.delete`
**And** ein anderer User, der dieselbe Person als „eingestempelt" sieht, kann **keine** ToDo-Inhalte abrufen (tRPC `dayEntry.todosForUser` liefert für andere User vor `published_at` nur `count`)
**And** die Projekt-P1 darf die ToDos sehen, sofern ein ToDo Bezug auf ihr/sein Projekt hat — verifiziert durch tRPC-Test mit zwei verschiedenen User-Sessions.
### Story 2.4: Abend-Reflexion mit Tagesplan-Echo, Ampel + Trend
Als **Mitarbeiter**,
ich möchte **abends meine ToDos durchgehen, abhaken oder verwerfen, einen Freitext schreiben und Ampel/Trend setzen**,
sodass **mein Tag offiziell als „voll" abgeschlossen gilt und der Status meines Projekts aktuell ist**.
**Acceptance Criteria:**
**Given** ich bin eingestempelt und öffne `/reflexion`,
**When** ich meine ToDos sehe (Tagesplan-Echo mit 200 ms Fade-In) und einige abhake, einige verwerfe (Inline-Grund-Feld) und einen Freitext mit ≤ 1000 Zeichen schreibe,
**Then** kann ich Ampel (🟢/🟡/🔴 als drei große Buttons) und Trend (↗︎/→/↘︎) setzen
**And** Trend ist Pflichtfeld, sofern mindestens ein ToDo Bezug=Projekt hat — Submit ohne Trend zeigt deutsche Inline-Fehlermeldung
**And** Submit setzt `day_entry.status='full'`, `reflected_at`, schreibt `reflection_text`, `ampel`, `trend`
**And** die Ampel + der Trend des verlinkten Projekts werden in derselben DB-Transaktion aktualisiert (`status_cache`, `trend_cache`)
**And** ein „Reflektiert."-Toast erscheint, ich werde auf `/puls` redirected
**And** Reflexion ist 30 min lang editierbar — danach erscheint sie unverändert.
### Story 2.5: Blocker inline in der Reflexion erfassen
Als **Mitarbeiter**,
ich möchte **bei der Reflexion einen Blocker mit einem Toggle eintragen**,
sodass **das Team meine Hindernisse am nächsten Werktagsmorgen sieht**.
**Acceptance Criteria:**
**Given** ich bin in der Reflexion,
**When** ich den „Blocker?"-Toggle aktiviere und Titel + Beschreibung eintippe,
**Then** wird beim Submit zusätzlich ein `blocker`-Datensatz erzeugt
**And** der Blocker ist mit `opened_by = mein User` und (sofern ToDo-Bezug=Projekt) `project_id` verknüpft
**And** der `day_entry.blocker_id` zeigt auf den neuen Blocker
**And** der Blocker erscheint **erst nach Publikation am nächsten Werktag** im bereichsübergreifenden Blocker-Modul des Puls (Verifizierung mit zweiter Session).
### Story 2.6: Cron „publish-day-entries" + Streak-Berechnung
Als **System**,
möchte ich **nachts um 00:05 Europe/Berlin die DayEntries des Vortags publizieren und Streaks neu berechnen**,
sodass **am Morgen X+1 die konsolidierten Vortrags-Einträge sichtbar werden und Streaks korrekt sind**.
**Acceptance Criteria:**
**Given** mehrere User haben am Vortag eingestempelt + reflektiert,
**When** der System-Cron `POST /internal/cron/publish-day-entries` mit Bearer-Token aufruft,
**Then** werden alle `day_entry`-Zeilen des Vortags mit `published_at = heute 00:00` versehen
**And** die nachfolgende tRPC-Procedure `dayEntry.feedForArea` liefert diese Einträge inklusive ToDos + Reflexion für alle Kollegen
**And** ein zweiter Cron-Aufruf `recompute-streaks` setzt `user.current_streak` korrekt (vollständige + halbe + abwesende Tage gemäß FR-33/34)
**And** Cron-Aufrufe ohne korrekten Bearer-Token liefern `401`.
### Story 2.7: Streak-Badge, Abwesenheit, „Halb"-Status
Als **Mitarbeiter**,
ich möchte **meine aktuelle Streak in der TopNav sehen und mich für Tage als abwesend markieren können**,
sodass **Urlaubstage nicht meine Streak brechen**.
**Acceptance Criteria:**
**Given** ich bin eingeloggt,
**When** ich die TopNav betrachte,
**Then** sehe ich rechts neben meinem Avatar einen Pill „N ^" (N = aktuelle Streak, KeyCaret als Suffix)
**And** ich kann via Profil-Modal einen Zeitraum als „abwesend" (Urlaub/Krank/Sonstiges) markieren
**And** Abwesenheits-Tage werden als `absence_day` gespeichert und im Streak-Cron als „nicht gegen die Serie zählend" behandelt
**And** wenn ich morgens nur einstempele aber nicht reflektiere, zeigt `dayEntry.todayStatus` für mich `status='begun'` und mein Tages-Status-Indikator wird gelb („halb")
**And** der nächste Streak-Cron würde diesen Tag nicht für die Serie zählen (verifiziert via Unit-Test in `werktag.ts`).
---
## Epic 3: Puls & Bereichs-Übersicht
Eine Person öffnet das Cockpit und sieht in unter 60 Sekunden alles Wesentliche: drei Bereiche mit Ampel-Aggregat, Heute-Quote, Blocker, Jourfixe-Hinweis, Vortrags-Feed.
### Story 3.1: Area-Schema, Aggregations-Algorithmus, Puls-Procedure
Als **Entwickler**,
ich möchte **die `area`-Tabelle und die `apps/api/src/lib/ampel.ts`-Aggregations-Logik plus eine tRPC-Procedure `puls.overview`**,
sodass **die Puls-Frontend-Seite alle Aggregat-Daten in einem Roundtrip bekommt**.
**Acceptance Criteria:**
**Given** die DB enthält drei `area`-Zeilen (dev, sales, marketing) und (zunächst leere) Projekt-Tabelle,
**When** `trpc.puls.overview` ohne Filter aufgerufen wird,
**Then** liefert es ein Objekt mit `areas: [{ id, name, ampel, ampel_count, missing_today_count }]`, `blockers: [...]`, `heuteQuote: { gepingt, gesamt, fehlende: [...] }`, `jourfixe: { nextDate, label }`
**And** die Ampel-Aggregation pro Bereich folgt FR-1a-Algorithmus (verifiziert via Vitest-Test mit Fixtures aus mehreren Status-Kombinationen)
**And** die Procedure liefert in < 200 ms bei 6-15 Usern und 90 Tagen Historie (Performance-Test mit `vitest --bench`).
### Story 3.2: Puls-Seite Layout mit Bereichs-Strip und Heute-Quote
Als **Mitarbeiter**,
ich möchte **auf `/puls` in einem Blick die drei Bereiche mit Ampelstatus und die Heute-Quote sehen**,
sodass **ich morgens innerhalb 60 s einen Überblick habe**.
**Acceptance Criteria:**
**Given** ich öffne `/puls`,
**When** die Seite geladen hat,
**Then** sehe ich oben einen Hero mit „Stand: Di, 25. Mai 2026"
**And** unter dem Hero ein 3-Spalten-Grid mit den drei Bereichen, jeweils mit AmpelBadge, Bereichsname, Anzahl fehlender Updates heute, und einer Klick-Aktion zur Bereichs-Detail-View
**And** rechts (oder darunter auf Tablet) ein „Heute fehlt"-Modul mit `X/Y eingestempelt`-Stat und Klick auf Detail-Liste der fehlenden Personen (mit Avatar + Name)
**And** wenn ich noch nicht eingestempelt bin, erscheint prominent oberhalb des Folds der CTA „Du hast heute noch nicht gepingt." mit „Einstempeln"-Primary-Button → führt zu `/mein-heute`
**And** Skeleton-Cards beim Initial-Load, Fade-In ≤ 200 ms beim Datenanstieg.
### Story 3.3: Blocker-Modul, Jourfixe-Hinweis, KPI-Slots
Als **Mitarbeiter**,
ich möchte **auf `/puls` die offenen Blocker, den nächsten Jourfixe und KPI-Slots pro Bereich sehen**,
sodass **ich den ganzen Unternehmens-Puls auf einer Seite verstehe**.
**Acceptance Criteria:**
**Given** ich öffne `/puls`,
**When** die Seite vollständig geladen ist,
**Then** sehe ich unter dem Bereichs-Strip ein Modul „Bereichsübergreifend offen" mit allen offenen Blockern sortiert nach Alter
**And** ein Modul „Jourfixe" zeigt den nächsten Termin (Default „Di, 11:00")
**And** pro Bereich erscheint eine KPI-Kachel mit Slots aus FR-5 (Anzahl Projekte, Status-Verteilung etc.) — Werte sind in Epic 3 ggf. noch 0 (echte Daten kommen in Epic 4)
**And** das Modul „Pflicht-Minimum" ist als Slot vorhanden, zeigt aber bis Epic 5 nur „Keine Projekte mit unerfülltem Pflicht-Minimum" als Empty-State.
### Story 3.4: Vortrags-Feed im Puls + „Heute fehlt"-Detail
Als **Mitarbeiter**,
ich möchte **am Morgen X+1 die konsolidierten Vortrags-Einträge meiner Kollegen im Feed sehen**,
sodass **ich weiß, was gestern lief**.
**Acceptance Criteria:**
**Given** am Tag X haben N Personen reflektiert und der Publikations-Cron lief um 00:05,
**When** ich am Tag X+1 morgens `/puls` öffne,
**Then** sehe ich unten einen „Gestern im Team"-Feed mit konsolidierten DayEntries (Avatar + Name + Bereich + Ampel + Trend + Reflexionstext + abgehakte/verworfene ToDos)
**And** der Feed sortiert neueste oben, paginiert 50/Seite mit „Mehr laden"
**And** Klick auf einen Eintrag öffnet die Detail-Sicht (read-only)
**And** das „Heute fehlt"-Modul klickt jetzt auf eine vollständige Liste der heute noch nicht eingestempelten Personen
**And** Performance-Budget < 1,5 s gesamtladezeit auf `/puls` mit 90 Tagen Historie (Lighthouse-Test).
---
## Epic 4: Projekte, Deals, Kampagnen — Bereichs-Details
Eine Person kann Projekte, Deals und Kampagnen anlegen und in den jeweiligen Bereichs-Detail-Views arbeiten. Die KPI-Slots im Puls werden mit Echtdaten gefüllt.
### Story 4.1: Project-, Milestone- und Verlinkungs-Schema, Anlage-Modal
Als **Projektverantwortliche/r (P1)**,
ich möchte **ein Projekt im Cockpit anlegen können mit allen Cockpit-Sicht-Feldern und Pflicht-Verlinkungen**,
sodass **das Projekt im Puls und in der Bereichs-Detail-View erscheint**.
**Acceptance Criteria:**
**Given** ich bin eingeloggt und in der Bereichs-Detail-View Entwicklung,
**When** ich auf „+ Neues Projekt" klicke,
**Then** öffnet sich ein Dialog mit den Pflichtfeldern Name, Verantwortliche/r (P1, User-Auswahl), Projektart (Kundenprojekt/Internes Projekt), Arbeitsmodus (Cycle/Kanban), Outline-Steckbrief-URL, Plane-Board-URL
**And** optional DoD-Text, Risikoliste-URL, Start, Deadline und 0..N grobe Meilensteine inline
**And** beim Submit werden `project`- und `milestone`-Zeilen geschrieben (Migration `0002_projects.sql`), audit-getracked
**And** das neue Projekt erscheint sofort im Bereich Entwicklung (FR-8/9) und im Puls-KPI-Slot.
### Story 4.2: Bereichs-Detail Entwicklung mit Projekt-Karten und Detail-View
Als **Mitarbeiter**,
ich möchte **die Liste aller Entwicklungs-Projekte in zwei Gruppen (Kundenprojekt/Internes Projekt) sehen und in die Detail-Sicht klicken**,
sodass **ich Status, Meilensteine und letzte Updates pro Projekt erfasse**.
**Acceptance Criteria:**
**Given** mindestens 2 Projekte (eines Kundenprojekt, eines internes) existieren,
**When** ich `/bereich/entwicklung` öffne,
**Then** sehe ich zwei Sektionen „Kundenprojekte" und „Interne Projekte" mit Projekt-Cards (Name, P1-Avatar, AmpelBadge + Trend, Deadline-Progress-Bar, # offene Meilensteine, Pflicht-Minimum-Score Slot)
**And** Klick auf Projekt-Card öffnet `/projekt/:id` mit der Detail-Sicht: Kopfzeile (Name, P1, Projektart, Arbeitsmodus, Ampel + Trend), Verlinkungen (Outline-Steckbrief, Plane-Board, optional Risikoliste), optional DoD-Text, Meilenstein-Checkliste, Update-Feed dieses Projekts
**And** Meilensteine sind inline editierbar (Status: offen/erledigt/überzogen, Fälligkeit ändern) und werden in der Cockpit-DB persistiert.
### Story 4.3: Deal-Schema, Sales-Kanban und Pipeline-KPIs
Als **Vertrieb**,
ich möchte **meine Deals als Kanban in 5 Stages sehen und per Drag-and-Drop verschieben**,
sodass **die Pipeline immer aktuell ist**.
**Acceptance Criteria:**
**Given** Migration `0003_sales.sql` ist gelaufen und mind. 3 Deals existieren,
**When** ich `/bereich/vertrieb` öffne,
**Then** sehe ich oben das KPI-Header-Modul mit gewichtetem Pipeline-Wert (Σ value × probability), aktiven Deals-Count, gewonnenen Deals des laufenden Quartals (# + EUR formatiert als `12.500,00 €`), ⌀ Stage-Verweildauer
**And** darunter ein 5-Spalten-Kanban (Lead → Erstgespräch → Demo → Angebot → Abschluss) mit Deal-Karten
**And** Drag-and-Drop einer Karte auf eine andere Spalte ändert `deal.stage` und setzt `entered_stage_at = now()` (optimistic UI + Rollback bei Fehler)
**And** unten ein gefilterter Vertrieb-Update-Feed (Bezug=Deal oder Vertrieb-allgemein).
### Story 4.4: GTM-Schritte und Vertrieb-Feed
Als **Vertrieb**,
ich möchte **pro Produkt eine sortierbare GTM-Schritt-Liste pflegen**,
sodass **die Markteinführung jedes Produkts strukturiert ist**.
**Acceptance Criteria:**
**Given** im Vertriebs-Detail existiert ein Bereich „GTM-Schritte pro Produkt",
**When** ich ein neues Produkt-Tab hinzufüge und Schritte (Titel + Verantwortlicher + Status) einpflege,
**Then** wird `gtm_step` in der DB persistiert mit `order`-Feld für die Reihenfolge
**And** Schritte sind per Drag-and-Drop oder Up/Down-Tastatur-Buttons umsortierbar (`order` wird neu vergeben in einer Transaktion)
**And** der Status (offen/in Arbeit/erledigt) ist inline änderbar.
### Story 4.5: Campaign-Schema, Lead-Funnel und Crosslink-Banner
Als **Marketing**,
ich möchte **den Lead-Funnel mit Conversion-Prozenten und die Kampagnen-Liste sehen, plus einen Crosslink-Banner zur Vertriebs-Übergabe**,
sodass **ich verstehe, wie viele Leads in echte Deals umgewandelt werden**.
**Acceptance Criteria:**
**Given** Migration `0004_marketing.sql` ist gelaufen und `lead_handover` enthält Daten,
**When** ich `/bereich/marketing` öffne,
**Then** sehe ich oben einen horizontalen 5-Stufen-Lead-Funnel (Reichweite → Website → Leads → MQL → Übergabe) mit Conversion-% zwischen den Stufen
**And** darunter eine Liste aktiver Kampagnen (Aktiv/Pausiert/Beendet, Reichweite, Verantwortlicher)
**And** ein Crosslink-Banner zeigt „Marketing hat X Leads übergeben in [letzten 30 Tagen], Vertrieb hat daraus Y Deals erzeugt (Z € im Quartal)"
**And** derselbe Banner spiegelt sich umgekehrt im Vertrieb-Detail (FR-19)
**And** unten ein gefilterter Marketing-Update-Feed.
---
## Epic 5: Pflicht-Minimum & Blocker
Die 6 Leitfaden-Pflicht-Punkte pro Projekt werden sichtbar gemacht. Blocker-Lebenszyklus ist komplett — inkl. der Regel „nur P1 darf auflösen".
### Story 5.1: Pflicht-Minimum-State, Lazy-Berechnung und Cron-Punkt-5
Als **Entwickler**,
ich möchte **die Pflicht-Minimum-Logik im Backend mit der korrekten Punkt-5-Aktualisierung**,
sodass **der Status pro Projekt stets korrekt aus den Daten abgeleitet wird**.
**Acceptance Criteria:**
**Given** Migration `0005_pflicht_minimum.sql` ergänzt `project.pflicht_minimum_state` (JSONB) und `project.steckbrief_freigegeben` (bool),
**When** `apps/api/src/lib/pflicht-minimum.ts` `computePflichtMinimum(projectId)` aufgerufen wird,
**Then** liefert es ein Objekt mit 6 Booleans gemäß FR-38 Definition (Punkte 1-4 manuell aus DB-Feldern, Punkt 5 berechnet aus letztem Reflexions-Zeitstempel)
**And** der Cron-Endpoint `POST /internal/cron/recompute-pflicht-minimum-5` setzt Punkt 5 auf `false` für alle Projekte mit letzter Reflexion > 7 Werktage zurück
**And** der Aggregations-Algorithmus aus FR-1a wird ergänzt: Pflicht-Minimum-Verstöße heben Ampel mindestens auf Gelb (Vitest-Test mit Fixtures).
### Story 5.2: Pflicht-Minimum-Indikator und -Panel in der UI
Als **P1 / P4**,
ich möchte **pro Projekt-Card und Projekt-Detail die 6 Pflicht-Punkte als visuelle Indikatoren sehen**,
sodass **ich sofort sehe, was bei diesem Projekt fehlt**.
**Acceptance Criteria:**
**Given** Stories 5.1 ist abgeschlossen und ein Projekt hat 4/6 Punkte erfüllt,
**When** ich `/bereich/entwicklung` öffne,
**Then** zeigt jede Projekt-Card unten rechts den `PflichtMinimumIndicator` mit 6 horizontalen Quadraten (gefüllt/leer) und Score „4/6"
**And** auf `/projekt/:id` erscheint das `PflichtMinimumPanel` mit allen 6 Punkten als Checkliste, jeweils mit Status, kurzer Beschreibung und (für Punkte 1-4) Quick-Action-Button („Steckbrief verlinken", „P1 setzen", „Plane-Board verlinken", „Meilenstein anlegen")
**And** Punkte 5 und 6 sind read-only mit Erklärungs-Tooltip
**And** Projekte mit ≥ 1 unerfülltem Punkt erscheinen auf `/puls` im Modul „Pflicht-Minimum" (vorher leerer Slot wird gefüllt).
### Story 5.3: Blocker-Lebenszyklus — Erfassen, Anzeige, P1-Auflösung
Als **Mitarbeiter**,
ich möchte **Blocker außerhalb der Reflexion erfassen können und P1 kann sie auflösen**,
sodass **das Team auf bereichsübergreifende Hindernisse reagieren kann**.
**Acceptance Criteria:**
**Given** der „+ Neuer Blocker"-Button in der TopNav (Shortcut `n`),
**When** ich auf ihn klicke und Titel + Beschreibung + Verantwortlichen + Bereich(e) + optionale Projekt-Verknüpfung eintrage,
**Then** wird `blocker` in der DB persistiert mit `opened_by = ich`
**And** der Blocker erscheint auf `/puls` im bereichsübergreifenden Modul, im jeweiligen Bereichs-Detail und (sofern projektgebunden) im Projekt-Detail
**And** auf der Blocker-Card erscheint ein „Auflösen"-Button **nur sichtbar, wenn ich P1 des bezogenen Projekts bin** (oder bei projektlosen Blockern Ersteller oder Verantwortlicher)
**And** ein nicht-P1-User, der versucht via direktem tRPC-Call aufzulösen, bekommt `TRPCError(FORBIDDEN)` mit deutscher Message
**And** beim Auflösen werden `resolved_by`, `resolved_at` und `resolution_text` persistiert; Blocker verschwindet aus den offenen Listen.
### Story 5.4: Blocker im Projekt-Detail und Audit der Auflösung
Als **P1 / P4**,
ich möchte **die Blocker-Historie pro Projekt einsehen können**,
sodass **ich nachvollziehe, was und wann gelöst wurde**.
**Acceptance Criteria:**
**Given** ein Projekt hat mehrere Blocker (einige offen, einige gelöst),
**When** ich `/projekt/:id` öffne,
**Then** sehe ich einen Tab oder Bereich „Blocker" mit zwei Listen: offene Blocker oben (mit „Auflösen"-Button für P1), gelöste Blocker darunter (mit Auflöser-Name + Datum + Kommentar)
**And** jede Blocker-Mutation (erstellen, lösen) hat einen entsprechenden `audit_event`-Eintrag (verifiziert per DB-Query in Test).
---
## Epic 6: Projekt-Abschluss, Archiv & Production
Projekte können abgeschlossen werden inkl. Lessons-Learned-Pflicht. Archiv-Sicht existiert. Production-Pipeline ist scharf: CI/CD, Backup, A11y-Tests.
### Story 6.1: Projekt-Abschluss-Workflow und Lessons-Learned-Pflicht
Als **P1**,
ich möchte **ein Projekt auf „abgeschlossen" setzen können — aber nur, wenn ich die Lessons-Learned-URL angegeben habe**,
sodass **die Leitfaden-Pflicht-Minimum-Position 6 garantiert erfüllt wird**.
**Acceptance Criteria:**
**Given** ich bin P1 eines aktiven Projekts und öffne den Projekt-Header,
**When** ich auf „Projekt abschließen" klicke,
**Then** öffnet sich ein Dialog, der die Lessons-Learned-URL als Pflichtfeld einfordert (URL-Format-Validierung via Zod)
**And** beim Submit wird `project.archiviert=true`, `archiviert_am=now()`, `lessons_learned_url` gesetzt und `pflicht_minimum_state.6=true` neu berechnet
**And** das Projekt verschwindet sofort aus `/bereich/entwicklung` und `/puls`
**And** Try-To-Submit ohne URL zeigt deutsche Inline-Fehlermeldung
**And** ein nicht-P1-User sieht den „Abschließen"-Button nicht (UI + tRPC-Guard).
### Story 6.2: Archiv-Sicht pro Bereich
Als **Mitarbeiter**,
ich möchte **abgeschlossene Projekte in einer Archiv-Sicht einsehen**,
sodass **vergangene Erkenntnisse auffindbar bleiben**.
**Acceptance Criteria:**
**Given** mindestens 2 Projekte sind abgeschlossen,
**When** ich `/archiv` öffne (oder via TopNav-Tab),
**Then** sehe ich pro Bereich (Tabs Entwicklung/Vertrieb/Marketing) eine Liste abgeschlossener Items sortiert nach `archiviert_am` (neueste oben)
**And** Klick auf ein Item öffnet die read-only Detail-Sicht mit allen Daten + Lessons-Learned-Link
**And** die Archiv-Sicht hat denselben Sub-Header wie die Bereichs-Detail-Views (Sticky), aber mit zusätzlichem „Archiv"-Marker.
### Story 6.3: Backup-Cron, Restore-Drill-Dokumentation
Als **DevOps**,
ich möchte **ein tägliches `pg_dump`-Backup mit 14-Tage-Retention und dokumentiertem Restore-Pfad**,
sodass **Datenverlust auch nach einem schweren Vorfall begrenzt bleibt**.
**Acceptance Criteria:**
**Given** der Cron-Endpoint `POST /internal/cron/pg-dump-backup` ist implementiert,
**When** die System-Cron-Definition den Endpoint täglich 02:00 aufruft,
**Then** wird ein gz-komprimiertes Dump-File auf einem separaten Docker-Volume `backups` geschrieben
**And** Dumps älter als 14 Tage werden automatisch gelöscht
**And** `docs/operations.md` enthält eine Restore-Anleitung in 5 Schritten (Stop API, Restore Dump, Migrate, Smoke-Test, Start API)
**And** ein quartalsweiser Restore-Drill ist als Issue im Plane geöffnet (Story-Akzeptanz prüft, dass die Aufgabe dokumentiert ist, nicht den Drill selbst).
### Story 6.4: CI-Pipeline mit Vitest, Playwright und Lighthouse-A11y
Als **Entwickler**,
ich möchte **eine CI-Pipeline, die Typecheck, Lint, Vitest, Playwright und Lighthouse-A11y-Test bei jedem PR ausführt**,
sodass **Qualität und Barrierefreiheit nicht erodieren**.
**Acceptance Criteria:**
**Given** `.gitea/workflows/ci.yml` erweitert die Pipeline,
**When** ein PR geöffnet wird,
**Then** läuft die Pipeline `pnpm install` → `pnpm typecheck` → `pnpm lint` → `pnpm test` (Vitest mit axe-core auf Komponenten-Snapshots) → `pnpm build` → Playwright-E2E auf den drei UJs (UJ-1, UJ-2, UJ-5) gegen eine ephemere Docker-Compose-Umgebung → Lighthouse-CI auf `/puls`, `/mein-heute`, `/projekt/:id`
**And** Lighthouse-A11y-Score < 95 lässt die Pipeline fehlschlagen
**And** jeder PR-Check zeigt einen Statusbericht mit den erfüllten/gefehlten Punkten.
### Story 6.5: Responsive-Audit und Mobile-Lesbarkeit
Als **Mitarbeiter**,
ich möchte **das Cockpit auch unterwegs am Handy lesen können** (nicht schreiben — das bleibt Desktop),
sodass **ich beim Pendeln zumindest sehe, wie es um die Projekte steht**.
**Acceptance Criteria:**
**Given** ich öffne `/puls` und `/projekt/:id` auf einem mobilen Browser (Viewport 375×667),
**When** die Seiten geladen sind,
**Then** sind alle Karten und Listen leserlich gestapelt (Single-Column), keine horizontalen Scrolls
**And** die TopNav wird zu einer Bottom-Tab-Bar mit 4 Items (Puls, Mein heute, Bereiche-Dropdown, Profil)
**And** der Einstempel-CTA auf `/mein-heute` zeigt einen sichtbaren Hinweis „Tagesupdate auf Desktop empfohlen" (Voice-konform)
**And** Playwright-Mobile-Viewport-Tests laufen für `/puls` und `/projekt/:id` und prüfen Layout-Integrität.
---
## Validation Summary
### FR Coverage Check
| FR | Story | Status |
|---|---|---|
| FR-1, 1a, 2-7 | 3.1-3.4 | ✅ |
| FR-8-11 | 4.1, 4.2 | ✅ |
| FR-12-16 | 4.3, 4.4 | ✅ |
| FR-17-20 | 4.5 | ✅ |
| FR-21-25 | 2.2, 2.3 | ✅ |
| FR-26-28, 31 | 2.4 | ✅ |
| FR-29, 30 | 2.6, 3.4 | ✅ |
| FR-32, 33 | 2.2, 2.4, 2.7 | ✅ |
| FR-34-37 | 2.7 | ✅ |
| FR-38-40 | 5.1, 5.2 | ✅ |
| FR-41-44 | 2.5, 5.3, 5.4 | ✅ |
| FR-45-47 | 6.1, 6.2 | ✅ |
| FR-48 | 1.6 | ✅ |
| FR-49 | — | ⏭ Phase 2 (explizit) |
**Coverage:** 48 von 49 FRs durch Stories abgedeckt; FR-49 (Volltextsuche) bewusst Phase 2 gemäß PRD § 8.
### NFR Coverage Check
- **Performance (NFR-1, 2):** 3.1 (Procedure-Budget), 3.4 (Lighthouse), 6.4 (CI-Performance-Gate)
- **Verfügbarkeit (NFR-3, 4):** 6.3 (Backup + Restore-Drill), 1.7 (Healthcheck)
- **Security (NFR-5, 6, 7):** 1.3 (Authentik), 1.4 (Audit-Wrapper)
- **Bedienbarkeit (NFR-8-10):** 1.5 (Brand-Tokens), 6.5 (Mobile-Audit)
- **Voice & Tone (NFR-11, 12, 13):** 1.5 (voice.ts) — alle UI-Stories nutzen die zentrale Datei
- **Daten (NFR-14, 15, 16):** 1.2 (Postgres+Drizzle), 6.3 (Backup), 1.1 (Drizzle-Migrationen)
### Story-Quality-Validation
- ✅ **Sized for single dev agent:** keine Story > 1 Arbeitstag in der KI-gestützten Entwicklung.
- ✅ **Given/When/Then-Format** auf jeder AK.
- ✅ **Keine Vorwärts-Abhängigkeiten** — jede Story baut auf vorherigen Stories (gleicher Epic) oder bereits abgeschlossenen Epics auf.
- ✅ **Inkrementelles Schema:** DB-Migrationen entstehen je Story-Bedarf, nicht upfront. (`0000_init`, `0001_day_rhythm` inkl. blocker, `0002_projects`, `0003_sales`, `0004_marketing`, `0005_pflicht_minimum`.)
- ✅ **Custom-Starter** ist Story 1.1 (Repo-Bootstrap), entspricht Architektur § Initialization Commands.
### Epic-Independence-Check
| Epic | Depends on | Liefert |
|---|---|---|
| 1 | — | Login + Shell + Brand |
| 2 | 1 | Tagesrhythmus inkl. Cron + Streak |
| 3 | 1, 2 | Puls-Übersicht mit Vortrags-Feed |
| 4 | 1 (unabhängig von 2/3 möglich) | Projekt-/Deal-/Kampagnen-Domain |
| 5 | 4 (Projekte) + 2 (Blocker-Inline) | Pflicht-Minimum + Blocker-Lifecycle |
| 6 | 4 (Archiv), 2 (Cron-Pattern) | Abschluss + Production-Pipeline |
✅ Jedes Epic liefert eigenständig nutzbaren Wert.
### File-Churn-Check
- Epic 2 und Epic 5 berühren beide `blocker`-Schema und -Komponente — bewusst getrennt: Epic 2 etabliert nur Inline-Erfassung in der Reflexion, Epic 5 fügt vollständigen Lifecycle (Standalone-Button + P1-Auflösung + Audit-Tab) hinzu. Aufteilung mitigiert Risiko, dass das volle Blocker-System verzögert wird, bevor der Tagesrhythmus läuft.
- Epic 3 und Epic 4 berühren beide `apps/api/src/routers/puls.ts` und KPI-Slots im Frontend — getrennt, weil Epic 3 die Aggregation für leere Bereiche etabliert (skelettiert) und Epic 4 die Domain-Daten dahinter liefert. Konsolidierung hätte ein zu großes Epic ohne Zwischen-Release-Wert ergeben.
### UX-DR-Coverage-Spot-Check
- UX-DR1-4 (Brand-Tokens, Typo, Spacing, Container) → Story 1.5
- UX-DR5-7 (Button, Card, Input, Textarea, Select, Checkbox) → Story 1.5 + 1.6 (verteilt, je nach Bedarf in Folge-Stories)
- UX-DR8 (AmpelButton, TrendButton) → Story 2.4
- UX-DR9 (Dialog, Tooltip) → Story 4.1 + 6.1
- UX-DR10 (SkeletonCard) → Story 3.2
- UX-DR11 (AmpelBadge) → Story 3.2 / 4.2
- UX-DR12 (PflichtMinimumIndicator) → Story 5.2
- UX-DR13 (KeyCaret) → Story 1.6 + 2.7
- UX-DR14-16 (Navigation, Breadcrumbs, Shortcuts) → Story 1.6
- UX-DR17 (voice.ts) → Story 1.5
- UX-DR18-20 (User Journeys) → Stories 2.2/2.4, 3.2, 4.1
- UX-DR21-25 (Responsive + A11y) → Story 6.4 + 6.5
- UX-DR26-30 (Interaktions-Patterns) → verteilt über alle UI-Stories
✅ Alle 30 UX-DRs sind in Stories adressiert.
### Validation Verdict
**🟢 READY FOR DEVELOPMENT**
- 49 FRs · 16 NFRs · 16 AR-Items · 30 UX-DRs → durch 6 Epics und 32 Stories abgedeckt
- Keine Vorwärts-Abhängigkeiten, keine Upfront-Big-Bang-Migrationen
- Epic-Reihenfolge entspricht der Architektur-Implementation-Sequence
- Bauen kann mit **Story 1.1 (Repo-Bootstrap)** sofort starten.