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

8.9 KiB

Coding Conventions

Analysis Date: 2026-04-27

Naming Patterns

Files:

  • 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/)

Functions:

  • 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())

Variables:

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

Types:

  • 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

Formatting:

  • Prettier configured in server/.prettierrc with:
    • Single quotes (singleQuote: true)
    • Trailing commas on all (trailingComma: "all")
  • Line length: implicit (Prettier default ~80 chars but allows overflow)
  • Indentation: 2 spaces

Linting:

  • Client: ESLint 9 with flat config (eslint.config.js)
    • Uses TypeScript ESLint recommended rules
    • React Hooks plugin with recommended rules
    • React Refresh plugin for Vite
    • No custom strict rules beyond defaults
  • Server: ESLint 9 with flat config (eslint.config.mjs)
    • Uses TypeScript ESLint recommended rules with type checking (recommendedTypeChecked)
    • Prettier plugin for code formatting integration
    • Important: @typescript-eslint/no-explicit-any is turned OFF (line 29)
    • Warnings (not errors) for: no-floating-promises, no-unsafe-argument
    • Custom Prettier rule with endOfLine: "auto" for Windows compatibility

TypeScript:

  • Strict Mode Enforced on client (client/tsconfig.app.json):
    • "strict": true
    • "noUnusedLocals": true
    • "noUnusedParameters": true
    • "noFallthroughCasesInSwitch": true
    • "noUncheckedSideEffectImports": true
  • Server TypeScript (server/tsconfig.json):
    • "strictNullChecks": true
    • "forceConsistentCasingInFileNames": true
    • "noImplicitAny": false (allows any, soft enforcement)
    • "skipLibCheck": true (skips lib type checking)

Import Organization

Order: (observed pattern)

  1. React/Framework imports (react, react-router-dom)
  2. Third-party utilities (zustand, axios, socket.io-client)
  3. NestJS/Framework imports (@nestjs/*)
  4. Type-only imports (type { ... })
  5. Relative imports from shared (@/shared/..., @/features/...)
  6. Decorators and metadata (after other imports)

Path Aliases:

  • 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

Module exports:

  • 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

Philosophy (per CLAUDE.md): No shortcuts. Proper error handling, not try/catch with console.log.

Server-side (NestJS):

  • 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

Client-side (React):

  • 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

Socket.io (WebSocket Gateway):

  • Token validation on connection (throws client.disconnect())
  • Logger for all connection/disconnection events
  • Errors logged but don't crash server

Logging

Framework:

  • Server: NestJS Logger (in modules/gateways)
    • E.g., private logger = new Logger('CharactersGateway')
    • Used for connection events, warnings, errors
  • Client: console.error() for error debugging

Patterns:

  • Server logs connection events with user context
  • Client silently catches most errors, logs critical ones
  • No debug logging infrastructure in place

Comments

When to Comment:

  • 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")

JSDoc/TSDoc:

  • Minimal usage observed
  • API methods documented with Swagger decorators on server: @ApiOperation(), @ApiResponse()
  • No runtime JSDoc comments in source

Function Design

Size:

  • Modal components: 500-1700 lines (large, but feature-complete)
  • Service methods: 10-50 lines (concise, focused)
  • Utility functions: 5-20 lines

Parameters:

  • Interface-based: Pass objects instead of multiple params
    • E.g., onAdd(condition: { name: string; nameGerman: string; value?: number })
    • DTO pattern on server: CreateCharacterDto, LoginDto
  • Optional params with defaults: remember: boolean = false

Return Values:

  • 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

Exports:

  • Components export as named: export function HpControl() { ... }
  • Utilities export as named: export const api = new ApiClient()
  • One export per file (generally)

Barrel Files:

  • 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

Dependency Injection (Server):

  • NestJS @Injectable() decorator for services
  • Constructor injection: constructor(private prisma: PrismaService)
  • Circular dependencies resolved with @Inject(forwardRef()): seen in CharactersService

State Management

Client (Zustand):

  • 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

Server (NestJS):

  • No client state management needed
  • WebSocket gateway maintains connection map: connectedClients = new Map()

Design Tokens (UI)

Colors:

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

Typography:

  • Font sizes: sm, base, lg (Tailwind defaults)
  • Weights: normal, medium (600), semibold
  • All UI text in German except code/technical terms

Icons:

  • Lucide React exclusively (e.g., Heart, Swords, BookOpen, Package)
  • No emoji anywhere
  • Icon sizes: h-4 w-4 (standard), h-6 w-6 (large)

Touch Targets:

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

Spacing:

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

Responsive:

  • 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

Convention analysis: 2026-04-27