Alt-Bestand nie formatiert — isolierter Format-Lauf vor der Audit-Verdrahtung. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
everythingbutwork
Internes Web-Tool von ToolCTRL für den täglichen Überblick über alle Projekte und Bereiche. Es ist das dritte Werkzeug neben Plane (Tickets) und Outline (Doku) und operationalisiert den ToolCTRL Projektmanagement-Leitfaden v3.0.
Falls du in dieses Repo neu reinrutschst (neue Session, anderes Modell): lies
CONVENTIONS.mdvor jedem Edit, und schau in_bmad-output/planning-artifacts/für den vollen PRD/Architektur/UX-/Stories-Kontext.
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 |
Querschnittsfunktionen
- Leads / CRM: Qualitative Lead-Dossiers im Vertrieb, CSV-Import (header-basiert, Dedup über Firmenname, Adresse → Standort, Notizen → Austausch-Log), optionale Verknüpfung zu einem Projekt (egal welcher Bereich) → Projekte mit Leads erscheinen in der Vertriebs-Sicht, ohne redundant angelegt zu werden.
- Projektmanagement-Tiefe (operationalisiert Leitfaden v3.0): Projekt-Modus (Relax/Standard/Eskalation/Taskforce), 4-Phasen-Lebenszyklus mit Gate-Reviews, Statusbericht (Ampel/Trend/Text + Verlauf), Stakeholder-Analyse mit Macht/Interesse-Matrix, Risiko- & Chancen-Register (W×A, Showstopper, Owner, Strategie), Änderungs-Log (Scope-Creep), Zieldreieck, strukturierter Abschluss.
- Zeiterfassung: Persistente Timer-Pill in der TopNav (Live-Sekundenzähler), Quick-Picker mit ToDos + Kategorien + Freitext, retroaktiver Nachtrag. „Gesamt" pro Person ist Wall-Clock (überlappende parallele Tasks zählen einmal); pro Aufgabe wird die Summe getrennt ausgewiesen („getrackt").
- Blocker: Inline in der Reflexion oder über
n-Shortcut bzw. den globalen „Neuer Blocker"-Dialog. Auflösung nur durch den Projekt-P1. - Pflicht-Minimum-Check (Leitfaden §9): 6-Punkte-Checkliste pro Projekt; Punkt „Status-Ampel aktuell (≤ 7 Werktage)" wird per Cron pro Projekt aus dem jüngsten Statusbericht berechnet.
- Streak: aufeinanderfolgende Werktage mit voller Reflexion. Wochenenden, bundesweite Feiertage und gemeldete Abwesenheiten sind neutral (brechen nicht). Flammen-Pill rechts oben.
- Keyboard-Shortcuts:
g d/b/h/aNavigation,g e/v/mdirekt in Entwicklung/Vertrieb/Marketing,nNeuer Blocker,?Cheatsheet.
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 |
⚠️ 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.
Verzeichnisstruktur
.
├── apps/
│ ├── web/ Vite + React SPA (Port 7173)
│ │ ├── public/ Brand-Assets (Logo SVG, Fonts, Favicon)
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── blocker/ BlockerDialog
│ │ │ │ ├── layout/ AppShell, TopNav
│ │ │ │ ├── time/ TimerPill, TimelineSection, TeamTimeSection
│ │ │ │ └── ui/ Button, Card, KeyCaret, SkeletonCard, ToolCtrlLogo
│ │ │ ├── hooks/ useCurrentUser
│ │ │ ├── lib/ router, trpc, trpc-provider, voice,
│ │ │ │ format-duration, time-categories,
│ │ │ │ lead-meta, project-meta
│ │ │ ├── routes/ dashboard, bereich, projekt, heute, reflexion,
│ │ │ │ leads, lead, archiv, login, not-found
│ │ │ └── styles/globals.css
│ │ ├── index.html
│ │ └── vite.config.ts
│ └── api/ Fastify Backend (Port 7100)
│ ├── crontab System-Cron-Definitionen (Containerseitig)
│ └── src/
│ ├── auth/ oidc, routes (login/callback/logout/dev-login),
│ │ session, user, middleware
│ ├── cron/routes.ts /internal/cron/* (Bearer-Token geschützt)
│ ├── lib/ werktag (Mo-Fr Berlin + Feiertage), holidays,
│ │ streak, csv, ampel, pflicht-minimum, logger
│ ├── routers/ _app, user, area, project, deal, gtm, lead,
│ │ risk, stakeholder, change, campaign, blocker,
│ │ day-entry, time, dashboard
│ ├── env.ts Zod-validierte Env-Vars
│ ├── db.ts Singleton-Drizzle-Client
│ ├── trpc.ts Context, protectedProcedure, withAudit
│ ├── types.ts Fastify-Augmentation für req.cockpitUser
│ └── server.ts Fastify-Bootstrap + Healthcheck
├── packages/
│ ├── db/ Drizzle-Schema + Migrationen
│ │ ├── src/{schema,client,seed,index,migrate,base-data}.ts
│ │ ├── migrations/ 0000_init … 0011_lead_project_link
│ │ └── drizzle.config.ts
│ └── shared/ Zod-Schemas + Konstanten + Types
│ └── src/schemas/ day-entry, project, deal, campaign, time-entry,
│ lead, risk, stakeholder, change
├── _bmad-output/planning-artifacts/ PRD, Architektur, UX-Spec, Epics, Decision-Log
├── docs/operations.md Ops-Guide (Authentik-Setup, Backup, Restore)
├── scripts/backup.sh pg_dump-Skript (im Postgres-Container)
├── docker-compose.yml Produktion (web + api + postgres + caddy)
├── docker-compose.dev.yml Nur Postgres für lokale Entwicklung
├── Caddyfile Reverse-Proxy-Config
├── CONVENTIONS.md Bindende Code-Konventionen
├── .gitea/workflows/ci.yml Gitea Actions
├── .env.example Env-Template
├── eslint.config.mjs Flat-Config (ESLint 9)
├── tsconfig.base.json Shared TS-Config
└── pnpm-workspace.yaml
Lokal loslegen
Vorbereitung (einmalig)
# Repo & Tooling
pnpm install # 4 Workspaces installieren
cp .env.example .env # Defaults reichen für lokale Entwicklung
Dev-Stack starten
# 1) Postgres im Docker-Container (Port 55432, NICHT 5432!)
docker compose -f docker-compose.dev.yml up -d postgres
# 2) Migration anwenden (Schema initialisieren)
DATABASE_URL='postgres://cockpit:cockpit_dev@localhost:55432/cockpit' \
pnpm --filter @cockpit/db migrate:up
# 3) Optional: Seed mit Test-Areas (Entwicklung/Vertrieb/Marketing/Allgemein)
DATABASE_URL='postgres://cockpit:cockpit_dev@localhost:55432/cockpit' \
pnpm --filter @cockpit/db run seed
# 4) API + Web parallel starten (zwei Terminals)
pnpm --filter @cockpit/api dev # → http://localhost:7100
pnpm --filter web dev # → http://localhost:7173
Browser öffnen
Im Dev-Modus läuft ein Auto-Login als Admin-User dejan@tool-ctrl.de. Authentik ist nicht erforderlich; der Redirect zu /api/auth/dev-login setzt sofort eine Session.
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) |
Häufig genutzte Scripts
pnpm typecheck # alle Workspaces parallel
pnpm lint # ESLint (flat config)
pnpm format # Prettier write
pnpm test # Vitest (--passWithNoTests für leere)
pnpm --filter @cockpit/db studio # Drizzle Studio (Browser-DB-Inspector)
pnpm --filter @cockpit/db migrate:generate --name=<name> # neue Migration
Datenbank
Postgres 16, Drizzle als ORM und Migrator. Schema-Single-Source-of-Truth: packages/db/src/schema.ts.
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 |
Migrationen liegen in packages/db/migrations/*.sql und werden über drizzle-kit migrate angewendet. Schema-Änderungen brauchen immer eine neue Migration — kein Schema-Drift.
API-Surface
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 |
tRPC-Router (apps/api/src/routers/_app.ts)
health publicProcedure
user me, list, markAbsent
area list
project list, byAreaSlug, byId, create, update, archive,
setMilestoneStatus, addMilestone, updateMilestone, removeMilestone,
setModus, setPhase, addPhaseGate, phaseGates,
addStatus, statusHistory, listArchived
lead list, byId, forProject, create, update, addContact, removeContact,
addTouchpoint, removeTouchpoint, promoteToDeal, importCsv
risk forProject, create, update, remove
stakeholder forProject, create, update, remove
change forProject, create, update, remove
deal list, kpis, create, updateStage
gtm list, create, setStatus (kein UI, Phase 2)
campaign list, create, funnel, crosslink (kein UI, Phase 2)
blocker listOpen, byProject, create, resolve
dayEntry today, todayTeam, pendingCarryOver, checkIn, updateTodos,
editTodoTitle, addTodo, submitReflection, feed, todayPresence
time now, start, stop, listToday, update, upsertManual,
delete, teamToday
dashboard overview
Frontend importiert den Typ via import type { AppRouter } from '@cockpit/api/router' (siehe apps/web/src/lib/trpc.ts).
Procedure-Typen
publicProcedure— kein Auth-CheckprotectedProcedure— wirftUNAUTHORIZEDwennctx.user === null
Hinweis: dayEntryVisibleProcedure und projectOwnerProcedure waren ursprünglich geplant (siehe Architektur-Spec), sind aber implizit in den Routern erfüllt (z. B. blocker.resolve prüft P1 manuell).
Authentication
Produktion: Authentik OIDC
Der Code ist vollständig vorhanden — was fehlt sind die Authentik-seitigen Daten:
- Authentik-Admin legt Provider + Application an (siehe
docs/operations.md§ Authentik-Setup). - Client-ID/Secret/Issuer-URL fließen in
.env.production:AUTHENTIK_ISSUER=https://auth.tool-ctrl.de/application/o/everythingbutwork/ AUTHENTIK_CLIENT_ID=<von Authentik> AUTHENTIK_CLIENT_SECRET=<von Authentik> AUTHENTIK_REDIRECT_URI=https://everythingbutwork.tool-ctrl.de/api/auth/callback - Flow:
openid-client v6, Authorization Code + PKCE, Discovery via/.well-known/openid-configuration. Code:apps/api/src/auth/oidc.ts.
Bekannte offene Stelle (OQ-1): Der groups-Claim wird aus dem Token gelesen, aber noch nicht auf user.default_area_id gemappt. Heißt: neue User landen ohne Default-Bereich. Mapping kann später in auth/user.ts:upsertUserFromOidc ergänzt werden.
Dev: Auto-Login
Im NODE_ENV=development ist /api/auth/dev-login aktiv. Die Frontend-Login-Route (/login) redirected dort automatisch hin, sodass man nie eine Login-Seite sieht. Logik:
- Sucht den User mit
email = 'dejan@tool-ctrl.de'. - Existiert er nicht, wird er via
upsertUserFromOidcmitsub='local-dejan'angelegt. - Session wird gesetzt, Redirect auf
/dashboard.
In Production ist diese Route nicht registriert, weil die if (env.NODE_ENV === 'development')-Guard in apps/api/src/auth/routes.ts dann false ist.
Session-Modell
- Postgres-Tabelle
session(id, user_id, expires_at, ip_address, user_agent, created_at) - Cookie:
cockpit_session, HttpOnly + SameSite=Lax + (Securein Prod) - TTL: 24h (Env:
SESSION_TTL_HOURS) - Stop-condition: jedes Request läuft durch
auth/middleware.ts→getSessionWithUser(sessionId)→ setztreq.cockpitUser
Frontend-Architektur
Routing
React Router v7 (createBrowserRouter) — alle Routen sind Lazy (Code-Split per Route). Definition in apps/web/src/lib/router.tsx.
Login-Route ist außerhalb der AppShell (/login). Alle übrigen Routen unter / rendern die AppShell (TopNav + Main + Outlet + BlockerDialog).
State
- Server-State: ausschließlich React Query via tRPC (
createTRPCReact<AppRouter>). Konfig inapps/web/src/lib/trpc-provider.tsx(staleTime 0 → Daten werden bei Mount/Tab-Fokus neu geholt, kein Polling; ein Retry; zentrales onError → Toast). Mutationen invalidieren zusätzlich gezielt die gleichzeitig sichtbaren Sichten. - Auth-State: React Query
user.me(HookuseCurrentUser). - Lokaler UI-State:
useStatein der Komponente. Kein globaler Store.
Brand & Voice
- Logo: ToolCTRL-Emblem (
apps/web/public/toolctrl-emblem.svg) + Wordmarkeverythingbutwork. - Hausschrift: Space Grotesk (selbst gehostet in
apps/web/public/fonts/). - Buttons: Keycap-Stil (Gradient + Druckeffekt + Tastenkante) — siehe
apps/web/src/styles/globals.css§ Keycap-Buttons. - Mikrocopy: zentral in
apps/web/src/lib/voice.ts. Tonalität locker/direkt/deutsch (mit zwei englischen Lehnwörtern: „Lock in" und „Locked in" statt „Einstempeln/Eingestempelt"). - Ampel-Farben:
green=#15803d/#dcfce7,amber=#a16207/#fef3c7,red=#b91c1c/#fee2e2(UX-Spec § Visual Design Foundation).
Keyboard-Shortcuts
In apps/web/src/components/layout/AppShell.tsx:
g d Dashboard
g b Bereich (Default Entwicklung)
g e Entwicklung
g v Vertrieb
g m Marketing
g h Heute
g a Archiv
n Neuer Blocker
? Hilfe-Cheatsheet
Geteilte Logik (packages/shared)
Zod-Schemas + zugehörige TS-Types werden über @cockpit/shared re-exportiert. Beispiele:
import { DayEntrySchemas, TimeEntrySchemas, ProjectSchemas } from '@cockpit/shared';
// Im Backend (tRPC):
checkIn: protectedProcedure.input(DayEntrySchemas.checkInInput).mutation(...)
// Im Frontend (React Hook Form):
const resolver = zodResolver(TimeEntrySchemas.manualTimeEntryInput);
Konstanten (MAX_TODO_TEXT_LENGTH, WERKTAGE, JOURFIXE_DAY, REFLEXION_REMINDER_HOUR) in packages/shared/src/constants.ts.
Produktion / Deployment
Docker Compose
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 |
Env-Variablen werden über .env.production injiziert. Required: POSTGRES_PASSWORD, SESSION_COOKIE_SECRET (mind. 32 Z.), CRON_BEARER_TOKEN, AUTHENTIK_*.
Caddyfile
cockpit.tool-ctrl.deals Host (per${COCKPIT_HOST}overridbar) — wird beim nächsten Deploy aufeverythingbutwork.tool-ctrl.degesetzt/internal/*wird extern geblockt (403) — Cron-Endpunkte nur internes Netz/api/*und/trpc/*reverse-proxy zuapi:3000- Statischer Frontend-Content aus
/srv - Standard-Security-Header (HSTS, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
Cron im Postgres-Container
scripts/backup.sh läuft als System-Cron im Postgres-Container: tägliches pg_dump mit 14-Tage-Retention + Heartbeat an /internal/cron/pg-dump-backup für Audit.
CI & Auto-Deploy
.gitea/workflows/ci.yml:
quality → install, typecheck, lint, format:check, test
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
runMigrations()ausgeführt (Drizzle-Migrationen idempotent; schlägt eine fehl, startet die API nicht), dannensureBaseAreas()(legt die 4 Basis-Bereiche idempotent an, damit z. B. der „Neues Projekt"-Dropdown nie leer ist — auch auf einer nicht geseedeten Prod-DB).
Konventionen — Pflicht-Lesen vor Code-Edits
CONVENTIONS.md im Repo-Root. Zusammengefasst die wichtigsten Punkte:
- DB: Singular
snake_caseTabellen,idals UUID, FK<entity>_id, Enums alstext+ check. - tRPC: Procedure-Naming
<feature>.<verbNoun>(camelCase). Inputs immer Zod aus@cockpit/shared, niemals inline. - Errors:
TRPCErrormit deutschen menschenlesbaren Messages. Frontend zeigt sie via zentralem onError-Toast. - State: Server-State ausschließlich React Query — niemals
useStatefür Server-Loading. - Werktage/Zeit: Alle Datumslogik im Backend (
apps/api/src/lib/werktag.ts). Server-ZeitEurope/Berlin. - Sichtbarkeit: Heutige ToDos und Zeit sind teamweit sichtbar (Änderung gegenüber Original-PRD). Vortags-Reflexionen werden via Cron publiziert.
- No-Gos: kein Kanban, kein Steckbrief-Editor, kein Plane-Issue-Spiegel — die Wahrheit dieser Dinge lebt in Plane/Outline.
Was bewusst NICHT gebaut ist (Phase 2)
- Plane-/Outline-API-Sync — Cockpit verlinkt nur, hängt sich nichts ab
- Kanban-Pipeline / Deal-Funnel-UI —
gtm/campaignohne UI (Lead-CRM ist gebaut) - Reportings / Wochen-/Monatsauswertungen — bewusst minimal
- Reaktionen / Kommentare auf Tagesupdates
- Mobile schreibbar — Desktop-first, mobil nur lesbar
- Volltextsuche über Updates
- Kimai-Sync — Kimai läuft parallel ohne Bezug (eigener Pfad)
- Loki/Grafana, Sentry — pino → stdout reicht erstmal
- Authentik-Group → Bereich-Mapping (OQ-1, siehe Auth-Abschnitt)
Planungs-Artefakte
Vollständige PRD/Architektur/UX/Stories im _bmad-output/planning-artifacts/-Ordner. Diese Artefakte sind teilweise historisch (z. B. Kanban war ursprünglich geplant, ist aber inzwischen aus dem UI raus) — der Code ist die aktuelle Quelle der Wahrheit. Die Artefakte sind nützlich für:
- Hintergrund zur Methodik (ToolCTRL-Leitfaden v3.0)
- Entscheidungs-Log (
prds/prd-projectmanagement-2026-05-25/.decision-log.md) - 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 |
Repo & Remote
- Default-Branch:
main - Remote:
ssh://git@git.tool-ctrl.de:2222/toolctrl-labs/everythingbutwork.git(Gitea, non-standard SSH-Port) - Gitignore:
.env,node_modules,dist,_bmad/-Tools (Bmad-Framework),.claude/,ToolCTRL Brand Identity/(215 MB Raw-Assets)
Quick-Wins fürs nächste Modell / die nächste Session
- Sanity-Check vor jedem Edit:
git status, dann liesCONVENTIONS.md. - Schema ändern? → neue Drizzle-Migration generieren (
pnpm --filter @cockpit/db migrate:generate --name=<...>) und applien. NIEMALS direkt am DB-Snapshot rumdoktern. - Neuer tRPC-Endpoint? → Zod-Schema in
packages/shared/src/schemas/<feature>.ts, dann Procedure im passenden Router. Frontend importiert den Typ automatisch überAppRouter. - Englisch-Verbot in UI-Strings — Ausnahmen: „Lock in", „Locked in" (vom Owner so gewollt), Fachbegriffe wie „Kanban" (im Leitfaden gesetzt).
- Postgres-Port ist 55432, nicht 5432. Ports sind aus Kollisionsgründen so gewählt: API 7100, Web 7173, DB 55432.
- Dev-User:
dejan@tool-ctrl.de(Admin). Wird im Auto-Login angelegt falls nicht vorhanden. - Beim Bauen neuer Features: schau wie ähnliche Features umgesetzt sind (z. B. Time-Tracking als Vorbild für strukturähnliche Domain-Slices: Schema → Shared-Zod → Router → Frontend-Komponente).