Projekt-Dashboard v3 — Implementations-Plan

Overview

Statisches Operations-Dashboard unter dashboard.agenticventures.de. Next.js 16 + Tailwind v4 + Recharts (Repo: av-cockpit). Server Components lesen Vault-Markdown direkt via gray-matter. Static Export nach S3 + CloudFront. Geist Sans/Mono, Vercel/Stripe-Aesthetik (monochrom, shadow-as-border, Akzent 533afd).

Pivot von v2: Lambda + EventBridge + S3-Daten-Bucket sind raus. Stattdessen Build-Time-Scripts + Snapshot-Files im Vault. Cognito + S3 + CloudFront bleiben (Frontend-Hosting only).

Pivot von v3-Astro zu av-cockpit (2026-05-16): Astro 5 (av-dashboard) ersetzt durch Next.js 16 (av-cockpit). Begruendung: Server Components + gray-matter ist simpler als Astro Content Collections fuer Vault-Reads. Recharts direkt statt shadcn-charts-Wrapper. Geist-Fonts statt Inter/JetBrains Mono. Bestehende Pages: /heute, /projekte, /cloud, /finanzen, /routinen.

Requirements Trace

Trace zu _index.md v3 — Anchor-IDs sind die R*-Marker:

  • R1-R7 Daten-Quellen → Phase 1 (Foundation) + Phase 4 (Backfill)
  • R8-R12 Frontend/Tech → Phase 2 (Design-System) + Phase 3 (Charts)
  • R13-R15 Customization → Phase 5
  • R16 Routing → Phase 2 + Phase 3
  • R17-R20 /heute v3 vier Bloecke → Phase 2 (Mock) + Phase 3 (Live-Daten)
  • R21-R23 Auth/Hosting → Phase 6

Scope Boundaries

Siehe _index.md §Scope Boundaries. Hier nur Plan-Ebene:

  • Plan deckt MVP-Live unter dashboard.agenticventures.de ab. Activity-Stream /runs, Observable-Plot-Visualisierungen und Drag-and-Drop sind explizit Phase-Out und nicht in diesem Plan.
  • Backfill ist on-demand-Skript, kein Cron. Plan beschreibt das Skript, nicht eine Automatik.

Context & Research

Relevant Code

  • ~/source/av-cockpit/Aktives Repo. Next.js 16 + Tailwind v4 + Recharts. 5 Pages live: /heute, /projekte (Kanban), /cloud (AWS-Kosten + 7d-Trend), /finanzen, /routinen. Vault-Bridge in src/lib/vault.ts (gray-matter + fs). Deploy via scripts/deploy.sh (S3 sync + CloudFront invalidation).
  • ~/source/av-cockpit/src/lib/vault.ts — Vault-Bridge: liest intern/projekte/*/_index.md + intern/kunden/*.md via gray-matter, typesafe Types (ProjectCard, Customer, Task), Filter-Helpers (isActiveProject, getMyTasks, getWaitingProjects).
  • ~/source/av-cockpit/src/app/cloud/page.tsx — Cloud-Kosten-Page mit Recharts Area-Chart, Kundenabrechnung, Service-Breakdown. Nutzt SWR + /api/data/aws-costs.json.
  • ~/source/av-dashboard/Vorgaenger (Astro 5). Archiviert, nicht mehr aktiv entwickelt. Liegt noch als Referenz fuer Design-Tokens (ink-Palette, MetricCard-Pattern).
  • ~/source/agents-platform/lambdas/dashboard-refresh/ — v2-Lambda, wird NICHT geloescht (steht als Referenz). Keine Dependency aus v3/v4 darauf.

Relevant Vault-Quellen

  • beleg-quellen.md — Gmail-Label-Konvention + Sender-Pattern fuer Kategorisierung
  • web-properties.md — Cloudflare-DNS-Convention fuer den Subdomain-Cutover
  • _index.md — av-mgmt-Account + Cross-Account-Cost-Aggregation
  • gsuite.md — Gmail-Pull fuer Belege im Backfill-Script

Institutional Learnings

  • ADHS-Pattern — System unsichtbar, nur das Relevante zeigen. /heute hat 4 Bloecke, nicht 10. Mehr Karten = weniger Klarheit.
  • AWS-First Hosting — S3 + CloudFront im av-production-Account, kein Vercel/Cloudflare-Pages-Alternative.
  • Schreibstil — Deutsche Umgangssprache in UI-Texten, keine em-dashes, ganze Saetze.
  • [2026-05-16] Astro → Next.js Pivot — Astro Content Collections waren Over-Engineering fuer den Use-Case. gray-matter + fs in Next.js Server Components ist direkter und braucht keine Symlinks/Loader-Hacks fuer Vault-Pfade ausserhalb des Repos.

External References

Phasen-Overview

flowchart LR
    P0[Phase 0\nCleanup + Foundation] --> P1[Phase 1\nContent Collections\n+ Zod-Schemas]
    P1 --> P2[Phase 2\nDesign-System\n+ Mock /heute v3]
    P2 --> P3[Phase 3\nshadcn-charts\n+ Live-Daten]
    P3 --> P4[Phase 4\nBackfill-Scripts\nFinanzen + Cloud]
    P4 --> P5[Phase 5\nCustomization\nSaved Views + localStorage]
    P5 --> P6[Phase 6\nDeploy\nS3 + CloudFront + Cognito]

Zeitlich grob: P0-P3 = MVP-Live (Sprint 1, ~3-5 Tage), P4-P5 = Komfort (Sprint 2), P6 = Production-Cutover (1 Tag wenn AWS-Vorarbeit aus Runbook v2 nutzbar).


Phase 0 — Cleanup + Foundation

Goal: Bestand inventarisieren, v2-Reste sauber abklemmen, av-dashboard auf den v3-Ready-Zustand bringen ohne Funktionalitaet zu verlieren.

Unit 0.1 — v2-Lambda-Code als Referenz-Frieren

  • ~/source/agents-platform/lambdas/dashboard-refresh/ bleibt unangetastet. README darin updaten mit Vermerk „v2 Plan, ersetzt durch v3 (static)“. Kein Cron mehr in CDK aktiv lassen.
  • Acceptance: EventBridge-Rule fuer dashboard-refresh ist disabled (oder Stack entfernt). README hat v3-Pointer.

Unit 0.2 — av-dashboard Repo aufraeumen

  • public/api/data/*.json bleibt als Read-Fallback waehrend Migration. Spaeter (Phase 3) wird der Pfad obsolet.
  • src/lib/data.ts — Typen bleiben, werden Vorbild fuer Zod-Schemas in Phase 1.
  • .env.example ergaenzen um neue Build-Vars: AWS_PROFILE_MGMT, HETZNER_API_TOKEN, CLOUDFLARE_API_TOKEN, GSUITE_OAUTH_PATH.
  • Acceptance: npm run dev startet noch ohne Fehler, alle 4 Pages laden Mock-Daten.

Unit 0.3 — Astro-Integrations vorbereiten

  • React-Integration installieren: npx astro add react — fuer Charts + interaktive Komponenten.
  • Astro-Content-Collections aktivieren in src/content/config.ts.
  • shadcn-Setup: npx shadcn@latest init fuer Tailwind-Preset + components.json. Default-Theme als Basis, Customizing in Phase 2.
  • Acceptance: Astro-Build laeuft mit React-Integration, leere src/content/config.ts da, components.json da.

Phase 1 — Content Collections + Zod-Schemas

Goal: Vault-Markdown wird zu typesafe Daten beim Build. Bestehende Mock-JSONs werden parallel weiter genutzt.

Unit 1.1 — Content-Collection projects

  • src/content/config.ts: Collection projects mit Zod-Schema entsprechend Schema 5.5 (id, type, project_type, customer, status, ball_bei, next_step, next_step_due, code_repos, tags).
  • Glob-Source: ~/source/agentic-ventures/intern/projekte/*/_index.md. Astro Content Collections supportet loader-Pattern fuer externe Pfade — sonst Symlink-Bridge src/content/projects/ → Vault.
  • Mapping-Function mapProject(entry) -> Projekt (kompatibel zum bestehenden Projekt-Type in src/lib/data.ts).
  • Acceptance: getCollection('projects') liefert validierte Liste, fehlerhafte Frontmatter wirft beim Build mit klarer Message.

Unit 1.2 — Content-Collection customers

  • Analog projects, Source intern/kunden/*.md. Schema 5.2 (customer).
  • Acceptance: validierte Kunden-Liste, Cross-Ref customer:-Field in Projekten wird via Zod-Refine geprueft (Kunde muss existieren).

Unit 1.3 — Snapshot-Collections cloud-snapshots + finanzen-snapshots

  • Zwei JSON-Collections (Astro 5 support JSON-Content).
  • Source: intern/finanzen/cloud-snapshots/<jahr>-<monat>.json + intern/finanzen/snapshots/<jahr>-<monat>.json.
  • Schema: monatliche Aggregate (Kategorien-Totals, Provider-Totals, Beleg-Count). Detail-Schema im File selbst dokumentiert.
  • Phase 1 erstellt die Schemas + leere Collection (keine Files da). Files kommen aus Phase 4 Backfill.
  • Acceptance: Collections sind definiert + leer, Build laeuft ohne Fehler.

Unit 1.4 — Current-Data-Schema fuer Build-Zeit-Pulls

  • Zwei TypeScript-Files in src/data/: finanzen-current.json + cloud-current.json. Initial leer / Mock-Inhalt.
  • Schema in src/lib/schemas.ts zentralisiert (Zod). Re-Export der bestehenden Types in src/lib/data.ts.
  • Acceptance: Build laeuft, Pages lesen aus src/data/*.json (statt aus public/api/data/*.json) per import.

Unit 1.5 — Migration der bestehenden Pages

  • /heute, /projekte: switch von fetchKpi(...) auf direkte Imports der Content-Collections.
  • /cloud, /finanzen: switch auf direkte Imports der Snapshot-Collections (wenn leer: Mock-Fallback aus Phase 0).
  • Acceptance: Alle 4 Pages laden Daten aus Content-Collections statt aus /api/data/. Mock-JSONs sind nicht mehr referenziert.

Phase 2 — Design-System + Mock /heute v3

Goal: Visueller Anker. Inter + JetBrains Mono installiert, Farb-Palette finalisiert, /heute v3 als statisches Mock. Kein State, kein Live-Daten — nur Form.

Unit 2.1 — Fonts self-hosted

  • public/fonts/ mit Inter Variable + JetBrains Mono Variable. Latin + Latin-Extended Subsets.
  • @font-face in src/styles/globals.css. font-display: swap.
  • tailwind.config.mjs: fontFamily.sans → Inter, fontFamily.mono → JetBrains Mono, mit System-Fallbacks.
  • Acceptance: Fonts laden in npm run dev ohne Netzwerk-Roundtrip zu Google. Visueller Vergleich vorher/nachher.

Unit 2.2 — Farb-Palette finalisieren

  • Erweitere ink-Palette um 200, 300, 500, 600, 800 (heute Luecken).
  • Akzent: behalte #0066cc, ergaenze accent.50 (Hintergrund-Wash), accent.muted (Subtle-Variante).
  • Semantic-Colors ok, warn, err behalten, ergaenze info (= accent).
  • Acceptance: Tailwind-Build laeuft, Beispiel-Komponente nutzt erweiterte Palette in Mock.

Unit 2.3 — shadcn-Komponenten installieren

  • npx shadcn@latest add button card badge separator dialog dropdown-menu tabs.
  • Dunkel-Modus via tailwindcss-animate + class-Strategy.
  • Acceptance: Komponenten in src/components/ui/ da, Beispiel-Card rendert.

Unit 2.4 — Mock /heute v3

  • Vorab frontend-design-Skill aufrufen mit Brief: vier Bloecke (R17-R20), Linear/Mercury-Aesthetik, Inter+Mono, Dark+Light, Mobile 375px.
  • Output ist statische Astro-Page src/pages/index-mock.astro (parallel zu existierendem index.astro).
  • Mock-Daten inline im File (kein Fetch).
  • Acceptance: Marvin sieht Mock im Browser, nimmt Look ab oder gibt Iteration-Feedback.

Unit 2.5 — Mock → echte /heute

  • Sobald Look abgenommen: index-mock.astro ersetzt index.astro. Datenquellen via Phase-1-Content-Collections.
  • Acceptance: /heute zeigt live-Daten im neuen Look, alle 4 Bloecke aktiv.

Phase 3 — shadcn-charts + Live-Daten

Goal: Charts auf /cloud + /finanzen + /heute Burn-Rate. Build-Time-Pulls fuer aktuelle Daten.

Unit 3.1 — shadcn-charts installieren + erste Chart

  • npx shadcn@latest add chart.
  • Burn-Rate-Sparkline-Component src/components/charts/BurnRateSparkline.tsx — React-Island, kleine SVG-Sparkline letzte 30 Tage.
  • Eingebunden in /heute Block 3 (R19).
  • Acceptance: Sparkline rendert mit Mock-Daten, responsive.

Unit 3.2 — Cloud-Charts auf /cloud

  • Drei Charts:
    • Stacked-Bar 30 Tage pro Tag, Stack nach Provider (aws/hetzner/cloudflare)
    • Pie/Donut Verteilung nach Business-Kategorie (current month)
    • Stacked-Area 13 Monate Trend (nutzt Snapshot-Collection wenn vorhanden, sonst nur aktueller Monat)
  • Zeit-Range-Selektor oben: 7d / 30d / 90d / 12mo / Custom — React-Island, schreibt localStorage.
  • Acceptance: Charts laden, Range-Selektor wechselt Daten.

Unit 3.3 — Finanzen-Charts auf /finanzen

  • Zwei Charts:
    • Bar pro Monat (letzte 12 Monate), Stack nach Kategorie — aus finanzen-snapshots-Collection
    • Donut Top-Kategorien current month
  • Belege-Drift-Counter bleibt prominent (R20).
  • Acceptance: Charts laden, leerer Zustand graceful wenn keine Snapshots da.

Unit 3.4 — Build-Time-Pull-Scripts (aktuelle Daten)

  • scripts/build-finanzen.ts — nutzt gsuite-MCP-CLI oder direkter Gmail-API-Call, schreibt src/data/finanzen-current.json.
  • scripts/build-cloud.ts — aws-cli + Hetzner-API + Cloudflare-API, schreibt src/data/cloud-current.json.
  • package.json Script prebuild ruft beide Scripts. Auch als npm run pull separat triggerbar.
  • Acceptance: npm run pull schreibt frische Daten, npm run build ruft pull vorher.

Unit 3.5 — Projekt-Detail-Pages /projekte/<slug>

  • Astro Dynamic Routes via Content-Collection.
  • Layout: Projekt-Header (name, status, customer-Link, next_step) + Activity-Timeline (aus last_activity Frontmatter falls vorhanden) + Code-Repos-Liste (mit Links auf ~/source/<slug>/).
  • Acceptance: /projekte/bas-twin laedt, Header korrekt.

Unit 3.6 — Kunden-Detail-Pages /kunden/<slug>

  • Analog Projekt-Detail. Profil aus Frontmatter, Liste verlinkter Projekte.
  • Acceptance: /kunden/becker laedt.

Phase 4 — Backfill-Scripts

Goal: Historische Snapshots in den Vault dumpen. On-demand, kein Cron.

Unit 4.1 — scripts/backfill-finanzen.ts

  • Liest Gmail-Belege via gsuite-MCP fuer alle Monate seit 2024-01.
  • Pro Monat: Kategorien-Totals + Beleg-Count berechnen (Pattern aus intern/finanzen/beleg-quellen.md Sender-Mapping).
  • Output: intern/finanzen/snapshots/<jahr>-<monat>.json mit Schema aus Unit 1.3.
  • Idempotent: bestehende Files werden ueberschrieben.
  • Dry-Run-Mode --dry-run zeigt was geschrieben wuerde.
  • Acceptance: Backfill schreibt ~28 Monats-Files (2024-01 bis 2026-04), Spot-Check 2-3 Files inhaltlich korrekt.

Unit 4.2 — scripts/backfill-cloud.ts

  • Liest AWS Cost-Explorer fuer alle erreichbaren Monate (max 13 zurueck).
  • Pro Monat: pro Linked-Account Kategorien-Totals (mapping in intern/capabilities/aws/_index.md).
  • Hetzner + Cloudflare: NUR aktueller Monat (API gibt nicht mehr her). Ab heute live, History startet bei dem ersten Backfill.
  • Output: intern/finanzen/cloud-snapshots/<jahr>-<monat>.json.
  • Acceptance: ~13 AWS-Monats-Files + 1 Hetzner/Cloudflare-Current-Snapshot geschrieben.

Unit 4.3 — Charts wechseln von leer auf real

  • /cloud Stacked-Area zeigt 13 Monate echt.
  • /finanzen Monats-Bar zeigt 12+ Monate echt.
  • /heute Burn-Rate vergleicht Current-Month mit Vormonat-Aggregat aus Snapshot.
  • Acceptance: Visueller Smoke-Test, Zahlen plausibel (gegen Papierkram-Stand abgleichen).

Unit 4.4 — Vault-Commit fuer Snapshots

  • Backfill commitet NICHT automatisch. Marvin reviewed git diff intern/finanzen/snapshots/ + commitet manuell mit chore(dashboard): backfill finanzen-snapshots <jahr>-<monat>..<jahr>-<monat>.
  • Acceptance: Snapshot-Files sind im Vault-Git-Log nachvollziehbar.

Phase 5 — Customization (Saved Views + localStorage)

Goal: Marvin kann Karten ein-/ausblenden, reordern, zwischen Saved Views switchen.

Unit 5.1 — Card-Registry + Stable-IDs

  • Jede Card auf /uebersicht hat eine stable ID (card.projects.today, card.cloud.burn-rate, etc.).
  • Zentrale Registry src/lib/cards.ts mit Card-Definitionen (id, title, default-visible, default-order).
  • Acceptance: Registry vollstaendig, alle Cards auf /uebersicht registriert.

Unit 5.2 — localStorage-Layer

  • src/lib/preferences.ts — typesafe getPref(key) / setPref(key, value), mit Defaults aus Registry.
  • Keys: av-dashboard.<view>.hidden-cards, av-dashboard.<view>.order, av-dashboard.<page>.time-range.
  • Acceptance: Praefs persistieren ueber Reload, kein React-State-Issue.

Unit 5.3 — Card-Toolbar (Show/Hide + Reorder)

  • Pro Card kleines MoreMenu (shadcn Dropdown) mit „verbergen” + ↑ + ↓.
  • Hidden-Cards in einem Footer-Akkordeon „verborgene Karten (n)” wieder einblendbar.
  • Acceptance: Verstecken + Reordern funktioniert, Reload behaelt Zustand.

Unit 5.4 — Saved-View-Switcher

  • Top-Bar auf /uebersicht: drei Buttons Morning / Cost-Audit / Steuerberater + „Custom” (Marvins Manual-Edit-Zustand).
  • View-Definitionen aus intern/firma/dashboard-views.json (per Content-Collection geladen).
  • Click switched localStorage-Keys, Page re-rendert.
  • Acceptance: View-Switch in 1 Click, Layout aendert sich sichtbar.

Unit 5.5 — Time-Range-Selektor (globale Component)

  • React-Island <TimeRangeSelector />, eingebunden in /cloud, /finanzen, /uebersicht.
  • Optionen: 7d / 30d / 90d / 12mo / Custom (Date-Picker shadcn-Component).
  • Filtert die geladenen Snapshots client-side.
  • Acceptance: Range-Wechsel re-rendert Charts, persistiert pro Page.

Phase 6 — Deploy

Goal: Live unter dashboard.agenticventures.de, Cognito-protected.

Unit 6.1 — S3 + CloudFront aus Runbook v2 reaktivieren

  • runbook.md aus v2 hat die CDK-Steps. Re-use ohne Lambda-Stack (nur S3 + CloudFront + Route53 + ACM).
  • Deploy in av-production (eu-central-1).
  • Acceptance: CloudFront-Distribution erreichbar via temporaere CloudFront-Domain mit Static-Build.

Unit 6.2 — Cognito User-Pool + Google IdP

  • Cognito-User-Pool + Hosted UI + Google-IdP (hello@-only via Email-Filter im Pre-Sign-Up-Trigger).
  • Frontend bereits vorbereitet (src/lib/auth.ts, Dashboard.astro-Redirect-Logik).
  • .env.production mit PUBLIC_COGNITO_DOMAIN, PUBLIC_COGNITO_CLIENT_ID, PUBLIC_AUTH_REDIRECT_URI.
  • Acceptance: Login via Google funktioniert, andere Accounts werden blockiert.

Unit 6.3 — Cloudflare-DNS Cutover

  • CNAME dashboard.agenticventures.de → CloudFront-Domain.
  • ACM-Cert in us-east-1 (CloudFront-Constraint) fuer den Subdomain.
  • Acceptance: HTTPS-Cert valid, Domain liefert Dashboard.

Unit 6.4 — Smoke-Test in Production

  • Alle 4 Hauptpages + Detail-Routes per Browser-Klick durchgehen.
  • Mobile-Test auf iPhone (375px) und iPad (768px).
  • Console-Errors? Network-Tab auf US-Drittanbieter pruefen.
  • Acceptance: Keine US-CDN-Calls im Network, keine Console-Errors, alle Pages rendern.

Risk Log

RiskWahrscheinlichkeitImpactMitigation
Gmail-MCP-Pull schlaegt aus Build-Skript fehl (OAuth-Token expired)MittelMittelSkript-Output ist gecached in src/data/*.json — Build laeuft mit Stand-Daten weiter, Warning im Footer. Marvin re-authet on-demand.
AWS Cost-Explorer braucht Cross-Account-Aktivierung die noch nicht laeuftMittelMittelPhase 0 Smoke-Test aws ce get-cost-and-usage --profile av-mgmt. Falls Fehler: Aktivierung in av-mgmt-Account ist 1-Klick-Setting.
Astro Content Collections + Vault-Pfade ausserhalb des ReposMittelNiedrigLoader-Pattern (Astro 5 unterstuetzt) oder Symlink im Repo. Symlink ist robuster fuer File-Watcher.
Snapshot-File-Format aendert sich rueckwirkend, alte Snapshots brechenNiedrigMittelZod-Schema versioniert (schema_version im Snapshot-File). Migration-Script falls aenderung noetig.
Inter Variable Font-File ist zu gross (>500kb)NiedrigNiedrigVariable-Font mit Subsetting via glyphhanger oder direkt das offizielle latin-subset von rsms.me.
Cognito Google-IdP Filter-Trigger nicht straight-forwardMittelNiedrigPre-Sign-Up-Lambda akzeptiert nur hello@-Email. Templates online, ~30min Setup.
Backfill-Skript laeuft 20 Minuten (~261 Belege, 28 Monate, Pro-Monat-Pull)NiedrigNiedrigOn-demand-Script, Marvin laeuft es einmal abends. Progress-Bar.
Recharts-Tree-Shaking schlaegt fehl, Bundle wird grossNiedrigNiedrigshadcn-charts-Pattern importiert nur was gebraucht wird. Bundle-Analyzer-Check vor Deploy.

Open Questions for Implementation

  • [Phase 1] Astro 5 Loader-Pattern fuer Glob ausserhalb src/content/ testen — alternativ Symlink src/content/projects~/source/agentic-ventures/intern/projekte/?
  • [Phase 4] Belege-Kategorie-Mapping ist heute in beleg-quellen.md als Prosa. Plan: vor Backfill in scripts/lib/beleg-kategorien.ts als typesafe Mapping ueberfuehren.
  • [Phase 5] Saved-View JSON-Format finalisieren — Plan-Vorschlag:
    {
      "morning": {
        "visible": ["card.today.tasks", "card.projects.active", "card.cloud.burn-rate", "card.finanzen.drift"],
        "order": [...]
      },
      "cost-audit": { ... },
      "steuerberater": { ... }
    }

Next Steps

  1. Phase 0 Unit 0.3 startklar machen (Astro-React + Content-Collections-Setup).
  2. Parallel: frontend-design-Skill fuer Mock /heute v3 (Unit 2.4) — visueller Anker BEVOR Phase 1 los geht.
  3. Nach Mock-Abnahme: Phase 1 + Phase 2 in Reihenfolge, dann Phase 3.