# 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 ``` ## 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 ## 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/` ## 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` - Component callbacks: callbacks are async promises (`onHpChange: (newHp: number) => Promise`) - 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()` - 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 ## 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) ## 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 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. ## 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.