chore(format): Prettier über das gesamte Repo
ci / quality (push) Failing after 45s
ci / build (push) Has been skipped
deploy / deploy (push) Successful in 53s

Behebt die rote CI (format:check schlug an 36 Alt-Bestand-Dateien fehl:
migrations/meta-Snapshots, seed.ts, schemas/lead.ts, README u. a.) und erzwingt
nebenbei einen frischen web-Build beim Auto-Deploy (apps/web-Dateien geaendert
-> COPY-Layer invalidiert -> Vite baut neu).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Raffael SheikhandClaude Opus 4.8 committed 2026-06-07 17:50:07 +02:00
1 parent b340b45110
commit a1cf6f3883
36 files changed
+1559 -3510

No files matched your search

+77 -76
View File
@@ -8,15 +8,15 @@ Internes Web-Tool von **ToolCTRL** für den täglichen Überblick über alle Pro
## Was die App tut
| Bereich | Feature |
|---|---|
| **Dashboard** (`/dashboard`) | Unternehmens-Übersicht: Bereichs-Ampelstatus, **Showstopper** (offene Showstopper-Risiken), **Projekte in Eskalation/Taskforce**, „Heute fehlt"-Liste, bereichsübergreifende Blocker, Pflicht-Minimum-Übersicht, Jourfixe-Hinweis, „Heute im Team" (ToDos), „Zeit im Team heute" (Live-Tracking, Wall-Clock), Vortags-Feed |
| **Bereich** (`/bereich`, `/bereich/<slug>`) | Tab-Switcher Entwicklung / Vertrieb / Marketing — Projekt-Liste (Kundenprojekte / Interne Projekte) mit Pflicht-Minimum- & Modus-Indicator. **Vertrieb** zusätzlich: Lead-Teaser + „Projekte mit Vertriebsaktivität" (bereichsübergreifend) |
| **Projekt** (`/projekt/:id`) | Detail: Ziel/Maxime/Nicht-Ziele/Liefergegenstände + Zieldreieck, **Phasen-Lebenszyklus mit Gate-Reviews**, **Statusbericht** (Ampel/Trend + Verlauf), **Stakeholder-Matrix**, **Risiko- & Chancen-Register**, **verknüpfte Leads**, **Änderungs-Log**, Verlinkungen, Pflicht-Minimum, Meilensteine (mit Ergebnis/Kundennutzen + Datums-Warnung), DoD, Projekt-Abschluss (Checkliste + Vermerk, P1), Projekt-Modus |
| **Leads** (`/leads`, `/lead/:id`) | Vertriebs-CRM: Lead-Liste nach Status (Cold/Warm/Hot/Won/Lost), Dossier (Stammdaten, Pain & Bedarf, Soft Factors, Strategie), Kontaktpersonen, Austausch-Log, **CSV-Import**, Lead→Deal-Promotion, **Projekt-Verknüpfung** |
| **Heute** (`/heute`) | Tagesrhythmus: Lock-in mit ToDo-Liste, Auto-Carryover offener ToDos vom Vortag, **ToDos mitten am Tag hinzufügen**, Timer pro ToDo, Zeiterfassungs-Timeline mit Edit/Delete/Nachtrag |
| **Reflexion** (`/reflexion`) | Abend-Reflexion: ToDos abhaken + **Titel inline korrigieren**, Freitext, Ampel + Trend, optional Blocker. Editierbar bis 00:00 Berlin |
| **Archiv** (`/archiv`) | Abgeschlossene Projekte, gruppiert nach Bereich |
| Bereich | Feature |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Dashboard** (`/dashboard`) | Unternehmens-Übersicht: Bereichs-Ampelstatus, **Showstopper** (offene Showstopper-Risiken), **Projekte in Eskalation/Taskforce**, „Heute fehlt"-Liste, bereichsübergreifende Blocker, Pflicht-Minimum-Übersicht, Jourfixe-Hinweis, „Heute im Team" (ToDos), „Zeit im Team heute" (Live-Tracking, Wall-Clock), Vortags-Feed |
| **Bereich** (`/bereich`, `/bereich/<slug>`) | Tab-Switcher Entwicklung / Vertrieb / Marketing — Projekt-Liste (Kundenprojekte / Interne Projekte) mit Pflicht-Minimum- & Modus-Indicator. **Vertrieb** zusätzlich: Lead-Teaser + „Projekte mit Vertriebsaktivität" (bereichsübergreifend) |
| **Projekt** (`/projekt/:id`) | Detail: Ziel/Maxime/Nicht-Ziele/Liefergegenstände + Zieldreieck, **Phasen-Lebenszyklus mit Gate-Reviews**, **Statusbericht** (Ampel/Trend + Verlauf), **Stakeholder-Matrix**, **Risiko- & Chancen-Register**, **verknüpfte Leads**, **Änderungs-Log**, Verlinkungen, Pflicht-Minimum, Meilensteine (mit Ergebnis/Kundennutzen + Datums-Warnung), DoD, Projekt-Abschluss (Checkliste + Vermerk, P1), Projekt-Modus |
| **Leads** (`/leads`, `/lead/:id`) | Vertriebs-CRM: Lead-Liste nach Status (Cold/Warm/Hot/Won/Lost), Dossier (Stammdaten, Pain & Bedarf, Soft Factors, Strategie), Kontaktpersonen, Austausch-Log, **CSV-Import**, Lead→Deal-Promotion, **Projekt-Verknüpfung** |
| **Heute** (`/heute`) | Tagesrhythmus: Lock-in mit ToDo-Liste, Auto-Carryover offener ToDos vom Vortag, **ToDos mitten am Tag hinzufügen**, Timer pro ToDo, Zeiterfassungs-Timeline mit Edit/Delete/Nachtrag |
| **Reflexion** (`/reflexion`) | Abend-Reflexion: ToDos abhaken + **Titel inline korrigieren**, Freitext, Ampel + Trend, optional Blocker. Editierbar bis 00:00 Berlin |
| **Archiv** (`/archiv`) | Abgeschlossene Projekte, gruppiert nach Bereich |
**Querschnittsfunktionen**
@@ -32,23 +32,23 @@ Internes Web-Tool von **ToolCTRL** für den täglichen Überblick über alle Pro
## Tech Stack
| Layer | Wahl |
|---|---|
| Sprache | **TypeScript** strict, ESM überall |
| Repo-Layout | **pnpm**-Monorepo (`pnpm-workspace.yaml`) |
| Node | **22+** |
| Frontend | **Vite 5 + React 18 + Tailwind 4 + React Router 7 + React Query 5 + Sonner** (Toasts) + **lucide-react** (Icons) |
| Backend | **Fastify 5 + tRPC v11** (`@trpc/server/adapters/fastify`) |
| ORM | **Drizzle 0.38** + **drizzle-kit** |
| Datenbank | **Postgres 16** |
| Auth | **Authentik OIDC** via `openid-client v6` (Auth Code + PKCE), Session-Cookies HttpOnly+SameSite=Lax, Sessions in Postgres |
| Validation | **Zod 3** (geteilt zwischen FE und BE via `@cockpit/shared`) |
| Logging | **pino** (Fastify-built-in) |
| Styling | Tailwind 4 + CSS-Custom-Properties · Hausschrift **Space Grotesk** (selbst gehostet) · Keycap-Button-Stil |
| Tests | **Vitest** (Unit + tRPC) |
| Reverse-Proxy | **Caddy 2** (siehe `Caddyfile`) |
| CI | **Gitea Actions** (`.gitea/workflows/ci.yml`) |
| Deployment | **Docker Compose** (`docker-compose.yml`) auf ToolCTRL-interner Infra |
| Layer | Wahl |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Sprache | **TypeScript** strict, ESM überall |
| Repo-Layout | **pnpm**-Monorepo (`pnpm-workspace.yaml`) |
| Node | **22+** |
| Frontend | **Vite 5 + React 18 + Tailwind 4 + React Router 7 + React Query 5 + Sonner** (Toasts) + **lucide-react** (Icons) |
| Backend | **Fastify 5 + tRPC v11** (`@trpc/server/adapters/fastify`) |
| ORM | **Drizzle 0.38** + **drizzle-kit** |
| Datenbank | **Postgres 16** |
| Auth | **Authentik OIDC** via `openid-client v6` (Auth Code + PKCE), Session-Cookies HttpOnly+SameSite=Lax, Sessions in Postgres |
| Validation | **Zod 3** (geteilt zwischen FE und BE via `@cockpit/shared`) |
| Logging | **pino** (Fastify-built-in) |
| Styling | Tailwind 4 + CSS-Custom-Properties · Hausschrift **Space Grotesk** (selbst gehostet) · Keycap-Button-Stil |
| Tests | **Vitest** (Unit + tRPC) |
| Reverse-Proxy | **Caddy 2** (siehe `Caddyfile`) |
| CI | **Gitea Actions** (`.gitea/workflows/ci.yml`) |
| Deployment | **Docker Compose** (`docker-compose.yml`) auf ToolCTRL-interner Infra |
⚠️ **Namespace-Hinweis**: Die internen pnpm-Packages heißen `@cockpit/*` (Historie), die App selbst heißt **everythingbutwork**. Nicht umbenennen — das würde unzählige Imports brechen ohne Mehrwert.
@@ -153,11 +153,11 @@ Im Dev-Modus läuft ein **Auto-Login** als Admin-User `dejan@tool-ctrl.de`. Auth
### Wichtige Ports
| Service | Port | Quelle |
|---|---|---|
| Vite Dev-Server | **7173** | `apps/web/vite.config.ts` |
| Fastify API | **7100** | `.env` (`PORT`) |
| Postgres (Dev) | **55432** | `docker-compose.dev.yml` (5432 würde mit Mac-System-Postgres kollidieren) |
| Service | Port | Quelle |
| --------------- | --------- | ------------------------------------------------------------------------- |
| Vite Dev-Server | **7173** | `apps/web/vite.config.ts` |
| Fastify API | **7100** | `.env` (`PORT`) |
| Postgres (Dev) | **55432** | `docker-compose.dev.yml` (5432 würde mit Mac-System-Postgres kollidieren) |
### Häufig genutzte Scripts
@@ -178,29 +178,29 @@ Postgres 16, Drizzle als ORM und Migrator. **Schema-Single-Source-of-Truth**: `p
### Tabellen (aktueller Stand nach Migration 0011)
| Tabelle | Zweck |
|---|---|
| `user` | Mitarbeiter (`authentik_sub` als Identitäts-Anker), `is_admin`-Flag |
| `session` | Server-Side Sessions (Postgres-persistent), Browser kennt nur Cookie-`id` |
| `audit_event` | Audit-Trail (Tabelle vorhanden; `withAudit`-Wrapper aktuell nicht verdrahtet) |
| `area` | Bereich (entwicklung / vertrieb / marketing / allgemein) |
| `project` | Projekt: Name, `description`, `maxime`, `ziel`/`nicht_ziele`/`liefergegenstaende`, `zieldreieck_flex`, `modus`, `phase`, Outline-/Plane-URLs, Arbeitsmodus, `pflicht_minimum_state` JSONB, Status-/Trend-Cache, `abschlussvermerk`, Archiv-Felder |
| `milestone` | Cockpit-Sicht-Meilenstein pro Projekt (+ `ergebnis`, `kundennutzen`) |
| `project_status` | Statusbericht-Historie pro Projekt (Ampel/Trend/Text, extern-Flag) |
| `phase_gate` | Gate-Review am Phasenende (Ergebnis erreicht? + Notiz) |
| `change_entry` | Änderungs-Log pro Projekt (Scope-Creep) |
| `stakeholder` | Stakeholder-Analyse pro Projekt (Interesse × Einfluss, Haltung) |
| `risk` | Risiko- & Chancen-Register pro Projekt (W×A, Showstopper, Owner, Strategie) |
| `day_entry` | Tageseintrag (begun / full / absent), `published_at` für Vortrags-Veröffentlichung |
| `todo` | Tagesplan-Item, optional an Bezug gebunden, `carried_over`-Flag |
| `absence_day` | Urlaub/Krank/Sonstiges — zählt nicht gegen Streak |
| `blocker` | Bereichsübergreifendes Hindernis |
| `lead` | Vertriebs-Lead-Dossier; optionale `project_id`-Verknüpfung zum (universellen) Projekt |
| `lead_contact` | Kontaktperson(en) eines Leads |
| `lead_touchpoint` | Austausch-Log eines Leads (Kanal, Outcome, Follow-up) |
| `deal` | Pipeline-Deal; wird per Lead→Deal-Promotion erzeugt |
| `gtm_step`, `campaign`, `lead_handover` | Im Schema vorhanden (Phase-2-Vorbereitung), kein UI |
| `time_entry` | Zeiterfassungs-Block, optional an ToDo gebunden, Partial-Unique-Index erzwingt max. einen aktiven Timer pro User |
| Tabelle | Zweck |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user` | Mitarbeiter (`authentik_sub` als Identitäts-Anker), `is_admin`-Flag |
| `session` | Server-Side Sessions (Postgres-persistent), Browser kennt nur Cookie-`id` |
| `audit_event` | Audit-Trail (Tabelle vorhanden; `withAudit`-Wrapper aktuell nicht verdrahtet) |
| `area` | Bereich (entwicklung / vertrieb / marketing / allgemein) |
| `project` | Projekt: Name, `description`, `maxime`, `ziel`/`nicht_ziele`/`liefergegenstaende`, `zieldreieck_flex`, `modus`, `phase`, Outline-/Plane-URLs, Arbeitsmodus, `pflicht_minimum_state` JSONB, Status-/Trend-Cache, `abschlussvermerk`, Archiv-Felder |
| `milestone` | Cockpit-Sicht-Meilenstein pro Projekt (+ `ergebnis`, `kundennutzen`) |
| `project_status` | Statusbericht-Historie pro Projekt (Ampel/Trend/Text, extern-Flag) |
| `phase_gate` | Gate-Review am Phasenende (Ergebnis erreicht? + Notiz) |
| `change_entry` | Änderungs-Log pro Projekt (Scope-Creep) |
| `stakeholder` | Stakeholder-Analyse pro Projekt (Interesse × Einfluss, Haltung) |
| `risk` | Risiko- & Chancen-Register pro Projekt (W×A, Showstopper, Owner, Strategie) |
| `day_entry` | Tageseintrag (begun / full / absent), `published_at` für Vortrags-Veröffentlichung |
| `todo` | Tagesplan-Item, optional an Bezug gebunden, `carried_over`-Flag |
| `absence_day` | Urlaub/Krank/Sonstiges — zählt nicht gegen Streak |
| `blocker` | Bereichsübergreifendes Hindernis |
| `lead` | Vertriebs-Lead-Dossier; optionale `project_id`-Verknüpfung zum (universellen) Projekt |
| `lead_contact` | Kontaktperson(en) eines Leads |
| `lead_touchpoint` | Austausch-Log eines Leads (Kanal, Outcome, Follow-up) |
| `deal` | Pipeline-Deal; wird per Lead→Deal-Promotion erzeugt |
| `gtm_step`, `campaign`, `lead_handover` | Im Schema vorhanden (Phase-2-Vorbereitung), kein UI |
| `time_entry` | Zeiterfassungs-Block, optional an ToDo gebunden, Partial-Unique-Index erzwingt max. einen aktiven Timer pro User |
Migrationen liegen in `packages/db/migrations/*.sql` und werden über `drizzle-kit migrate` angewendet. Schema-Änderungen brauchen **immer eine neue Migration** — kein Schema-Drift.
@@ -210,16 +210,16 @@ Migrationen liegen in `packages/db/migrations/*.sql` und werden über `drizzle-k
### REST-Routen (Fastify)
| Methode | Pfad | Zweck |
|---|---|---|
| `GET` | `/api/health` | DB- und Authentik-Reachability-Check |
| `GET` | `/api/me` | Eingeloggter User (oder 401) |
| `GET` | `/api/auth/login` | Startet OIDC-Flow (Redirect zu Authentik) |
| `GET` | `/api/auth/callback` | Code-Exchange + Session-Create |
| `POST` | `/api/auth/logout` | Session löschen + Cookie clearen |
| `GET\|POST` | `/api/auth/dev-login` | **Nur Dev-Modus**: Auto-Login als Dejan |
| `POST` | `/trpc/<procedurePath>` | tRPC-Endpunkt (Batch + Stream) |
| `POST` | `/internal/cron/<job>` | Bearer-Token-geschützt: publish-day-entries, recompute-streaks, recompute-pflicht-minimum-5, pg-dump-backup |
| Methode | Pfad | Zweck |
| ----------- | ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| `GET` | `/api/health` | DB- und Authentik-Reachability-Check |
| `GET` | `/api/me` | Eingeloggter User (oder 401) |
| `GET` | `/api/auth/login` | Startet OIDC-Flow (Redirect zu Authentik) |
| `GET` | `/api/auth/callback` | Code-Exchange + Session-Create |
| `POST` | `/api/auth/logout` | Session löschen + Cookie clearen |
| `GET\|POST` | `/api/auth/dev-login` | **Nur Dev-Modus**: Auto-Login als Dejan |
| `POST` | `/trpc/<procedurePath>` | tRPC-Endpunkt (Batch + Stream) |
| `POST` | `/internal/cron/<job>` | Bearer-Token-geschützt: publish-day-entries, recompute-streaks, recompute-pflicht-minimum-5, pg-dump-backup |
### tRPC-Router (`apps/api/src/routers/_app.ts`)
@@ -359,12 +359,12 @@ Konstanten (`MAX_TODO_TEXT_LENGTH`, `WERKTAGE`, `JOURFIXE_DAY`, `REFLEXION_REMIN
`docker-compose.yml` definiert vier Services:
| Service | Image | Rolle |
|---|---|---|
| `postgres` | `postgres:16-alpine` | DB, persistentes Volume `cockpit_postgres_data`, Backups in `cockpit_backups` |
| `api` | Build aus `apps/api/Dockerfile` | Fastify auf 3000, hängt an Postgres-Health |
| `web` | Build aus `apps/web/Dockerfile` | Vite-Build wird in `cockpit_web_dist`-Volume gelegt |
| `caddy` | `caddy:2-alpine` | Reverse-Proxy (80+443), TLS via Let's Encrypt, Caddyfile mountet |
| Service | Image | Rolle |
| ---------- | ------------------------------- | ----------------------------------------------------------------------------- |
| `postgres` | `postgres:16-alpine` | DB, persistentes Volume `cockpit_postgres_data`, Backups in `cockpit_backups` |
| `api` | Build aus `apps/api/Dockerfile` | Fastify auf 3000, hängt an Postgres-Health |
| `web` | Build aus `apps/web/Dockerfile` | Vite-Build wird in `cockpit_web_dist`-Volume gelegt |
| `caddy` | `caddy:2-alpine` | Reverse-Proxy (80+443), TLS via Let's Encrypt, Caddyfile mountet |
Env-Variablen werden über `.env.production` injiziert. Required: `POSTGRES_PASSWORD`, `SESSION_COOKIE_SECRET` (mind. 32 Z.), `CRON_BEARER_TOKEN`, `AUTHENTIK_*`.
@@ -392,6 +392,7 @@ build → install, web build, api build (needs quality)
`.gitea/workflows/deploy.yml` (Runner `runs-on: host` auf dem Homeserver): **bei jedem Push auf `main`** → `git reset --hard origin/main`, `docker compose up -d --build`, dann Warten bis `cockpit-api` healthy. Es gibt **keinen manuellen Trigger** — ein (ggf. leerer) Push löst den Deploy aus.
**Startup-Verhalten der API** (`apps/api/src/server.ts`): vor dem Listen wird
1. `runMigrations()` ausgeführt (Drizzle-Migrationen idempotent; schlägt eine fehl, startet die API nicht), dann
2. `ensureBaseAreas()` (legt die 4 Basis-Bereiche idempotent an, damit z. B. der „Neues Projekt"-Dropdown nie leer ist — auch auf einer nicht geseedeten Prod-DB).
@@ -434,12 +435,12 @@ Vollständige PRD/Architektur/UX/Stories im `_bmad-output/planning-artifacts/`-O
- Ursprüngliche User Journeys
- Anti-Ziele und Roadmap-Hinweise
| Datei | Inhalt |
|---|---|
| `prds/prd-projectmanagement-2026-05-25/prd.md` | PRD (49 FRs, 16 NFRs) |
| `architecture.md` | Stack-Entscheidungen, Patterns |
| `ux-design-specification.md` | Brand-Tokens, Komponenten, Voice & Tone |
| `epics.md` | 6 Epics, 32 Stories |
| Datei | Inhalt |
| ---------------------------------------------- | --------------------------------------- |
| `prds/prd-projectmanagement-2026-05-25/prd.md` | PRD (49 FRs, 16 NFRs) |
| `architecture.md` | Stack-Entscheidungen, Patterns |
| `ux-design-specification.md` | Brand-Tokens, Komponenten, Voice & Tone |
| `epics.md` | 6 Epics, 32 Stories |
---