# CODING_STANDARDS.md ## Language & style - Node 20+, CommonJS, `'use strict'` not needed in CJS modules but harmless. - 2-space indent, semicolons, single quotes, trailing commas in multiline literals. - `const` by default; `let` only if reassigned; never `var`. - Names: `camelCase` functions/vars, `PascalCase` classes, `UPPER_SNAKE` constants, `snake_case` DB columns. - Convert DB `snake_case` rows → `camelCase` objects at the service boundary (one small mapper per entity). - Functions do one thing and fit on a screen (< 40 lines). Early returns over deep nesting. - Comments explain *why*, not *what*. Add a one-line header comment to each file describing its purpose. ## Errors Create `src/utils/errors.js`: ```js class AppError extends Error { constructor(code, message, status = 400) { super(message); this.code = code; this.status = status; } } ``` - Services throw `AppError` for expected failures (`new AppError('INSUFFICIENT_ENERGY','Not enough energy.',422)`). - Routes use an async wrapper so thrown errors reach `errorHandler`: ```js const wrap = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); ``` - `errorHandler` maps `AppError` → envelope; `ZodError` → 400 `VALIDATION_ERROR`; anything else → 500 generic message + server log. ## Pure game code - `src/game/*` exports plain functions; no I/O; no `Date.now()`; no `Math.random()` — take `rng` / `nowMs` params. - Return new objects instead of mutating inputs. ## Database access - One prepared statement per query, created once at module load (or lazily cached), not inside loops. - Wrap multi-write operations in `db.transaction`. - Never `SELECT *` in services for public output; select what you return. ## Frontend JS - `public/js/api.js` exports a small `api(method, path, body)` wrapper that handles JSON, error envelope, and 401 → redirect to login. - DOM updates via `textContent` / `createElement`. No `innerHTML` with dynamic data. - One JS file per page + shared `api.js` and `ui.js` (toasts, formatting). - No global state beyond a single `state` object per page. ## Logging `src/utils/logger.js`: tiny wrapper over `console` with levels; silent in tests unless `LOG=1`. ## Dependencies Pinned in package.json via `npm install --save-exact`. No dependency without need (NOTES.md §2.3).