docs: map existing codebase

This commit is contained in:
2026-04-27 09:13:11 +02:00
parent 15dc0d289a
commit 3e91d5713d
7 changed files with 2237 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
# Architecture
**Analysis Date:** 2026-04-27
## Pattern Overview
**Overall:** NestJS modular backend + React feature-based frontend with real-time WebSocket synchronization
**Key Characteristics:**
- 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
**Backend: Controller Layer**
- 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:
- `server/src/modules/characters/characters.controller.ts` - Character CRUD
- `server/src/modules/campaigns/campaigns.controller.ts` - Campaign management
- `server/src/modules/equipment/equipment.controller.ts` - Equipment search/browse
- `server/src/modules/auth/auth.controller.ts` - Login/Register
**Backend: Service Layer**
- 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:
- `server/src/modules/characters/characters.service.ts` - Character operations, access checks
- `server/src/modules/characters/alchemy.service.ts` - Alchemy system logic (formulas, prepared items, vials)
- `server/src/modules/characters/pathbuilder-import.service.ts` - Pathbuilder JSON parsing
- `server/src/modules/equipment/equipment.service.ts` - Equipment search with filters
- `server/src/modules/battle/battle.service.ts` - Battle session and token management
**Backend: Gateway Layer (WebSocket)**
- 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:
- `server/src/modules/characters/characters.gateway.ts` - Character HP, conditions, items, alchemy real-time sync
- `server/src/modules/battle/battle.gateway.ts` - Battle token movement, HP, initiative real-time sync
**Backend: Persistence Layer**
- 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`
**Frontend: Feature Modules**
- Purpose: Isolated feature domains with components, hooks, types
- Location: `client/src/features/[feature]/`
- Contains: Components, hooks, index.ts barrel exports
- Examples:
- `client/src/features/auth/` - Login/Register pages, useAuthStore hook
- `client/src/features/characters/` - Character sheet page, modals, utilities
- `client/src/features/campaigns/` - Campaign list/detail pages
- `client/src/features/battle/` - Battle canvas, tokens
- `client/src/features/library/` - Battle maps, NPC templates (combatants)
**Frontend: Shared Layer**
- Purpose: Reusable components, hooks, utilities, types across features
- Location: `client/src/shared/`
- Contains:
- Components: `ui/` (shadcn/ui), `layout.tsx`, `protected-route.tsx`
- Hooks: `use-character-socket.ts`, `use-battle-socket.ts`
- Lib: `api.ts` (API client), `utils.ts` (helpers)
- Types: `index.ts` (all TypeScript interfaces)
- Used by: All features
**Frontend: Router**
- 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`
**Frontend: State Management**
- 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)
1. **User Action** (React Component)
- User damages character in `client/src/features/characters/components/hp-control.tsx`
- Calls `api.updateCharacterHp()` → PATCH `/campaigns/:id/characters/:id/hp`
2. **Controller** (`server/src/modules/characters/characters.controller.ts`)
- Receives HTTP request
- Validates JWT token via `JwtAuthGuard`
- Calls `CharactersService.updateHp()`
3. **Service** (`server/src/modules/characters/characters.service.ts`)
- Checks campaign access (GM or campaign member)
- Checks character ownership (owner or GM can edit)
- Updates character HP in Prisma
- Emits WebSocket event via `CharactersGateway.broadcast()`
4. **Gateway Broadcast** (`server/src/modules/characters/characters.gateway.ts`)
- Broadcasts `character_update` event to all clients in character room
- Update type: `'hp'`
- Payload: `{ hpCurrent, hpTemp, hpMax }`
5. **Client Socket Hook** (`client/src/shared/hooks/use-character-socket.ts`)
- Listens for `character_update` event
- Routes to appropriate callback: `onHpUpdate?.(data)`
- Component state updates via React state
6. **Component Re-render**
- Character sheet displays new HP values
- All other connected clients see update in real-time
### Equipment Database Search
1. **User Search** (React Component)
- User searches equipment in `client/src/features/characters/components/add-item-modal.tsx`
- Calls `api.searchEquipment({ query, category, filters, page, limit })`
2. **Controller** (`server/src/modules/equipment/equipment.controller.ts`)
- Receives GET `/equipment` with query params
- Calls `EquipmentService.search()`
3. **Service** (`server/src/modules/equipment/equipment.service.ts`)
- Builds Prisma where clause from filters
- Queries Equipment table (5,482 items)
- Returns paginated results with pagination metadata
- Includes category list for UI dropdown
4. **Component Display**
- Results displayed with pagination controls
- User can view equipment details, add to inventory
- New item created via `api.addCharacterItem()`
### Character Creation (Pathbuilder Import)
1. **User Upload** (React Component)
- User uploads Pathbuilder JSON in `client/src/features/characters/components/import-character-modal.tsx`
- Calls `api.importCharacterFromPathbuilder(pathbuilderJson)`
2. **Controller** (`server/src/modules/characters/characters.controller.ts`)
- POST `/campaigns/:id/characters/import`
- Calls `PathbuilderImportService.importCharacter()`
3. **Pathbuilder Import Service** (`server/src/modules/characters/pathbuilder-import.service.ts`)
- Parses Pathbuilder JSON structure
- Extracts abilities, skills, feats, spells
- Creates Character with all related entities (CharacterAbility, CharacterSkill, etc.)
- Stores raw pathbuilderData for future reference
4. **Database Persistence**
- Character created with all nested relations
- Each skill, feat, spell stored as separate records
- Character ready for real-time sync
### Battle Session Synchronization
1. **Token Movement** (React Component)
- User drags token on battle canvas
- Calls `api.moveBattleToken(positionX, positionY)`
2. **Battle Gateway** (`server/src/modules/battle/battle.gateway.ts`)
- Receives movement update
- Broadcasts `battle_update` event with type `'token_moved'`
- All clients in session room receive update
3. **Client Display**
- All participants see token at new position
- No UI lag — updates are instant
### Alchemy System State
1. **Prepare Items** (React Component)
- User selects formulas to prepare daily in `client/src/features/characters/components/alchemy-tab.tsx`
- Calls `api.dailyPreparation(items)`
2. **Alchemy Service** (`server/src/modules/characters/alchemy.service.ts`)
- Validates character has formulas
- Creates CharacterPreparedItem records
- Updates CharacterAlchemyState (versatileVialsCurrent, advancedAlchemyMax)
- Emits WebSocket `alchemy_prepared` and `alchemy_state` updates
3. **Real-Time Sync**
- UI updates showing prepared items and vial tracker
- Ready for combat use
## Key Abstractions
**Prisma ORM Service:**
- 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
**JWT Strategy & Guards:**
- Purpose: Authentication and authorization
- Location:
- `server/src/modules/auth/strategies/jwt.strategy.ts` - JWT validation
- `server/src/modules/auth/guards/jwt-auth.guard.ts` - Global auth enforcement
- `server/src/modules/auth/guards/roles.guard.ts` - Role-based access control
- Pattern: NestJS guards executed globally on every request
- Metadata: `@Roles()` and `@Public()` decorators control per-endpoint behavior
**API Client Service:**
- 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
**WebSocket Socket Manager:**
- 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
**Character/Battle Update Types:**
- Purpose: Type-safe event dispatch
- Location:
- `server/src/modules/characters/characters.gateway.ts` (CharacterUpdatePayload)
- `server/src/modules/battle/battle.gateway.ts` (BattleUpdatePayload)
- Pattern: Union types for event kind discrimination
## Entry Points
**Server Entry:**
- Location: `server/src/main.ts`
- Triggers: `npm run start:dev` or deployed container startup
- Responsibilities:
- Create NestJS app from AppModule
- Enable global pipes (ValidationPipe)
- Configure CORS from env
- Setup Swagger API docs at `/api/docs`
- Listen on PORT (default 5000)
**Client Entry:**
- Location: `client/src/main.tsx`
- Triggers: Browser page load or `npm run dev`
- Responsibilities:
- Render React app into #root DOM element
- Wrap with StrictMode
**Router:**
- Location: `client/src/App.tsx`
- Pattern: React Router v6 with protected routes
- Flow:
1. QueryClientProvider (React Query setup)
2. BrowserRouter (React Router)
3. AppContent checks auth state
4. Public routes: /login, /register
5. Protected routes: / (campaigns), /campaigns/:id, /campaigns/:id/characters/:characterId, /campaigns/:id/battle, /campaigns/:id/library
6. ProtectedRoute wrapper ensures authentication
## Error Handling
**Strategy:** Structured error responses with HTTP status codes
**Backend Patterns:**
- `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()`
**Frontend Patterns:**
- API client `response.interceptors` catches 401 → redirects to /login
- Components wrapped in error boundaries (future enhancement)
- Failed requests return rejected promises to component
**WebSocket Patterns:**
- 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
**Logging:**
- Backend: NestJS Logger class used in services/gateways
- Frontend: Console.log for development (socket.io events log connection state)
**Validation:**
- Backend: Global ValidationPipe with DTOs (class-validator)
- Frontend: Form validation in components (manual checks in modals)
- Prisma schema enforces constraints (NOT NULL, unique, enums)
**Authentication:**
- 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)
**Authorization:**
- Backend: RolesGuard checks @Roles() metadata
- Service methods verify campaign/character ownership before allowing operations
- Pattern: Check campaign membership → check character ownership → allow operation
**Real-Time Sync:**
- 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)
---
*Architecture analysis: 2026-04-27*