Files
2026-04-25 13:02:42 +02:00

4.6 KiB

CLAUDE.md

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

Project Overview

LA2 Eternal Portal is a web portal for a Lineage 2 private server. It consists of an Express API and a React SPA that manage website user accounts, link them to existing game server accounts, and display character data.

Architecture

This is a monorepo with two packages:

  • api/ — Express.js API server (TypeScript, Node 18+)
  • react-client/ — React SPA (Vite, TypeScript)

Dual Database Architecture

The API talks to two completely different databases:

  1. Portal Database (SQLite) — Stores website users, game account links, and cached character metadata. Accessed via Prisma ORM (api/prisma/schema.prisma). File path controlled by DATABASE_URL env var. This is the core database and is available in all environments.
  2. Game Server Databases (MSSQL) — External production-only database containing live Lineage 2 game server data. Not available in local development. Accessed via raw SQL through the mssql driver (api/src/services/gameServerService.ts) only when env vars are configured. Two connections:
    • lin2db — account and character tables
    • lin2world — builder_account table

Game server connection config lives in api/src/config/gameServer.ts and is read from env vars (GAME_SERVER_*, GAME_WORLD_*). Code that touches MSSQL should gracefully handle connection failures because the game server is not reachable outside production.

Auth Flow

  • Portal uses JWT (8h expiry). Token is generated on login, stored in localStorage, and sent via Authorization: Bearer header.
  • The API has two middleware functions in api/src/middleware/auth.ts: protectRoute (validates JWT) and adminOnly (checks role === 'ADMIN').
  • React auth state is managed by Zustand (react-client/src/hooks/useAuth.ts).

API Routing Structure

Route File Notes
/api/auth api/src/routes/auth.routes.ts login, register, me, link game account
/api/users api/src/routes/user.routes.ts user/character CRUD (Prisma/SQLite)
/api/admin api/src/routes/admin.routes.ts admin-only user management
/api/characters api/src/routes/characters.routes.ts character routes (mostly stub)

Business logic for game server DB operations is in api/src/services/gameServerService.ts. Business logic for portal DB operations is split between api/src/controllers/auth.controller.ts and api/src/controllers/user.controller.ts.

Commands

All commands are run from the respective package directory (api/ or react-client/).

API (cd api/)

npm run dev        # Start dev server with tsx watch (port 3001)
npm run build      # Compile TypeScript to ./dist
npm run start      # Run compiled JS (production)
npm run migrate    # Run Prisma migrations

React Client (cd react-client/)

npm run dev        # Start Vite dev server (port 5173)
npm run build      # Type-check and build for production
npm run preview    # Preview production build locally

Note: npm run lint is defined in react-client/package.json but ESLint is not actually installed/configured in the current lockfile.

Docker (from repo root)

docker compose build    # Build API and frontend images
docker compose up -d    # Start both services
docker compose logs -f api   # Tail API logs
docker compose logs -f react # Tail frontend logs

The API container runs tsx watch in development. The React container is a multi-stage build that compiles the SPA and serves it via nginx.

Important Files

  • api/prisma/schema.prisma — Portal DB schema (SQLite). Models: WebsiteAccount, GameAccount, GameCharacter.
  • api/src/config/gameServer.ts — MSSQL connection config and server metadata.
  • react-client/vite.config.ts — Vite config with path alias @/ pointing to src/ and a dev proxy for /api to localhost:3001.
  • .env.example — Required environment variables for local development.

Code Patterns

  • Controllers are inconsistent in style: some export plain async functions (auth.controller.ts), others export a controller object (user.controller.ts). Prefer plain async functions for new code.
  • MSSQL queries use template strings with parameterized inputs via .input(). Never interpolate user values directly into query strings.
  • Passwords for the game server are stored as plain binary (Buffer.from(password)) in the user_auth table, not hashed.
  • The gameServerService.ts connection pools are lazily initialized module-level singletons. They reconnect automatically if the connection drops.