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>
56 KiB
stepsCompleted, status, completedAt, inputDocuments, workflowType, project_name, user_name, date
| stepsCompleted | status | completedAt | inputDocuments | workflowType | project_name | user_name | date | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
complete | 2026-05-25 |
|
epics-and-stories | ToolCTRL Unternehmens-Cockpit | Dejancosic | 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:
- Projektsteckbrief in Outline freigegeben → erfüllt wenn
outline_steckbrief_urlgepflegt UND als „freigegeben" markiert. - P1 gesetzt.
- Plane-Board mit zerlegter Arbeit → erfüllt wenn
plane_project_urlgepflegt. - Meilensteine mit groben Terminen → erfüllt wenn ≥ 1 Meilenstein.
- Status-Ampel aktuell → erfüllt wenn letzte Reflexion mit Projektbezug ≤ 7 Werktage alt.
- Abschluss-Retrospektive (nur bei beendeten Projekten).
- Projektsteckbrief in Outline freigegeben → erfüllt wenn
- 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.tsmit 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-clientv6+ 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/postpublished_at),projectOwnerProcedure(P1-Check). - AR-5 Audit-Middleware (
withAudit) um jede schreibende tRPC-Mutation, schreibt parallel inaudit_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-servedapps/web/dist),api-Container (Node 22+),postgres:16-Container,caddy-Container als Reverse-Proxy aufcockpit.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.mdim Repo-Root (spiegelt Architektur §Implementation Patterns), Pflicht-Lesen vor Story-Bearbeitung. - AR-16 Backup-Strategie:
pg_dumptäglich auf separates Volume, Retention 14 Tage. Restore-Drill quartalsweise dokumentiert indocs/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.cssdefinieren und intailwind.config.tsals 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/interund@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
Buttonmit 3 Varianten (primary/secondary/ghost) + Destructive + Icon-Only, 3 Größen (sm/md/lg). - UX-DR6
Cardmit 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 undradius-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.tsmit 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/playwrightfür E2E. ESlint-jsx-a11ymitrecommendedaktiviert.
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_rhythminkl. 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.tsund 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.