Files
dotcom-arcade/CLAUDE.md
T
2026-01-28 19:21:02 +07:00

20 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Documentation-First Approach

IMPORTANT: This project has comprehensive documentation in the docs/ directory (100+ files). When handling requests:

  1. Use Documentation Instead of Context: Always reference the relevant documentation files instead of repeating information in responses. This prevents filling up context windows with redundant information.

  2. Point to Documentation: When answering questions, provide the path to the relevant documentation file (e.g., "See docs/04-frontend/architecture.md for details on frontend architecture").

  3. Read Documentation When Needed: Use the Read tool to check documentation files when you need specific information about:

    • Architecture: docs/02-architecture/
    • Backend: docs/03-backend/
    • Frontend: docs/04-frontend/
    • Game Service: docs/05-game-service/
    • API Reference: docs/06-api-reference/
    • Design System: docs/07-design-system/
    • Development: docs/08-development/
    • Deployment: docs/09-deployment/
    • Features: docs/10-features/
    • Diagrams: docs/11-diagrams/
    • Reference: docs/12-reference/
  4. Update Documentation After Changes: After completing any feature, enhancement, bug fix, or significant code change, ALWAYS ask the user:

    "I've completed the changes. Should I update the relevant documentation in the docs/ folder to reflect these changes?"

    Then update the appropriate documentation files to keep them in sync with the codebase.

Quick Documentation Reference

For Common Questions, Point Users/Read From:

Question Documentation File
How do I set up the project? docs/08-development/setup-guide.md
What commands are available? docs/08-development/commands.md
How does authentication work? docs/10-features/authentication-authorization.md
What are all the API endpoints? docs/06-api-reference/README.md
What's the database schema? docs/12-reference/database-schema-reference.md
How do components work? docs/04-frontend/components/component-overview.md
How do I deploy? docs/09-deployment/README.md
What's the architecture? docs/02-architecture/system-architecture.md
Design system/theming? docs/07-design-system/theme-system.md
Common errors/pitfalls? docs/08-development/common-pitfalls.md and "Common Pitfalls" section in CLAUDE.md
TypeScript types? docs/12-reference/type-definitions.md
Environment variables? docs/09-deployment/environment-variables.md
How to add new API endpoints? "Frontend API Guidelines" section in CLAUDE.md

Project Overview

Flashpoint Web is a self-hosted web application for browsing and playing games from the Flashpoint Archive. The project is a monorepo containing three independent services:

  • backend: REST API server (Express/TypeScript, port 3100)
  • frontend: React web UI (Vite/React/TypeScript, port 5173)
  • game-service: Game content proxy and ZIP server (Express/TypeScript, ports 22500/22501)

The architecture separates concerns: the backend handles game metadata and user management via SQLite databases, the game-service serves actual game files and handles proxying, and the frontend provides the user interface.

Development Commands

Monorepo (Root Level)

# Install all dependencies for all services
npm run install:all

# Start all services in development mode (concurrent)
npm run dev

# Start individual services
npm run dev:backend
npm run dev:frontend
npm run dev:game-service

# Build all services
npm run build

# TypeScript type checking across all services
npm run typecheck

# Clean all build artifacts and dependencies
npm run clean

Backend

cd backend

# Development server with hot reload (tsx)
npm run dev

# Build TypeScript to dist/
npm run build

# Run production build
npm start

# TypeScript type checking only
npm run typecheck

# Lint code
npm run lint

# Run tests (vitest)
npm test

Frontend

cd frontend

# Development server with HMR (Vite)
npm run dev

# Build for production (outputs to dist/)
npm run build

# Preview production build locally
npm run preview

# TypeScript type checking only
npm run typecheck

# Lint code
npm run lint

# Copy Ruffle emulator files to public/ (runs automatically on postinstall)
npm run copy-ruffle

Game Service

cd game-service

# Development server with hot reload
npm run dev

# Build TypeScript
npm run build

# Run production build
npm start

# TypeScript type checking
npm run typecheck

Docker

# Build all services
docker-compose build

# Start all services in background
docker-compose up -d

# View logs
docker-compose logs -f
docker-compose logs -f backend
docker-compose logs -f game-service
docker-compose logs -f frontend

# Stop all services
docker-compose down

# Rebuild and restart
docker-compose up -d --build

Set FLASHPOINT_HOST_PATH environment variable to point to your Flashpoint installation before running Docker commands.

Architecture

Backend Service (Port 3100)

The backend is a REST API built with Express and TypeScript. It manages two separate SQLite databases:

  1. Flashpoint Database (flashpoint.sqlite): Read-only access to the official Flashpoint game metadata database. The DatabaseService watches this file for changes and hot-reloads when the Flashpoint Launcher updates it.

  2. User Database (user.db): Application-specific database for user accounts, roles, permissions, playlists, favorites, play tracking, and authentication.

Key architectural patterns:

  • Service layer pattern: Business logic in src/services/, routes in src/routes/
  • JWT-based authentication with role-based access control (RBAC)
  • File watching: Automatically detects changes to flashpoint.sqlite from the Flashpoint Launcher
  • Proxy delegation: Backend proxies game file requests to game-service instead of serving them directly

Important services:

  • DatabaseService: Manages connection to flashpoint.sqlite with hot-reload support
  • UserDatabaseService: Manages user.db with schema migrations
  • GameService: Game metadata queries from flashpoint.sqlite
  • AuthService: User authentication and JWT token management
  • PlayTrackingService: Tracks user play sessions with cleanup of abandoned sessions

Frontend Service (Port 5173)

React 18 single-page application using modern patterns:

Tech stack:

  • Vite for build tooling and dev server
  • React Router for routing
  • TanStack Query (React Query) for server state management
  • Zustand for client-side UI state
  • Tailwind CSS for styling
  • Ruffle emulator for Flash content

State management approach:

  • Server state (games, playlists, user data): TanStack Query with caching
  • UI state (sidebar visibility, view modes): Zustand stores
  • URL state (filters, search, pagination): React Router search params
  • Auth state: Zustand store (store/auth.ts) with localStorage persistence

Component organization:

  • components/: Reusable components organized by domain (auth, library, player, playlist, etc.)
  • views/: Top-level page components
  • lib/api.ts: Centralized API client with typed endpoints

Player implementation:

  • Flash games: Ruffle WebAssembly emulator embedded in iframe
  • HTML5 games: Served directly via game-service proxy
  • Animations: Separate view with same player infrastructure

Frontend API Guidelines:

CRITICAL: Always use the authenticated axios instance for backend API calls.

  • Centralized API client: All backend API calls MUST go through frontend/src/lib/api.ts
  • Never use raw fetch() for backend endpoints - it bypasses authentication
  • Axios interceptors: The api instance automatically adds Authorization: Bearer <token> headers
  • Pattern to follow: Create typed API methods in appropriate objects (e.g., gamesApi, authApi, githubApi)

Example (CORRECT):

// In frontend/src/lib/api.ts
export const githubApi = {
  getStarCount: async (): Promise<{ stars: number }> => {
    const { data } = await api.get<{ success: boolean; data: { stars: number } }>('/github/stars');
    return data.data;
  }
};

// In component
import { githubApi } from '@/lib/api';
const result = await githubApi.getStarCount(); // ✅ Authenticated

Example (WRONG):

// In component - DO NOT DO THIS
const response = await fetch('/api/github/stars'); // ❌ No authentication!

Why this matters:

  • Maintenance mode blocks unauthenticated requests with 503
  • Protected endpoints require JWT tokens
  • Axios interceptors handle token refresh automatically
  • Consistent error handling across all API calls

When adding new backend endpoints:

  1. Create the backend route in backend/src/routes/
  2. Add the typed API method to frontend/src/lib/api.ts
  3. Use the API method in components (never raw fetch())
  4. Test with maintenance mode enabled to ensure authentication works

Game Service (Ports 22500, 22501)

Independent Node.js service that replaces the original Go-based Flashpoint Game Server. Runs two HTTP servers:

  1. HTTP Proxy Server (22500): Serves legacy web content with fallback chain:

    • Local htdocs (D:/Flashpoint/Legacy/htdocs)
    • Game data directory
    • ZIP archives (via zip-manager)
    • External CDN fallback (infinity.flashpointarchive.org)
    • Local file cache for downloaded content
  2. GameZip Server (22501): Mounts and serves files from ZIP archives in Data/Games/ without extraction using node-stream-zip

Key features:

  • MIME type detection for 199+ file types
  • CORS headers for cross-domain game content
  • Streaming for large files
  • External CDN fallback with caching
  • File path normalization and URL decoding

Environment Configuration

Backend (.env)

Required variables:

FLASHPOINT_PATH=D:/Flashpoint
FLASHPOINT_DB_PATH=D:/Flashpoint/Data/flashpoint.sqlite
FLASHPOINT_HTDOCS_PATH=D:/Flashpoint/Legacy/htdocs
FLASHPOINT_IMAGES_PATH=D:/Flashpoint/Data/Images
FLASHPOINT_LOGOS_PATH=D:/Flashpoint/Data/Logos
FLASHPOINT_PLAYLISTS_PATH=D:/Flashpoint/Data/Playlists
FLASHPOINT_GAMES_PATH=D:/Flashpoint/Data/Games

# Game service URLs (separate service)
GAME_SERVICE_PROXY_URL=http://localhost:22500
GAME_SERVICE_GAMEZIP_URL=http://localhost:22501

# Frontend origin for CORS
CORS_ORIGIN=http://localhost:5173

Optional: JWTSECRET, REDIS_ENABLED, LOG_LEVEL, RATE_LIMIT*

See backend/.env.example for complete configuration options.

Game Service (.env)

PROXY_PORT=22500
GAMEZIPSERVER_PORT=22501
FLASHPOINT_PATH=D:/Flashpoint
FLASHPOINT_HTDOCS_PATH=D:/Flashpoint/Legacy/htdocs
FLASHPOINT_GAMES_PATH=D:/Flashpoint/Data/Games
EXTERNAL_FALLBACK_URLS=http://infinity.flashpointarchive.org/Flashpoint/Legacy/htdocs,http://infinity.unstable.life/Flashpoint/Legacy/htdocs/
LOG_LEVEL=info

Frontend

Environment variables are injected at build time via Vite:

VITE_API_URL=http://localhost:3100

Vite proxy configuration in vite.config.ts handles /api/* and /proxy/* routing to backend.

Database Schema

Flashpoint Database (flashpoint.sqlite)

Read-only database from Flashpoint project. Key tables:

  • game: Main game metadata (id, title, platform, library, developer, publisher, etc.)
  • platform: Gaming platforms
  • tag: Tags and categories
  • game_tags_tag: Many-to-many relationship between games and tags
  • playlist: User playlists
  • playlist_game: Playlist entries

Important: This database is managed by the Flashpoint Launcher. The backend watches for file changes and automatically reloads connections when updates occur.

User Database (user.db)

Application-specific SQLite database. Schema managed via migrations in backend/src/migrations/. Tables include:

  • users: User accounts with hashed passwords (bcrypt)
  • roles: RBAC roles (admin, moderator, user, guest)
  • role_permissions: Permissions assigned to roles
  • user_roles: User role assignments
  • user_playlists: User-created playlists
  • user_favorites: Favorited games per user
  • play_sessions: Game play tracking with duration, completion status
  • system_settings: Global system-wide configuration (auth, app, metadata, features, game, storage, rate limiting)

Migrations run automatically on server startup via UserDatabaseService.

Authentication & Authorization

The application uses JWT-based authentication with RBAC:

Auth flow:

  1. User logs in via /api/auth/login with username/password
  2. Backend validates credentials, returns JWT access token + refresh token
  3. Frontend stores tokens in localStorage and Zustand auth store
  4. All subsequent API requests include JWT in Authorization header
  5. Backend middleware validates JWT and checks permissions

Permission system:

  • Permissions are strings like "games.play", "playlists.create", "users.manage"
  • Roles bundle permissions together
  • ProtectedRoute component in frontend enforces permission requirements
  • Backend RBAC middleware validates permissions on protected endpoints

Guest mode:

  • Users can browse games without authentication
  • Playing games requires authentication and "games.play" permission

Maintenance mode:

  • Controlled via app.maintenance_mode setting in system_settings table
  • When enabled, blocks all non-admin users from accessing endpoints (returns 503)
  • Admin users identified by settings.update permission bypass maintenance mode
  • Minimal public paths always accessible: /health, /api/auth/login, /api/auth/refresh, /api/settings/public, /proxy/*
  • Implemented in backend/src/middleware/maintenanceMode.ts
  • Depends on softAuth middleware to populate req.user before checking permissions

Permission caching:

  • User permissions cached for 5 minutes via PermissionCache (in-memory)
  • Cache automatically invalidated when user roles or role permissions change
  • Cache cleared on server restart
  • Debug issues by checking backend logs for [Maintenance] entries

Testing

Backend includes vitest configuration. Run tests with:

cd backend
npm test

Frontend testing setup TBD.

Important Implementation Notes

Database Access Patterns

  • Never use write operations on flashpoint.sqlite - it's read-only
  • User database writes use prepared statements with transactions for data consistency
  • DatabaseService includes file watcher to detect external changes from Flashpoint Launcher
  • Use BetterSqlite3 synchronous API (not async wrapper) for better performance

Game File Serving

Game files are not served by the backend. The flow is:

  1. Frontend requests game launch data from backend
  2. Backend returns launch configuration pointing to game-service URLs
  3. Frontend creates player iframe pointing to game-service (port 22500)
  4. Game-service handles all file serving, proxying, and ZIP mounting

This separation prevents backend from blocking on large file transfers and allows independent scaling.

Ruffle Integration

Ruffle emulator files are copied from npm package to frontend/public/ruffle/ during npm install (postinstall hook). The player component loads Ruffle from /ruffle/ruffle.js and creates instances for Flash content.

Scale modes supported: exactfit, noborder, showall (default), noscale

Play Session Tracking

Play sessions have three states:

  1. Active: User is playing
  2. Completed: User finished normally
  3. Abandoned: Session older than 24 hours without completion

Background job runs every 6 hours to clean up abandoned sessions.

CORS Configuration

  • Backend CORS origin must match frontend URL
  • Game-service enables CORS for all origins (cross-domain game content)
  • Vite proxy handles development routing to avoid CORS issues

Common Pitfalls

  1. Flashpoint path not found: Verify FLASHPOINT_PATH in .env points to valid Flashpoint installation
  2. Database locked errors: Flashpoint Launcher may lock flashpoint.sqlite - close it before migrations
  3. Port conflicts: Ports 3100, 5173, 22500, 22501 must be available
  4. Game files not loading: Ensure game-service is running before backend
  5. JWT secret in production: Change default JWT_SECRET in production environments
  6. Ruffle files missing: Run npm run copy-ruffle in frontend if Ruffle doesn't load
  7. 503 errors in maintenance mode: If admin users get 503 errors, check if components are using raw fetch() instead of the authenticated api instance from lib/api.ts. The axios interceptors automatically add authentication headers.
  8. Unauthenticated API calls: Never use raw fetch() for backend API endpoints. Always add new endpoints to frontend/src/lib/api.ts and use the typed API methods. See "Frontend API Guidelines" section above.

Recent Changes & Lessons Learned

2026-01-28: Maintenance Mode Admin Bypass Fix

Issue: Admin users were getting 503 errors when accessing /api/github/stars while maintenance mode was enabled.

Root Cause: The GitHubButton component was using raw fetch() instead of the authenticated axios instance, so requests had no Authorization header. The maintenance mode middleware blocked these unauthenticated requests.

Fix:

  1. Added githubApi.getStarCount() method to frontend/src/lib/api.ts
  2. Updated GitHubButton.tsx to use the authenticated API method
  3. The axios instance automatically adds JWT token via request interceptor

Key Lesson: NEVER use raw fetch() for backend API calls. Always use the centralized api instance from lib/api.ts which handles authentication, token refresh, and error handling automatically.

Verification Steps Taken:

  1. Checked database - confirmed admin role has settings.update permission ✅
  2. Tested backend directly - confirmed maintenance mode allows admin access ✅
  3. Identified frontend was making unauthenticated requests ❌
  4. Fixed component to use authenticated axios instance ✅

Prevention: See "Frontend API Guidelines" section for the correct pattern. When adding new API endpoints, always:

  1. Add typed method to appropriate API object in lib/api.ts
  2. Import and use the API method in components
  3. Test with maintenance mode enabled

2026-01-28: Database Migration Consolidation

Change: Consolidated 16 separate migration files into 2 files:

  • 001_initialize_schema.sql: All table definitions
  • 002_seed_default_data.sql: All seed data (roles, permissions, settings)

Added: Migration registry system in bootstrap.sql to track applied migrations with checksums and execution times.

Benefits:

  • Cleaner migration directory
  • Industry-standard migration tracking (similar to Flyway, Knex)
  • Backward compatibility with existing databases
  • All archived migrations saved in migrations/archived/ for reference

Source Code References

  • Flashpoint Launcher source code: D:\Repositories\Community\launcher
  • Flashpoint Game Server: D:\Repositories\Community\FlashpointGameServer

Flashpoint App Reference: D:\FP_Data\Flashpoint

Documentation Maintenance

After ANY code change, always:

  1. Verify no build errors: npm run typecheck and npm run build
  2. Check if documentation needs updates
  3. Ask the user if relevant documentation should be updated
  4. Update the following docs as needed:
    • Architecture changes → docs/02-architecture/
    • New/modified API endpoints → docs/06-api-reference/
    • Database schema changes → docs/12-reference/database-schema-reference.md
    • New features → docs/10-features/
    • Component changes → docs/04-frontend/components/
    • Configuration changes → docs/03-backend/configuration.md or docs/09-deployment/environment-variables.md

Documentation is a first-class concern - keeping it current ensures the project remains maintainable.