Files
Dimension-47/.planning/codebase/ARCHITECTURE.md

13 KiB

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
  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