Skip to content

Latest commit

 

History

History
76 lines (46 loc) · 6.09 KB

File metadata and controls

76 lines (46 loc) · 6.09 KB

Project instructions

Token rules (always follow)

  • Before exploring the codebase, check if SESSION_NOTES.md exists and read it first. It contains the current state of the project.
  • Prefer searching (grep/glob) over reading entire files. Only read a full file if it is small or you actually need all of it.
  • When you need one function or class, read only that section of the file, not the whole file.
  • Never read: build output, log files, lock files (package-lock.json, poetry.lock), .git contents, node_modules, pycache, or any file over 1000 lines unless explicitly asked.
  • Do not re-read a file you already read this session unless it has changed.
  • Keep answers short. No summaries of what you just did unless asked.

Session habits

  • End of session: the user runs /wrapup and you update SESSION_NOTES.md.
  • Start of session: the user runs /warmup and you orient using SESSION_NOTES.md.

CLAUDE.md

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

What this is

The public companion website for DZSL — a native GTK4 DayZ server browser / mod manager for Linux (the desktop app lives separately at /mnt/Storage1tb/coding/DZSL). This repo is the marketing site and the owner-facing backend: a React SPA plus Cloudflare Pages Functions, deployed to Cloudflare Pages at dayzlinux.com.

Commands

# Full stack locally (THE important one): builds, then runs Pages Functions +
# KV on http://localhost:8788 so /api/* returns live data like production.
./start-server.sh

# UI only, hot reload, http://localhost:5173 — but /api/* routes DO NOT run.
./start-server.sh --dev      # == npm run dev

npm run build                # tsc -b && vite build (app only — see note below)
./deploy.sh                  # build + wrangler pages deploy --project-name dayzlinux

There is no test runner and no linter configured — don't go looking for one. Correctness is enforced by TypeScript strict (incl. noUnusedLocals/noUnusedParameters).

npm run build only type-checks/builds the app (src/). The Pages Functions in functions/ are compiled by Cloudflare at deploy time, so a type error there won't surface in npm run build. Always check them separately after editing:

npx tsc --noEmit -p functions/tsconfig.json

The one gotcha that bites everything

There are two runtimes: the React SPA (src/) and Cloudflare Pages Functions (functions/api/*). Under plain vite dev (port 5173) the /api/* routes don't exist — the SPA _redirects fallback serves index.html instead, so a fetch to /api/... returns HTML, not JSON. Every client data helper (src/lib/api.ts, auth.ts, owner.ts) defends against this by checking the response content-type and throwing a "run pages:dev" error. When you need live data or auth locally, use ./start-server.sh (port 8788), not --dev.

Architecture

Server list data flow. functions/api/servers.ts proxies the large (~20 MB) community feed from dayzsalauncher.com, edge-cached (cf: { cacheTtl }). That feed is shaped { result: [{ endpoint: { ip, port }, name, players, mods, ... }] }; src/lib/api.ts#fetchServers unwraps and flattens it into the flat GameServer[] the UI uses. functions/api/stats.ts aggregates totals from the same feed for the header stats bar. The browser intentionally shows only populated servers, busiest-first.

Owner auth + server ownership (the substantial subsystem). Server owners sign in with Steam OpenID 2.0 and claim their servers:

  • functions/_lib/ holds shared backend helpers. The _ prefix means Pages does not route these as endpoints; route files under functions/api/** import from them. Every function declares its bindings via Env from _lib/env.ts.
  • Login: _lib/steam.ts builds the OpenID redirect and, on callback, re-validates the assertion with Steam (check_authentication) before trusting the SteamID. Realm/return_to are derived from the live request origin, so it works on both localhost:8788 and production unchanged.
  • Sessions: opaque 256-bit random tokens (_lib/session.ts) stored in KV, set as an HttpOnly; Secure; SameSite=Lax cookie. No passwords are ever handled; only public Steam data (SteamID, persona, avatar) is stored. SameSite=Lax is the CSRF defense — there are no separate CSRF tokens.
  • Ownership = name-token verification (_lib/claims.ts, api/claims/*): claiming a server issues a DZSL-XXXXXXXX token; the owner pastes it into their live server name; claims/verify re-reads the feed and confirms it appears, then flips the claim to verified. Only then can they edit/promote the listing (api/listings/[key].ts, owner-checked).

KV is the only datastore (binding DZSL_KV). Key patterns: session:<token>, claim:<ip:port>, listing:<ip:port>, owner:<steamId> (index of an owner's server keys). Listing keys carry a colon, so dynamic routes URL-encode/decode the ip:port.

Frontend wiring. main.tsx wraps the router in <AuthProvider> (src/lib/AuthContext.tsx); useAuth() exposes { user, loading, refresh }. Routing is react-router v7 with a single Layout route (shared header/nav/footer/stats bar) wrapping page routes in App.tsx. The campfire ambience toggle lives in the shared Layout header on purpose, so audio persists across page navigation (procedural + sampled audio in src/lib/campfire.ts).

Provisioning / config (needed for the API + auth in production)

  • KV namespace: npx wrangler kv namespace create DZSL_KV, then paste its id into wrangler.toml. Local pages dev simulates KV on disk under .wrangler/ regardless of the id.
  • Steam Web API key (optional — only adds persona name + avatar; login works without it): npx wrangler pages secret put STEAM_API_KEY for production, and STEAM_API_KEY=... in .dev.vars (gitignored; see .dev.vars.example) for local.

Deploy notes

Deploys go to the Cloudflare Pages project dayzlinux (custom domain dayzlinux.com, plus dayzlinux.pages.dev). Bindings (DZSL_KV) and compatibility_date come from wrangler.toml. Commit/push and deploy only when explicitly asked.