593 lines
28 KiB
Markdown
593 lines
28 KiB
Markdown
# Dimension47 - TTRPG Campaign Management Platform
|
||
|
||
## Projekt-Philosophie
|
||
|
||
**Qualität vor Geschwindigkeit**: Es ist egal, wie lange die Implementierung dauert - das System soll am Ende gut funktionieren. Keine Shortcuts oder Quick-Fixes, die später Probleme verursachen.
|
||
|
||
**Lieber langsam und richtig**: Immer den sauberen Weg wählen, auch wenn er länger dauert. Beispiele:
|
||
- Prisma Migrations statt `db push` verwenden
|
||
- Daten in Datenbank statt direkt aus JSON-Dateien lesen
|
||
- Proper Error Handling statt try/catch mit console.log
|
||
- TypeScript strict mode, keine `any` Types
|
||
|
||
## Architektur-Entscheidungen
|
||
|
||
### Daten-Management
|
||
- **Equipment/Items in Datenbank**: Alle Pathfinder 2e Daten (Waffen, Rüstungen, Ausrüstung, Zauber, Talente) werden in die PostgreSQL-Datenbank importiert, NICHT direkt aus JSON-Dateien gelesen.
|
||
- **Prisma Seed Scripts**: JSON-Dateien werden via `prisma db seed` in die Datenbank importiert.
|
||
- **Übersetzungen gecacht**: Deutsche Übersetzungen werden on-demand via Claude API generiert und in der Translation-Tabelle gespeichert.
|
||
|
||
### Vorteile des Database-Ansatzes
|
||
- Bessere Such- und Filtermöglichkeiten
|
||
- Konsistente Datenstruktur
|
||
- Eigene Items können hinzugefügt werden
|
||
- Relationale Verknüpfungen möglich
|
||
- Performance durch Indizes
|
||
|
||
## Tech Stack
|
||
|
||
### Frontend
|
||
- React 19 + TypeScript
|
||
- Vite als Build Tool
|
||
- Tailwind CSS v4
|
||
- shadcn/ui Komponenten (selbst gebaut)
|
||
- Zustand für Client State
|
||
|
||
### Backend
|
||
- NestJS mit TypeScript
|
||
- Prisma ORM
|
||
- PostgreSQL
|
||
- JWT Authentication
|
||
- Socket.io für WebSockets
|
||
|
||
## Ordnerstruktur
|
||
|
||
```
|
||
dimension47/
|
||
├── client/ # React Frontend
|
||
│ ├── src/
|
||
│ │ ├── app/ # App-Config, Router
|
||
│ │ ├── features/ # Feature-Module (auth, campaigns, characters, etc.)
|
||
│ │ │ ├── auth/components/
|
||
│ │ │ │ ├── login-page.tsx # Login mit Animationen
|
||
│ │ │ │ └── register-page.tsx # Registrierung
|
||
│ │ │ └── characters/
|
||
│ │ │ ├── components/
|
||
│ │ │ │ ├── character-sheet-page.tsx # Hauptseite mit Tabs
|
||
│ │ │ │ ├── hp-control.tsx # HP-Management Komponente
|
||
│ │ │ │ ├── add-condition-modal.tsx # Zustand hinzufügen
|
||
│ │ │ │ ├── add-item-modal.tsx # Item aus DB hinzufügen
|
||
│ │ │ │ ├── actions-tab.tsx # Aktionen-Tab
|
||
│ │ │ │ ├── alchemy-tab.tsx # Alchemie-Tab
|
||
│ │ │ │ └── rest-modal.tsx # Rasten-Modal
|
||
│ │ │ └── utils/
|
||
│ │ │ └── export-character-html.ts # HTML-Export Funktion
|
||
│ │ ├── shared/ # Geteilte Komponenten, Hooks, Types
|
||
│ │ │ └── hooks/
|
||
│ │ │ └── use-character-socket.ts # WebSocket Hook für Echtzeit-Sync
|
||
│ │ └── assets/
|
||
│ └── public/ # Statische Dateien, JSON-Datenbanken
|
||
│
|
||
└── server/ # NestJS Backend
|
||
├── src/
|
||
│ ├── modules/ # Feature-Module
|
||
│ │ ├── auth/ # Authentifizierung
|
||
│ │ ├── campaigns/ # Kampagnenverwaltung
|
||
│ │ ├── characters/# Charakterverwaltung
|
||
│ │ │ ├── characters.gateway.ts # WebSocket Gateway
|
||
│ │ │ └── alchemy.service.ts # Alchemie-System Service
|
||
│ │ └── equipment/ # Equipment-Datenbank
|
||
│ ├── common/ # Shared Utilities
|
||
│ └── prisma/ # Prisma Service
|
||
└── prisma/
|
||
├── schema.prisma # Datenbank-Schema
|
||
├── migrations/ # Prisma Migrations
|
||
├── seed.ts # Basis-Seed
|
||
├── seed-equipment.ts # Equipment-Import (5.482 Items)
|
||
└── data/ # JSON-Quelldaten für Equipment
|
||
```
|
||
|
||
## Implementierte Features
|
||
|
||
### Auth
|
||
- JWT-basierte Authentifizierung
|
||
- Login/Register/Logout
|
||
- Rollen: ADMIN, GM, PLAYER
|
||
- **"Anmeldung speichern"** Funktion (localStorage vs sessionStorage)
|
||
- **Animierter Login-Screen**:
|
||
- Zweistufiger Flow: Splash → Formular
|
||
- Animierter Sternenhintergrund mit schwebenden Orbs
|
||
- "DIMENSION 47" Titel mit Buchstaben-Animation und Glow-Effekt
|
||
- Logo mit Tap-Glow-Effekt
|
||
- Gestaffelte Formular-Animationen (Komponente für Komponente)
|
||
|
||
### Kampagnen
|
||
- CRUD für Kampagnen
|
||
- Mitgliederverwaltung
|
||
- GM-Berechtigungen
|
||
|
||
### Charaktere
|
||
- Pathbuilder 2e Import
|
||
- HP-Management (mobile-optimiert, Schaden/Heilung/Direkt)
|
||
- Zustände (Conditions) mit PF2e-Datenbank
|
||
- Fertigkeiten mit deutschen Namen
|
||
- Rettungswürfe
|
||
- **Inventar-System (komplett)**:
|
||
- Vollständige Equipment-Datenbank (5.482 Items)
|
||
- Item-Suche mit Kategoriefilter und Pagination
|
||
- Bulk-Tracking mit Belastungs-Anzeige
|
||
- Ausrüstungsstatus (angelegt/abgelegt/investiert)
|
||
- Quantity-Management
|
||
- Item-Details mit Eigenschaften, Schaden, etc.
|
||
- Benutzerdefinierte Notizen pro Item
|
||
- **Talente-Tab (komplett)**:
|
||
- Alle Charaktertalente aus Pathbuilder-Import
|
||
- Kategorisiert nach Quelle (Klasse, Abstammung, Allgemein, Fertigkeit, Bonus, Archetyp)
|
||
- Einklappbare Kategorien
|
||
- Talentdetails mit Beschreibung und Voraussetzungen
|
||
- **Aktionen-Tab** mit PF2e-Aktionsdatenbank (99 Aktionen)
|
||
- Kategorien: Allgemein, Kampf, Bewegung, Interaktion, Spezial
|
||
- Einklappbare Kategorien (standardmäßig eingeklappt)
|
||
- Aktionstyp-Icons (Aktion, Reaktion, Freie Aktion, etc.)
|
||
- Suchfunktion
|
||
- **WebSocket Real-Time Sync** für:
|
||
- HP (aktuell, temporär, max)
|
||
- Zustände (hinzufügen, entfernen, aktualisieren)
|
||
- Inventar (Items hinzufügen, entfernen, aktualisieren)
|
||
- Ausrüstungsstatus (angelegt/abgelegt)
|
||
- Geld (Credits)
|
||
- Level
|
||
- Alchemie (Phiolen, Formeln, vorbereitete Items)
|
||
- **Alchemie-Tab (komplett)**:
|
||
- Vielseitige Phiolen mit Tracker
|
||
- Formelbuch mit allen bekannten Formeln
|
||
- Tägliche Vorbereitung (Advanced Alchemy)
|
||
- Schnelle Alchemie (Quick Alchemy)
|
||
- Handwerkliche Alchemie (Craft Alchemy)
|
||
- Forschungsgebiete (Bomber, Chirurg, Mutageniker, Toxikologe)
|
||
- Infundierte Items mit Effekt-Anzeige und Schadenswerten
|
||
- **Rest-System**:
|
||
- HP-Heilung basierend auf CON-Mod × Level
|
||
- Zustands-Management (Erschöpft entfernt, Verdammt/Entkräftet reduziert)
|
||
- Ressourcen-Reset (Zauberplätze, Fokuspunkte)
|
||
- Alchemie-Reset (infundierte Items verfallen, Phiolen aufgefüllt)
|
||
- **Status-Tab Erweiterungen**:
|
||
- Wahrnehmung mit korrekter PF2e-Berechnung
|
||
- Geschwindigkeit
|
||
- Rüstungsklasse mit Übungsstufe
|
||
- Rettungswürfe mit Übungsstufen
|
||
- **HTML-Export**:
|
||
- Vollständiger Charakterbogen als druckbare HTML-Datei
|
||
- Alle Attribute, Fertigkeiten, Talente, Ausrüstung
|
||
- Zauber und Alchemie (wenn vorhanden)
|
||
|
||
### Noch zu implementieren (Character Screen)
|
||
- **Level-Up System**: Stufenaufstieg mit Attributs-, Talent- und Fertigkeitenwahl
|
||
|
||
### Equipment-Datenbank
|
||
- **5.482 Items** aus Pathfinder 2e importiert
|
||
- Waffen mit Schaden, Schadentyp, Reichweite, Eigenschaften
|
||
- Rüstungen mit RK, DEX-Cap, Penalties
|
||
- Verbrauchsgüter und allgemeine Ausrüstung
|
||
- Durchsuchbar nach Name, Kategorie, Level, Eigenschaften
|
||
- API-Endpunkte: `/equipment`, `/equipment/categories`, `/equipment/weapons`, etc.
|
||
|
||
## Design-Prinzipien
|
||
|
||
- **Mobile-First**: Touch-optimiert mit 44px+ Touch-Targets
|
||
- **Dark Mode**: Primärfarbe #c26dbc (Magenta)
|
||
- **Deutsch**: Alle UI-Texte auf Deutsch
|
||
- **Keine Emojis**: Nur Lucide Icons
|
||
|
||
## Environment-Variablen
|
||
|
||
### Server (`server/.env`)
|
||
```bash
|
||
PORT=5000 # Server-Port
|
||
DATABASE_URL="postgresql://..." # PostgreSQL Connection String
|
||
JWT_SECRET="..." # JWT Signing Key
|
||
ANTHROPIC_API_KEY="..." # Claude API für Übersetzungen
|
||
```
|
||
|
||
### Client (`client/.env`)
|
||
```bash
|
||
VITE_API_URL=http://localhost:5000/api # Muss mit Server PORT übereinstimmen
|
||
```
|
||
|
||
**Wichtig**: Die WebSocket-URL wird automatisch aus `VITE_API_URL` abgeleitet (ohne `/api` Suffix).
|
||
|
||
Beispiel-Dateien: `server/.env.example` und `client/.env.example`
|
||
|
||
## Entwicklung
|
||
|
||
```bash
|
||
# Backend starten (Port 5000, konfigurierbar via PORT in .env)
|
||
cd server && npm run start:dev
|
||
|
||
# Frontend starten (Port 5173)
|
||
cd client && npm run dev
|
||
|
||
# Prisma Migrations (IMMER Migrations verwenden, NIEMALS db push!)
|
||
cd server && npm run db:migrate:dev # Neue Migration erstellen & anwenden
|
||
cd server && npm run db:migrate:deploy # Migrations in Produktion anwenden
|
||
cd server && npm run db:migrate:status # Status der Migrations prüfen
|
||
cd server && npm run db:migrate:reset # DB zurücksetzen (Dev only!)
|
||
|
||
# Prisma Sonstiges
|
||
cd server && npm run db:studio # DB Browser
|
||
cd server && npm run db:generate # Prisma Client generieren
|
||
cd server && npm run db:seed # Basis-Seed-Daten laden
|
||
cd server && npm run db:seed:equipment # Equipment-Datenbank laden
|
||
```
|
||
|
||
<!-- GSD:project-start source:PROJECT.md -->
|
||
## Project
|
||
|
||
**Dimension47**
|
||
|
||
Dimension47 ist eine selbst gehostete Web-App für Pathfinder-2e-Tischrunden auf Deutsch. Sie verwaltet Kampagnen, Charakterbögen mit komplettem PF2e-Regelumfang (HP, Zustände, Inventar, Talente, Aktionen, Alchemie) und stellt einen GM-Battle-Screen mit 3D-Druck-Tisch-Display bereit — alles in Echtzeit synchronisiert. Zielgruppe ist die eigene Spielgruppe, nicht die breite Öffentlichkeit.
|
||
|
||
**Core Value:** Am Tisch funktioniert alles in Echtzeit und regelkonform: Spieler lesen ihren Charakterbogen am Handy, der GM steuert vom Laptop aus den Battle-Screen, der eingelassene Tisch-Display zeigt die Spielsicht — ohne Reibung, ohne falsche Werte, ohne Reload.
|
||
|
||
### Constraints
|
||
|
||
- **Tech-Stack**: NestJS 11 + React 19 + Prisma 7 + PostgreSQL + Socket.io + Tailwind v4 — gesetzt durch Bestand, kein Stack-Wechsel sinnvoll
|
||
- **Sprache**: Deutsche UI durchgehend — alle neuen Texte ebenfalls Deutsch
|
||
- **Design**: Mobile-First für alle nutzerseitigen Screens (Charakterbogen, Vault-Browser, Würfler, Chat); Battle-GM-Screen darf desktop-fokussiert bleiben; Tisch-Display ist eigener Layout-Modus
|
||
- **Daten-Persistenz**: Alle PF2e-Daten gehören in die DB (Prisma-Seeds aus JSON), nichts wird zur Laufzeit aus JSON-Dateien gelesen
|
||
- **Migrationen**: Schema-Änderungen ausschließlich über `prisma migrate dev`, niemals `db push`
|
||
- **Code-Qualität**: TypeScript strict, keine `any`-Types, kein Quick-Fix der später wehtut
|
||
- **Hosting-Modell**: Self-hosted für eigene Spielgruppe — keine Multi-Tenant-/SaaS-Anforderungen
|
||
- **Push-Plattform**: Web Push (Service-Worker-basiert), kein FCM/APNs-Native-Wrapper
|
||
- **Vault-Endpoint**: Selbst-gehosteter Endpoint (vermutlich auf eigenem Server) — konkretes Protokoll wird in der Vault-Phase entschieden, nicht jetzt
|
||
<!-- GSD:project-end -->
|
||
|
||
<!-- GSD:stack-start source:codebase/STACK.md -->
|
||
## Technology Stack
|
||
|
||
## Languages
|
||
- TypeScript 5.9.3 (server), 5.7.3 (client) - Strict mode enabled, full type safety across codebase
|
||
- JavaScript (build outputs, scripts)
|
||
- HTML/CSS (frontend templates)
|
||
## Runtime
|
||
- Node.js (version not pinned, assumed LTS) - Used for both server and client dev/build
|
||
- ES2023 target (server), ES2022 target (client)
|
||
- npm - Lockfiles present for both client and server
|
||
## Frameworks
|
||
- React 19.2.0 - UI framework
|
||
- React Router DOM 7.12.0 - Client-side routing
|
||
- Vite 7.2.4 - Build tool and dev server
|
||
- NestJS 11.0.1 - Web framework with TypeScript-first design
|
||
- Express (via `@nestjs/platform-express`) - Underlying HTTP server
|
||
- Tailwind CSS 4.1.18 - Utility-first CSS framework
|
||
- `@tailwindcss/vite` plugin for Vite integration
|
||
- Jest 30.0.0 - Test runner (server-side only, configured in package.json)
|
||
- ts-jest - TypeScript support for Jest
|
||
- Supertest 7.0.0 - HTTP assertion library (server integration tests)
|
||
- @vitejs/plugin-react - React fast refresh for Vite
|
||
## Key Dependencies
|
||
- `@prisma/client` 7.2.0 - ORM and database abstraction layer
|
||
- `prisma` 7.2.0 - CLI and schema management tool
|
||
- `@anthropic-ai/sdk` 0.71.2 - Claude API for on-demand German translations
|
||
- `socket.io` 4.8.3 - WebSocket library for real-time communication
|
||
- `@nestjs/websockets` 11.1.12 - NestJS WebSocket integration
|
||
- `@nestjs/platform-socket.io` 11.1.12 - Socket.io adapter for NestJS
|
||
- `@nestjs/jwt` 11.0.2 - JWT authentication provider
|
||
- `@nestjs/passport` 11.0.5 - Passport.js integration for authentication
|
||
- `passport-jwt` 4.0.1 - JWT strategy for Passport
|
||
- `bcrypt` 6.0.0 - Password hashing
|
||
- `class-validator` 0.14.3 - Request DTO validation
|
||
- `class-transformer` 0.5.1 - DTO transformation
|
||
- `@nestjs/swagger` 11.2.5 - OpenAPI/Swagger documentation
|
||
- `@nestjs/config` 4.0.2 - Environment configuration management
|
||
- `dotenv` 17.2.3 - .env file loading
|
||
- `axios` 1.13.2 - HTTP client library for API requests
|
||
- `socket.io-client` 4.8.3 - WebSocket client for real-time updates
|
||
- `zustand` 5.0.10 - Client state management (auth store)
|
||
- `@tanstack/react-query` 5.90.19 - Server state and data fetching (caching, synchronization)
|
||
- `react-router-dom` 7.12.0 - Client-side routing
|
||
- `framer-motion` 12.26.2 - Animation library
|
||
- `lucide-react` 0.562.0 - Icon library (SVG icons)
|
||
- `clsx` 2.1.1 - Conditional CSS class utilities
|
||
- `tailwind-merge` 3.4.0 - Tailwind class merging utility
|
||
- `@nestjs/cli` 11.0.0 - NestJS code generation and project scaffolding
|
||
- `@nestjs/schematics` 11.0.0 - Code generators for NestJS
|
||
- `prettier` 3.4.2 - Code formatter
|
||
- `eslint` 9.18.0 - Linting
|
||
- `typescript-eslint` 8.20.0 - TypeScript ESLint support
|
||
- `tsx` 4.21.0 - TypeScript execution (used for seed scripts)
|
||
- `tsconfig-paths` 4.2.0 - TypeScript path alias resolution
|
||
- `ts-node` 10.9.2 - TypeScript REPL and script runner
|
||
- `ts-loader` 9.5.2 - TypeScript webpack loader
|
||
- `eslint` 9.39.1 - Linting
|
||
- `typescript-eslint` 8.46.4 - TypeScript ESLint support
|
||
- `eslint-plugin-react-hooks` 7.0.1 - React Hooks linting rules
|
||
- `eslint-plugin-react-refresh` 0.4.24 - Vite React refresh linting
|
||
## Configuration
|
||
- Server loads from `.env` file (see `.env.example`):
|
||
- Client loads from `.env` or `.env.local`:
|
||
- Server: `server/tsconfig.json` with target ES2023, decorators enabled
|
||
- Client: `client/tsconfig.app.json` with target ES2022, strict mode
|
||
- Client Vite config: `client/vite.config.ts`
|
||
- Server NestJS config: `server/nest-cli.json` (if exists)
|
||
## Platform Requirements
|
||
- Node.js LTS (tested with v22)
|
||
- npm (lockfiles version management)
|
||
- PostgreSQL 16+ (via Docker Compose)
|
||
- Docker & Docker Compose (for database)
|
||
- Git
|
||
- Node.js LTS
|
||
- PostgreSQL 16+ (managed service or self-hosted)
|
||
- Anthropic API key for translations (optional but recommended)
|
||
- File storage: Local filesystem or cloud storage (currently local via `./uploads`)
|
||
## Database
|
||
- Port 5432 (internal), 5433 (exposed for dev)
|
||
- Database name: `dimension47`
|
||
- Default credentials in docker-compose (dev only)
|
||
- pgAdmin 4 included for database management (port 5050)
|
||
- Schema: `server/prisma/schema.prisma`
|
||
- Generator: Prisma Client with CommonJS module format
|
||
- Adapter: `@prisma/adapter-pg` for optimized PostgreSQL queries
|
||
- Output: `src/generated/prisma/`
|
||
<!-- GSD:stack-end -->
|
||
|
||
<!-- GSD:conventions-start source:CONVENTIONS.md -->
|
||
## Conventions
|
||
|
||
## Naming Patterns
|
||
- Components: kebab-case (e.g., `character-sheet-page.tsx`, `add-condition-modal.tsx`, `hp-control.tsx`)
|
||
- Utilities/Services: kebab-case (e.g., `use-character-socket.ts`, `export-character-html.ts`)
|
||
- Directories: kebab-case (e.g., `features/`, `shared/`, `components/`)
|
||
- camelCase for all function names
|
||
- Hooks prefixed with `use` (e.g., `useAuthStore`, `useCharacterSocket`, `useMemo`, `useState`)
|
||
- Event handlers prefixed with `handle` (e.g., `handleApply`, `handleConnection`, `handleDisconnect`)
|
||
- Getter/setter methods follow camelCase (e.g., `getToken()`, `setToken()`)
|
||
- camelCase for all variable names
|
||
- Constants in UPPER_SNAKE_CASE (e.g., `PROFICIENCY_BONUS`, `SKILL_DATA`, `TABS`)
|
||
- Type unions with capitalized names (e.g., `CharacterType`, `AbilityType`, `TabType`)
|
||
- Boolean prefixes: `is`, `has`, `should`, `can` (e.g., `isLoading`, `isOwner`, `hasAccess`)
|
||
- PascalCase for all types, interfaces, and enums
|
||
- Domain types in shared: `Character`, `Campaign`, `User`, `CharacterItem`, `CharacterFeat`
|
||
- Props interfaces suffixed with `Props` (e.g., `HpControlProps`, `AddConditionModalProps`)
|
||
- DTO interfaces suffixed with `Dto` (e.g., `CreateCharacterDto`, `LoginDto`, `RegisterDto`)
|
||
- State types in Zustand: domain-specific (e.g., `AuthState`)
|
||
## Code Style
|
||
- Prettier configured in `server/.prettierrc` with:
|
||
- Line length: implicit (Prettier default ~80 chars but allows overflow)
|
||
- Indentation: 2 spaces
|
||
- Client: ESLint 9 with flat config (`eslint.config.js`)
|
||
- Server: ESLint 9 with flat config (`eslint.config.mjs`)
|
||
- **Strict Mode Enforced** on client (`client/tsconfig.app.json`):
|
||
- Server TypeScript (`server/tsconfig.json`):
|
||
## Import Organization
|
||
- Client: `@/*` → `./src/*` (defined in `vite.config.ts` and `tsconfig.app.json`)
|
||
- Server: No path alias configured; uses relative paths
|
||
- Always use `@/` prefix on client to avoid relative path hell
|
||
- Barrel files used: `features/*/index.ts`, `shared/components/ui/index.ts`
|
||
- Default exports on pages: `export default App`
|
||
- Named exports for utilities, types, hooks: `export { HpControl }`, `export const api = new ApiClient()`
|
||
## Error Handling
|
||
- Use NestJS exception classes: `NotFoundException`, `ForbiddenException`, `UnauthorizedException`, `ConflictException`
|
||
- Access checks before operations (e.g., `checkCampaignAccess()`, `checkCharacterAccess()` in `characters.service.ts`)
|
||
- Return meaningful error messages: "Campaign not found", "No access to this campaign"
|
||
- Prisma operations wrapped in try-catch only when necessary for data validation
|
||
- JWT verification throws exceptions through guard: `JwtAuthGuard` handles 401s
|
||
- Axios interceptors for request/response handling (in `api.ts`)
|
||
- 401 errors trigger logout and redirect to `/login` (except auth endpoints)
|
||
- Error state in components: `isLoading`, `error`, `pendingChange` states
|
||
- Modal operations: try/catch with `setIsLoading(false)` in finally block
|
||
- Error logging: `console.error()` for debugging, no silent failures
|
||
- User feedback: Navigation on error (`navigate()`) or via error state
|
||
- Token validation on connection (throws `client.disconnect()`)
|
||
- Logger for all connection/disconnection events
|
||
- Errors logged but don't crash server
|
||
## Logging
|
||
- Server: NestJS `Logger` (in modules/gateways)
|
||
- Client: `console.error()` for error debugging
|
||
- Server logs connection events with user context
|
||
- Client silently catches most errors, logs critical ones
|
||
- No debug logging infrastructure in place
|
||
## Comments
|
||
- Constants with unclear meaning (e.g., `PROFICIENCY_BONUS` values, skill-to-ability mappings)
|
||
- Complex calculations (e.g., HP percentage calculations)
|
||
- Business logic that isn't immediately obvious (e.g., Pathfinder 2e rules)
|
||
- NOT used for obvious code ("increment counter")
|
||
- Minimal usage observed
|
||
- API methods documented with Swagger decorators on server: `@ApiOperation()`, `@ApiResponse()`
|
||
- No runtime JSDoc comments in source
|
||
## Function Design
|
||
- Modal components: 500-1700 lines (large, but feature-complete)
|
||
- Service methods: 10-50 lines (concise, focused)
|
||
- Utility functions: 5-20 lines
|
||
- Interface-based: Pass objects instead of multiple params
|
||
- Optional params with defaults: `remember: boolean = false`
|
||
- Async functions return typed Promises: `async getCharacter(): Promise<Character>`
|
||
- Component callbacks: callbacks are async promises (`onHpChange: (newHp: number) => Promise<void>`)
|
||
- Services return full domain objects with relations included
|
||
## Module Design
|
||
- Components export as named: `export function HpControl() { ... }`
|
||
- Utilities export as named: `export const api = new ApiClient()`
|
||
- One export per file (generally)
|
||
- Used in features: `features/auth/index.ts` re-exports `useAuthStore`, `LoginPage`, `RegisterPage`
|
||
- Used for UI components: `shared/components/ui/index.ts` re-exports all buttons, cards, inputs
|
||
- Reduces import complexity
|
||
- NestJS @Injectable() decorator for services
|
||
- Constructor injection: `constructor(private prisma: PrismaService)`
|
||
- Circular dependencies resolved with @Inject(forwardRef()): seen in `CharactersService`
|
||
## State Management
|
||
- Single store pattern: `create<AuthState>()`
|
||
- Persisted state with middleware: `persist()`
|
||
- Partialize: stores only non-sensitive fields (`user`, `isAuthenticated`)
|
||
- Actions as methods in store: `login()`, `logout()`, `checkAuth()`
|
||
- Error state in store: `error: string | null`
|
||
- No client state management needed
|
||
- WebSocket gateway maintains connection map: `connectedClients = new Map()`
|
||
## Design Tokens (UI)
|
||
- Primary: Magenta `#c26dbc` (in Tailwind as `primary-500`, `primary-600`, etc.)
|
||
- Secondary: Dark grays for dark mode (`secondary-800`, `secondary-700`)
|
||
- Text: Primary (light), secondary (dimmer), tertiary (dimmest)
|
||
- Background: Primary, secondary, tertiary layers
|
||
- Error: Red (`error-500`, `error-600`)
|
||
- Success: Green (`green-500`)
|
||
- Warning: Yellow (`yellow-500`)
|
||
- Font sizes: sm, base, lg (Tailwind defaults)
|
||
- Weights: normal, medium (600), semibold
|
||
- All UI text in German except code/technical terms
|
||
- Lucide React exclusively (e.g., `Heart`, `Swords`, `BookOpen`, `Package`)
|
||
- No emoji anywhere
|
||
- Icon sizes: `h-4 w-4` (standard), `h-6 w-6` (large)
|
||
- Minimum 44px (mobile-first, accessible)
|
||
- Buttons: `h-11` (44px), `h-9` (36px for small), `h-12` (48px for large)
|
||
- Icon buttons: `h-11 w-11` (44x44px)
|
||
- Tailwind v4 defaults: `p-4`, `gap-2`, `rounded-lg`, `rounded-2xl`
|
||
- Modals: `rounded-t-2xl sm:rounded-2xl` (bottom sheet on mobile, centered on desktop)
|
||
- Mobile-first breakpoints: `sm:` prefix for tablet+ (e.g., `sm:items-center`, `sm:rounded-2xl`)
|
||
- Flexbox for layouts: `flex`, `flex-col`, `items-center`, `justify-between`
|
||
- Grid rarely used
|
||
<!-- GSD:conventions-end -->
|
||
|
||
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
|
||
## Architecture
|
||
|
||
## Pattern Overview
|
||
- Modular NestJS architecture with feature-based modules (Auth, Characters, Campaigns, Equipment, Battle)
|
||
- Feature-first React organization with shared components and hooks
|
||
- WebSocket Gateway real-time sync for character and battle state
|
||
- Role-based access control (ADMIN, GM, PLAYER) enforced globally
|
||
- Prisma ORM for PostgreSQL data persistence
|
||
- JWT-based stateless authentication
|
||
## Layers
|
||
- Purpose: HTTP request handling and routing
|
||
- Location: `server/src/modules/*/[feature].controller.ts`
|
||
- Contains: REST endpoints with decorators (@Post, @Get, @Put, @Patch, @Delete)
|
||
- Depends on: Services, DTOs, Guards, Decorators
|
||
- Used by: HTTP clients (React frontend)
|
||
- Examples:
|
||
- Purpose: Business logic, data processing, validation
|
||
- Location: `server/src/modules/*/[feature].service.ts`
|
||
- Contains: Methods for creating, updating, deleting entities; complex calculations
|
||
- Depends on: PrismaService, other Services, external APIs (Claude)
|
||
- Used by: Controllers, Gateways, other Services
|
||
- Examples:
|
||
- Purpose: Real-time bidirectional communication for live updates
|
||
- Location: `server/src/modules/*/[feature].gateway.ts`
|
||
- Contains: Socket.io event handlers, authentication, room management
|
||
- Depends on: JwtService, PrismaService, Services
|
||
- Used by: React WebSocket hooks
|
||
- Examples:
|
||
- Purpose: Database abstraction and ORM
|
||
- Location: `server/src/prisma/prisma.service.ts`
|
||
- Contains: Prisma client wrapper, query interface
|
||
- Depends on: PostgreSQL database
|
||
- Used by: All Services
|
||
- Data Models defined in: `server/prisma/schema.prisma`
|
||
- Purpose: Isolated feature domains with components, hooks, types
|
||
- Location: `client/src/features/[feature]/`
|
||
- Contains: Components, hooks, index.ts barrel exports
|
||
- Examples:
|
||
- Purpose: Reusable components, hooks, utilities, types across features
|
||
- Location: `client/src/shared/`
|
||
- Contains:
|
||
- Used by: All features
|
||
- Purpose: Navigation and route protection
|
||
- Location: `client/src/App.tsx`
|
||
- Contains: React Router v6 routes, protected route wrapper
|
||
- Depends on: React Router, Feature components
|
||
- Entry point: `client/src/main.tsx`
|
||
- Purpose: Client-side state persistence
|
||
- Location: `client/src/features/auth/hooks/use-auth-store.ts`
|
||
- Contains: Zustand store for authentication state
|
||
- Used by: Auth-related components, ProtectedRoute
|
||
## Data Flow
|
||
### Character Update (Real-Time WebSocket Sync)
|
||
### Equipment Database Search
|
||
### Character Creation (Pathbuilder Import)
|
||
### Battle Session Synchronization
|
||
### Alchemy System State
|
||
## Key Abstractions
|
||
- Purpose: Database abstraction, query builder
|
||
- Location: `server/src/prisma/prisma.service.ts`
|
||
- Pattern: Singleton service injected into all modules
|
||
- Used for: All CRUD operations, complex queries with relations
|
||
- Purpose: Authentication and authorization
|
||
- Location:
|
||
- Pattern: NestJS guards executed globally on every request
|
||
- Metadata: `@Roles()` and `@Public()` decorators control per-endpoint behavior
|
||
- Purpose: HTTP communication abstraction
|
||
- Location: `client/src/shared/lib/api.ts`
|
||
- Pattern: Singleton class with axios instance
|
||
- Features: Token management, auto-retry, auth interceptors, 401 handling
|
||
- Purpose: Prevent duplicate connections, manage subscriptions
|
||
- Location: `client/src/shared/hooks/use-character-socket.ts`
|
||
- Pattern: Global socket singleton with ref counting
|
||
- Features: Auto-reconnect, polling fallback, room subscription
|
||
- Purpose: Type-safe event dispatch
|
||
- Location:
|
||
- Pattern: Union types for event kind discrimination
|
||
## Entry Points
|
||
- Location: `server/src/main.ts`
|
||
- Triggers: `npm run start:dev` or deployed container startup
|
||
- Responsibilities:
|
||
- Location: `client/src/main.tsx`
|
||
- Triggers: Browser page load or `npm run dev`
|
||
- Responsibilities:
|
||
- Location: `client/src/App.tsx`
|
||
- Pattern: React Router v6 with protected routes
|
||
- Flow:
|
||
## Error Handling
|
||
- `NotFoundException` - 404 when entity not found
|
||
- `ForbiddenException` - 403 when user lacks permission
|
||
- `BadRequestException` - 400 for invalid input
|
||
- `UnauthorizedException` - 401 for auth failures
|
||
- Global error filter could be added for consistent formatting
|
||
- Service methods validate access before querying: `checkCampaignAccess()`, `checkCharacterAccess()`
|
||
- API client `response.interceptors` catches 401 → redirects to /login
|
||
- Components wrapped in error boundaries (future enhancement)
|
||
- Failed requests return rejected promises to component
|
||
- Token verification on connection → disconnect if invalid
|
||
- No structured error responses; silent failures with console logging
|
||
- Clients auto-reconnect via socket.io configuration
|
||
## Cross-Cutting Concerns
|
||
- Backend: NestJS Logger class used in services/gateways
|
||
- Frontend: Console.log for development (socket.io events log connection state)
|
||
- Backend: Global ValidationPipe with DTOs (class-validator)
|
||
- Frontend: Form validation in components (manual checks in modals)
|
||
- Prisma schema enforces constraints (NOT NULL, unique, enums)
|
||
- Backend: JwtAuthGuard applied globally in app.module.ts
|
||
- Endpoints opt-out via @Public() decorator
|
||
- WebSocket: Token verified in gateway.handleConnection()
|
||
- Frontend: Token stored in localStorage (persistent) or sessionStorage (session-only)
|
||
- Backend: RolesGuard checks @Roles() metadata
|
||
- Service methods verify campaign/character ownership before allowing operations
|
||
- Pattern: Check campaign membership → check character ownership → allow operation
|
||
- WebSocket Gateway manages rooms (one room per character/session)
|
||
- Clients join room on component mount, leave on unmount
|
||
- Broadcasts to all clients in room except sender (optional)
|
||
<!-- GSD:architecture-end -->
|
||
|
||
<!-- GSD:skills-start source:skills/ -->
|
||
## Project Skills
|
||
|
||
No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, or `.github/skills/` with a `SKILL.md` index file.
|
||
<!-- GSD:skills-end -->
|
||
|
||
<!-- GSD:workflow-start source:GSD defaults -->
|
||
## GSD Workflow Enforcement
|
||
|
||
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
|
||
|
||
Use these entry points:
|
||
- `/gsd-quick` for small fixes, doc updates, and ad-hoc tasks
|
||
- `/gsd-debug` for investigation and bug fixing
|
||
- `/gsd-execute-phase` for planned phase work
|
||
|
||
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
|
||
<!-- GSD:workflow-end -->
|
||
|
||
<!-- GSD:profile-start -->
|
||
## Developer Profile
|
||
|
||
> Profile not yet configured. Run `/gsd-profile-user` to generate your developer profile.
|
||
> This section is managed by `generate-claude-profile` -- do not edit manually.
|
||
<!-- GSD:profile-end -->
|