A new README for the combined project with setup from the Flashpoint Ultimate torrent. New feature docs for streaming, proxy sign-in and game saves; deployment, upgrade and streaming READMEs updated for the single compose file; the project renamed throughout.
12 KiB
System Architecture
Overview
Dotcom Arcade is a monorepo containing 2 independent services: frontend (React UI) and backend (Express API with integrated game file serving). Services communicate via HTTP with clean separation of concerns. The backend handles metadata, authentication, business logic, and game file serving with hardened resource management (connection limits, stream cleanup, download concurrency limits).
Architecture Diagram
graph TB
subgraph "Client Layer"
Browser[Web Browser]
Ruffle[Ruffle Emulator]
end
subgraph "Frontend Service :5173"
React[React SPA]
Router[React Router]
Query[TanStack Query]
Zustand[Zustand Stores]
Vite[Vite Dev Server]
end
subgraph "Backend Service :3100"
Express[Express Server]
GameSvc[GameService]
UserSvc[UserService]
AuthSvc[AuthService]
PlaySvc[PlayTrackingService]
Middleware[Auth/RBAC/Logging]
ProxyHandler[Game Proxy Handler]
ZipManager[ZIP Manager]
GameRoutes[Game Routes<br/>/game-proxy/*<br/>/game-zip/*]
end
subgraph "Data Layer"
FlashpointDB[(flashpoint.sqlite<br/>READ-ONLY)]
UserDB[(user.db<br/>READ-WRITE)]
FileSystem[File System<br/>Games, Images, ZIPs]
end
subgraph "External Services"
CDN[Flashpoint CDN<br/>infinity.flashpointarchive.org]
end
Browser --> React
React --> Router
React --> Query
React --> Zustand
Query --> Express
Express --> Middleware
Middleware --> GameSvc
Middleware --> UserSvc
Middleware --> AuthSvc
Middleware --> PlaySvc
Express --> GameRoutes
GameSvc --> FlashpointDB
UserSvc --> UserDB
AuthSvc --> UserDB
PlaySvc --> UserDB
PlaySvc --> FlashpointDB
GameRoutes --> ProxyHandler
GameRoutes --> ZipManager
ProxyHandler --> FileSystem
ProxyHandler -.fallback.-> CDN
ZipManager --> FileSystem
React --> Ruffle
Ruffle -.loads.-> GameRoutes
Vite -.dev proxy.-> Express
style Browser fill:#e1f5ff
style React fill:#61dafb
style Express fill:#90ee90
style GameRoutes fill:#ffd700
style FlashpointDB fill:#ff9999
style UserDB fill:#ff9999
Services Overview
Frontend Service (Port 5173)
Purpose: React single-page application for user interface
Technology: React 18, TypeScript, Vite, React Router, TanStack Query, Zustand, Tailwind CSS, Ruffle
State Management:
- Server State (TanStack Query): Games, playlists, user data
- UI State (Zustand): Sidebar, view modes, auth state
- URL State (React Router): Search params, filters
- Local Storage: Auth tokens, preferences
Key Features: Game browsing, search, filtering, play tracking, favorites, playlists
Backend Service (Port 3100)
Purpose: REST API for metadata, authentication, and business logic
Technology: Express.js, TypeScript, BetterSqlite3, JWT, Bcrypt, Zod
Key Responsibilities:
- Game metadata queries
- User management and authentication
- Role-based access control (RBAC)
- Play session tracking
- Playlist management
- Database hot-reloading for Flashpoint Launcher updates
Databases:
- flashpoint.sqlite: Read-only with file watcher
- user.db: Read-write with schema migrations
Architecture Pattern: Routes → Middleware → Services → Databases
Backend Game Serving (Integrated)
Purpose: Game file serving and ZIP mounting (integrated into backend)
Game Proxy Routes (/game-proxy/*):
- Serves legacy web content with fallback chain:
- Local htdocs directory
- Game data directory
- ZIP archives
- External CDN fallback
- Local cache
- Permissive CORS headers for cross-origin game content
- Registered before auth/CORS middleware
- URL sanitization to prevent directory traversal attacks
Game ZIP Routes (/game-zip/*):
- Mounts and streams ZIP archives
- Zero-extraction design
- LRU cache (max 100, 30-min TTL)
- Auto-cleanup on eviction
- Integrated with backend service layer
- Supports background downloads from
gameDataSourcesinpreferences.json
Resource Management (server.ts):
keepAliveTimeout: 65s- Prevents idle connections from blockingheadersTimeout: 66s- Must exceed keepAliveTimeouttimeout: 120s- 2-minute max for any request (handles file streaming)maxConnections: 500- Prevents connection exhaustion- Stream cleanup on request completion
- Download concurrency limits (configured in preferences)
Data Flow
Request Processing Pipeline
graph LR
subgraph "Frontend"
Component[React Component]
Hook[Custom Hook]
API[API Client]
Store[Zustand Store]
end
subgraph "Backend"
Route[Express Route]
MW[Middleware]
Service[Service Layer]
end
subgraph "Database"
DB[(SQLite)]
end
Component --> Hook
Hook --> API
Hook --> Store
API --> Route
Route --> MW
MW --> Service
Service --> DB
DB -.data.-> Service
Service -.response.-> Route
Route -.response.-> API
API -.update.-> Hook
Hook -.render.-> Component
Frontend → Backend:
- User interaction triggers component action
- Custom hook calls API client
- API client adds JWT token via interceptor
- Axios sends HTTP request
- Vite proxy forwards to Express (development)
Backend Processing:
- Express route receives request
- Authentication middleware verifies JWT
- RBAC middleware checks permissions
- Activity logger records action
- Route handler validates request (Zod)
- Service layer executes business logic
- Database query returns data
- Response sent back to client
Frontend State Update:
- TanStack Query receives response
- Cache updated with new data
- Components re-render
- Optimistic updates for UX
Database Architecture
Flashpoint Database (flashpoint.sqlite)
Ownership: Flashpoint Launcher (external, read-only)
Hot-Reload: FileSystem watcher detects changes and reloads connection
Key Tables:
game: Game metadata (100,000+ entries)game_data: Game file paths and launch commandsplatform: Gaming platforms (Flash, HTML5, etc.)tag,game_tags_tag: Tags and relationshipsplaylist,playlist_game: Community playlists
User Database (user.db)
Ownership: Application-managed with migrations
Authentication & Authorization:
users: User accounts with hashed passwords (bcrypt)roles: RBAC roles (admin, moderator, user, guest)role_permissions: Role-permission mappingssystem_settings: Global configuration
User Features:
user_playlists: User-created playlistsuser_favorites: Favorited gamesuser_settings: User preferences
Play Tracking:
user_game_plays: Individual sessionsuser_game_stats: Per-game aggregatesuser_stats: Overall user stats
Activity Logging:
activity_logs: Audit trail
Security Architecture
Authentication
sequenceDiagram
participant Client
participant Backend
participant UserDB
Client->>Backend: POST /api/auth/login {username, password}
Backend->>UserDB: Query user by username
UserDB-->>Backend: User record
Backend->>Backend: Bcrypt compare password
Backend->>Backend: Generate JWT tokens
Backend-->>Client: {accessToken, refreshToken, user}
Client->>Client: Store in localStorage + Zustand
Access Token: Short-lived (15 minutes), contains user ID, role, permissions
Refresh Token: Long-lived (7 days), used to obtain new access token
Token Refresh: Axios interceptor handles 401 automatically
Authorization
Role-Based Access Control:
User → Role → Permissions → Resources
Default Roles:
admin: Full system accessmoderator: Content managementuser: Standard featuresguest: Read-only (if enabled)
Permission Format: resource.action (e.g., games.play, users.manage)
File System Architecture
D:/Flashpoint/
├── Data/
│ ├── flashpoint.sqlite # Game metadata
│ ├── Images/ # Screenshots
│ ├── Logos/ # Game logos
│ ├── Games/ # ZIP archives
│ │ └── {first-letter}/{gameId}.zip
│ └── Playlists/ # Playlist files
├── Legacy/
│ └── htdocs/ # Legacy web content
│ └── {domain}/{path}
└── Flashpoint.exe
Access Patterns:
- Images/Logos: Served by backend from file system
- Game Content: Delegated to game-service proxy
- ZIPs: Mounted by GameZip server on-demand
Scalability Considerations
Current: Single-Server Architecture
All services run on localhost with SQLite databases.
Performance Optimizations
- Frontend route-based lazy loading (38% bundle reduction)
- React.memo for component optimization (98% fewer re-renders)
- Backend LRU cache for ZIP mounts (prevents memory leaks)
- Backend request size limits (1MB max, DoS protection)
- Backend query result caching (5-minute TTL)
- In-process game file serving (no inter-service HTTP overhead)
- TanStack Query auto-polling (only when downloading, 2s interval)
- Entry index optimization for large game databases
- Connection pooling with timeouts
- Stream cleanup on request completion or error
- Background downloads don't block initial response
Scaling Strategies (Future)
Horizontal:
- Frontend: Static hosting on CDN (Vercel, Netlify)
- Backend: Multiple instances behind load balancer with shared file storage
Vertical:
- flashpoint.sqlite read replicas
- user.db: PostgreSQL/MySQL for better concurrency
- Redis for session storage and caching
- CDN for static game assets
Development vs Production
Development
Frontend: Vite dev server with HMR, proxy configuration, source maps
Backend: tsx watch mode, DEBUG logging, CORS enabled, SQLite WAL mode
Game Service: Node with tsx watch, verbose logging
Production
Frontend: Static build in dist/, minified, tree-shaken
Backend: Compiled TypeScript, INFO logging, rate limiting, environment-specific JWT secret
Game Service: Compiled TypeScript, structured logging, optimized concurrency
Error Handling
Frontend Error Boundaries:
<ErrorBoundary fallback={<ErrorPage />}>
<GameList />
</ErrorBoundary>
Backend:
class AppError extends Error {
constructor(
public statusCode: number,
message: string
) {}
}
app.use((err, req, res, next) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({ error: err.message });
}
logger.error(err);
res.status(500).json({ error: 'Internal server error' });
});
Graceful Degradation: Guest mode, CDN fallback, cached data, error toasts
Monitoring & Logging
Activity Logging: All significant user actions logged with userId, action, targetType, targetId, timestamp
Performance Metrics: Play session durations, API response times, database query performance
Log Levels:
DEBUG: DevelopmentINFO: Normal operationsWARN: Recoverable issuesERROR: Critical failures
Technology Rationale
TypeScript: Type safety, IDE support, refactoring, shared types, reduced runtime errors
BetterSqlite3: Synchronous API, performance, perfect for read-heavy workloads, WAL mode
TanStack Query: Automatic caching, invalidation, background refetching, optimistic updates
Monorepo: Shared types, coordinated development, single deployment, consistent tooling
Conclusion
Dotcom Arcade balances simplicity with scalability, maintaining clean separation of concerns between frontend UI and backend business logic. Game file serving is integrated into the backend, eliminating inter-service HTTP overhead while keeping the codebase maintainable and type-safe. The two-service design is straightforward to deploy and monitor while remaining extensible for future needs.