28 KiB
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 pushverwenden - Daten in Datenbank statt direkt aus JSON-Dateien lesen
- Proper Error Handling statt try/catch mit console.log
- TypeScript strict mode, keine
anyTypes
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 seedin 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)
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)
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
# 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, niemalsdb 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/viteplugin 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/client7.2.0 - ORM and database abstraction layerprisma7.2.0 - CLI and schema management tool@anthropic-ai/sdk0.71.2 - Claude API for on-demand German translationssocket.io4.8.3 - WebSocket library for real-time communication@nestjs/websockets11.1.12 - NestJS WebSocket integration@nestjs/platform-socket.io11.1.12 - Socket.io adapter for NestJS@nestjs/jwt11.0.2 - JWT authentication provider@nestjs/passport11.0.5 - Passport.js integration for authenticationpassport-jwt4.0.1 - JWT strategy for Passportbcrypt6.0.0 - Password hashingclass-validator0.14.3 - Request DTO validationclass-transformer0.5.1 - DTO transformation@nestjs/swagger11.2.5 - OpenAPI/Swagger documentation@nestjs/config4.0.2 - Environment configuration managementdotenv17.2.3 - .env file loadingaxios1.13.2 - HTTP client library for API requestssocket.io-client4.8.3 - WebSocket client for real-time updateszustand5.0.10 - Client state management (auth store)@tanstack/react-query5.90.19 - Server state and data fetching (caching, synchronization)react-router-dom7.12.0 - Client-side routingframer-motion12.26.2 - Animation librarylucide-react0.562.0 - Icon library (SVG icons)clsx2.1.1 - Conditional CSS class utilitiestailwind-merge3.4.0 - Tailwind class merging utility@nestjs/cli11.0.0 - NestJS code generation and project scaffolding@nestjs/schematics11.0.0 - Code generators for NestJSprettier3.4.2 - Code formattereslint9.18.0 - Lintingtypescript-eslint8.20.0 - TypeScript ESLint supporttsx4.21.0 - TypeScript execution (used for seed scripts)tsconfig-paths4.2.0 - TypeScript path alias resolutionts-node10.9.2 - TypeScript REPL and script runnerts-loader9.5.2 - TypeScript webpack loadereslint9.39.1 - Lintingtypescript-eslint8.46.4 - TypeScript ESLint supporteslint-plugin-react-hooks7.0.1 - React Hooks linting ruleseslint-plugin-react-refresh0.4.24 - Vite React refresh linting
Configuration
- Server loads from
.envfile (see.env.example): - Client loads from
.envor.env.local: - Server:
server/tsconfig.jsonwith target ES2023, decorators enabled - Client:
client/tsconfig.app.jsonwith 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-pgfor 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/.prettierrcwith: - 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 invite.config.tsandtsconfig.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()incharacters.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:
JwtAuthGuardhandles 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,pendingChangestates - 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_BONUSvalues, 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.tsre-exportsuseAuthStore,LoginPage,RegisterPage - Used for UI components:
shared/components/ui/index.tsre-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 asprimary-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:devor 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 foundForbiddenException- 403 when user lacks permissionBadRequestException- 400 for invalid inputUnauthorizedException- 401 for auth failures- Global error filter could be added for consistent formatting
- Service methods validate access before querying:
checkCampaignAccess(),checkCharacterAccess() - API client
response.interceptorscatches 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-quickfor small fixes, doc updates, and ad-hoc tasks/gsd-debugfor investigation and bug fixing/gsd-execute-phasefor 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-userto generate your developer profile. This section is managed bygenerate-claude-profile-- do not edit manually.