diff --git a/README.md b/README.md index 487e50c..462d19c 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,433 @@ -# ToolCTRL everythingbutwork +# everythingbutwork -Internes Web-Tool zur täglichen Übersicht über alle Projekte und Bereiche. Ergänzt **Plane** (Tickets) und **Outline** (Doku) als drittes Werkzeug gemäß ToolCTRL Projektmanagement-Leitfaden v3.0. +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. -## Stack +> Falls du in dieses Repo neu reinrutschst (neue Session, anderes Modell): lies **`CONVENTIONS.md`** vor jedem Edit, und schau in **`_bmad-output/planning-artifacts/`** für den vollen PRD/Architektur/UX-/Stories-Kontext. -- **Frontend:** Vite + React 18 + TypeScript + Tailwind (kommt in Story 1.5) -- **Backend:** Fastify + tRPC v11 + Drizzle (kommt in Story 1.4 + 1.2) -- **DB:** Postgres 16+ (kommt in Story 1.2) -- **Auth:** Authentik OIDC (kommt in Story 1.3) -- **Hosting:** Docker + Caddy auf interner ToolCTRL-Infrastruktur +--- + +## Was die App tut + +| Bereich | Feature | +|---|---| +| **Puls** (`/puls`) | Unternehmens-Übersicht: Bereichs-Ampelstatus, „Heute fehlt"-Liste, bereichsübergreifende Blocker, Pflicht-Minimum-Übersicht, Jourfixe-Hinweis, „Heute im Team" (ToDos), „Zeit im Team heute" (Live-Tracking), Vortags-Feed | +| **Bereich** (`/bereich`, `/bereich/`) | Tab-Switcher über Entwicklung / Vertrieb / Marketing — pro Bereich Projekt-Liste (Kundenprojekte / Interne Projekte) mit Pflicht-Minimum-Indicator | +| **Projekt** (`/projekt/:id`) | Detail: Verlinkungen (Outline-Steckbrief, Plane-Board, Risikoliste), Pflicht-Minimum-Status, Meilenstein-Checkliste, DoD, Projekt-Abschluss (P1) | +| **Heute** (`/heute`) | Tagesrhythmus: Lock-in mit ToDo-Liste, Auto-Carryover offener ToDos vom Vortag, ToDo-Editor, Zeiterfassungs-Timeline mit Edit/Delete/Nachtrag | +| **Reflexion** (`/reflexion`) | Abend-Reflexion: ToDos abhaken, Freitext, Ampel + Trend, optional Blocker. Editierbar bis 00:00 Berlin | +| **Archiv** (`/archiv`) | Abgeschlossene Projekte, gruppiert nach Bereich | + +**Querschnittsfunktionen** + +- **Zeiterfassung**: Persistente Timer-Pill in der TopNav (Live-Sekundenzähler), Quick-Picker mit ToDos + Kategorien + Freitext, retroaktiver Nachtrag-Dialog, Bindung an ToDo optional. Personenübergreifend sichtbar auf dem Puls. +- **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, einer davon (Status-Ampel aktuell) wird stündlich per Cron aus den Reflexions-Zeitstempeln aktualisiert. +- **Streak**: aufeinanderfolgende Werktage mit voller Reflexion. Flammen-Pill rechts oben. +- **Keyboard-Shortcuts**: `g p/b/h/a` Navigation, `g e/v/m` direkt in Entwicklung/Vertrieb/Marketing, `n` Neuer 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 -│ └── api/ # Fastify Backend +│ ├── 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 +│ │ │ ├── routes/ puls, bereich, projekt, heute, reflexion, +│ │ │ │ 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), ampel, pflicht-minimum, logger +│ ├── routers/ _app, user, area, project, deal, gtm, +│ │ campaign, blocker, day-entry, time, puls +│ ├── 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 -│ └── shared/ # Zod-Schemas + Konstanten + Typen -├── _bmad-output/ # Planungs-Artefakte (PRD, Architektur, UX, Epics) -└── CONVENTIONS.md # Bindende Code-Konventionen (Pflicht-Lesen) +│ ├── db/ Drizzle-Schema + Migrationen +│ │ ├── src/{schema,client,seed,index}.ts +│ │ ├── migrations/ 0000_init … 0006_time_entry +│ │ └── drizzle.config.ts +│ └── shared/ Zod-Schemas + Konstanten + Types +│ └── src/schemas/ day-entry, project, deal, campaign, time-entry +├── _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 ``` -## Loslegen +--- + +## Lokal loslegen + +### Vorbereitung (einmalig) ```bash -pnpm install -pnpm --filter web dev # Frontend auf http://localhost:5173 -pnpm --filter api dev # Backend auf http://localhost:3000 -pnpm typecheck # Alle Workspaces typecheken -pnpm lint # ESLint -pnpm format # Prettier +# Repo & Tooling +pnpm install # 4 Workspaces installieren +cp .env.example .env # Defaults reichen für lokale Entwicklung ``` +### Dev-Stack starten + +```bash +# 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 + +**http://localhost:7173** + +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 + +```bash +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= # 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 0006) + +| 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 für jede mutierende Operation | +| `area` | Bereich (entwicklung / vertrieb / marketing / allgemein) | +| `project` | Projekt mit Cockpit-Sicht-Feldern (Outline-/Plane-URLs, Pflicht-Minimum-State JSONB, etc.) | +| `milestone` | Cockpit-Sicht-Meilenstein pro Projekt | +| `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 | +| `deal`, `gtm_step`, `campaign`, `lead_handover` | Im Schema vorhanden (Phase-2-Vorbereitung), **kein UI** mehr | +| `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/` | tRPC-Endpunkt (Batch + Stream) | +| `POST` | `/internal/cron/` | 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 (mit area), create, archive, + setMilestoneStatus, listArchived +deal list, kpis, create, updateStage (kein UI, Phase 2) +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, submitReflection, feed, todayPresence +time now, start, stop, listToday, update, upsertManual, + delete, teamToday +puls 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-Check +- `protectedProcedure` — wirft `UNAUTHORIZED` wenn `ctx.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: + +1. Authentik-Admin legt Provider + Application an (siehe `docs/operations.md` § Authentik-Setup). +2. Client-ID/Secret/Issuer-URL fließen in `.env.production`: + ``` + AUTHENTIK_ISSUER=https://auth.tool-ctrl.de/application/o/everythingbutwork/ + AUTHENTIK_CLIENT_ID= + AUTHENTIK_CLIENT_SECRET= + AUTHENTIK_REDIRECT_URI=https://everythingbutwork.tool-ctrl.de/api/auth/callback + ``` +3. 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 `upsertUserFromOidc` mit `sub='local-dejan'` angelegt. +- Session wird gesetzt, Redirect auf `/puls`. + +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 + (`Secure` in Prod) +- TTL: 24h (Env: `SESSION_TTL_HOURS`) +- Stop-condition: jedes Request läuft durch `auth/middleware.ts` → `getSessionWithUser(sessionId)` → setzt `req.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`). Konfig in `apps/web/src/lib/trpc-provider.tsx` (30 s staleTime, ein Retry, zentrales onError → Toast). +- **Auth-State**: React Query `user.me` (Hook `useCurrentUser`). +- **Lokaler UI-State**: `useState` in der Komponente. Kein globaler Store. + +### Brand & Voice + +- **Logo**: ToolCTRL-Emblem (`apps/web/public/toolctrl-emblem.svg`) + Wordmark `everythingbutwork`. +- **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 p Puls +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: + +```ts +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.de` als Host (per `${COCKPIT_HOST}` overridbar) — wird beim nächsten Deploy auf `everythingbutwork.tool-ctrl.de` gesetzt +- `/internal/*` wird **extern geblockt** (403) — Cron-Endpunkte nur internes Netz +- `/api/*` und `/trpc/*` reverse-proxy zu `api: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 + +`.gitea/workflows/ci.yml`: + +``` +quality → install, typecheck, lint, format:check, test +build → install, web build, api build (needs quality) +``` + +--- + +## Konventionen — Pflicht-Lesen vor Code-Edits + +**`CONVENTIONS.md`** im Repo-Root. Zusammengefasst die wichtigsten Punkte: + +- **DB**: Singular `snake_case` Tabellen, `id` als UUID, FK `_id`, Enums als `text` + check. +- **tRPC**: Procedure-Naming `.` (camelCase). Inputs **immer** Zod aus `@cockpit/shared`, niemals inline. +- **Errors**: `TRPCError` mit **deutschen** menschenlesbaren Messages. Frontend zeigt sie via zentralem onError-Toast. +- **State**: Server-State ausschließlich React Query — niemals `useState` für Server-Loading. +- **Werktage/Zeit**: Alle Datumslogik im Backend (`apps/api/src/lib/werktag.ts`). Server-Zeit `Europe/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 / Lead-Funnel-UI** — Schemas existieren, aber UI raus +- **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 -- [PRD](./_bmad-output/planning-artifacts/prds/prd-projectmanagement-2026-05-25/prd.md) — 49 Functional Requirements, 16 NFRs -- [Architektur](./_bmad-output/planning-artifacts/architecture.md) — Stack, Schnitt, Patterns -- [UX-Spec](./_bmad-output/planning-artifacts/ux-design-specification.md) — Brand-Tokens, Komponenten, User Journeys -- [Epics & Stories](./_bmad-output/planning-artifacts/epics.md) — 6 Epics, 32 Stories -- [Konventionen](./CONVENTIONS.md) — Naming, Struktur, Formate, Errors +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 + +1. **Sanity-Check vor jedem Edit**: `git status`, dann lies `CONVENTIONS.md`. +2. **Schema ändern?** → neue Drizzle-Migration generieren (`pnpm --filter @cockpit/db migrate:generate --name=<...>`) und applien. NIEMALS direkt am DB-Snapshot rumdoktern. +3. **Neuer tRPC-Endpoint?** → Zod-Schema in `packages/shared/src/schemas/.ts`, dann Procedure im passenden Router. Frontend importiert den Typ automatisch über `AppRouter`. +4. **Englisch-Verbot in UI-Strings** — Ausnahmen: „Lock in", „Locked in" (vom Owner so gewollt), Fachbegriffe wie „Kanban" (im Leitfaden gesetzt). +5. **Postgres-Port ist 55432, nicht 5432**. Ports sind aus Kollisionsgründen so gewählt: API 7100, Web 7173, DB 55432. +6. **Dev-User**: `dejan@tool-ctrl.de` (Admin). Wird im Auto-Login angelegt falls nicht vorhanden. +7. **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).