docs: vollständige README für neue Sessions / Modell-Wechsel
ci / quality (push) Has been cancelled
ci / build (push) Has been cancelled

Dokumentiert den aktuellen Code-Stand: was die App tut, Tech-Stack,
Verzeichnisstruktur, Dev-Setup (Ports 7173/7100/55432), DB-Tabellen,
tRPC-Routermap, Authentik vs Dev-Auto-Login, Frontend-Architektur,
Brand & Voice, Production-Deployment, Konventionen-Verweise und
Quick-Wins fürs nächste Modell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.7 committed 2026-06-02 17:39:54 +02:00
1 parent 95beb99cd4
commit 4879556905
1 file changed
+415 -26
+415 -26
View File
@@ -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/<slug>`) | 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=<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/<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 (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=<von Authentik>
AUTHENTIK_CLIENT_SECRET=<von Authentik>
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<AppRouter>`). 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 `<entity>_id`, Enums als `text` + check.
- **tRPC**: Procedure-Naming `<feature>.<verbNoun>` (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/<feature>.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).