centuriaVillageDashboard — Core Architecture & Context

⚠️ STATUS: DISABLED (2026-09-04)

collect.ts (the interval that scraped b15 with the CENTURIA_SESSION cookie) has been deleted — no automated requests to b15.playcenturia.com are being made anymore. Reason: after building this, Valentino and Claude discussed how traceable this is (see below) and decided the account-detection risk wasn't worth it right now. He may revisit later.

What's still here: db.ts, site.ts, page.ts — the dashboard UI/API still work and will show whatever was last collected (a few real snapshots from 2026-09-04, including real resource/production numbers for village "8low"), but nothing new comes in until collect.ts is rebuilt and re-scheduled.

To resume later: re-create collect.ts (its last version is recoverable from this val's file history / version log even though it's deleted — ask Val Town or check list_files/version history), get a fresh PHPSESSID into CENTURIA_SESSION (the old one is likely stale by then anyway), and re-add a cron via write_interval_settings. Read the "Why this was disabled" section below again first — the underlying detection risk hasn't changed.

Why this was disabled: traceability

The PHPSESSID cookie is the account identity at the HTTP layer — any request bearing it is authenticated as Valentino's account server-side, indistinguishable from him personally making the request. Val Town does not provide anonymity; it only changes the network path:

  • Requests arrive from a Val Town datacenter IP instead of Valentino's normal IP — on the same session/account. If the game logs IPs per session, this reads as an anomaly (datacenter IP suddenly appearing on a residential account's session), not as cover.
  • The site sits behind Cloudflare (confirmed via response headers), which fingerprints connections below the HTTP layer (TLS handshake, HTTP/2 frame ordering) — this can't be disguised by setting a believable User-Agent.
  • Server-only fetch() calls skip all the ~190 subresource requests (CSS/JS/images) a real page load triggers, and land on a suspiciously regular clock (every 15 min) — both are typical bot signatures.

Bottom line: this was always fully attributable to Valentino's account, not just "traceable to Val Town." That's the reason it's off.

Original architecture (for reference / when resuming)

Live resource/production dashboard for Valentino's Centuria (b15.playcenturia.com) village "8low". Centuria has no bearer-token REST API (unlike apexGemTracker, which this val was originally remixed from) — it's a classic server-rendered Travian-engine game gated by a PHPSESSID session cookie, treated here as the "token" equivalent.

Data model (SQLite) — still present, still queryable

  • snapshots: one row per successful collect run — resource stocks (lumber/clay/iron/crop), production/hour, warehouse/granary capacity, gold. village_name doubles as village_id (single-village setup).
  • villages: reserved for multi-village support — never populated.
  • collect_log: one row per collect run regardless of outcome (ok / error / expired) — drives the dashboard's status banner.

Scraping details (from the deleted collect.ts, for when rebuilding)

Fetched /dorf1.php with Cookie: PHPSESSID=<CENTURIA_SESSION>, a realistic Chrome User-Agent/Accept/Accept-Language, parsed with deno_dom (NOT linkedom — linkedom@0.16.11 pulls in a canvas native binding unavailable in Val Town's runtime and crashes on import).

Selectors confirmed live on 2026-09-04 against Centuria build v0.6.25, and verified working against real data before being disabled:

  • #l1 / #l2 / #l3 / #l4 — lumber/clay/iron/crop stock
  • .production tr — rows of text like "Lumber: 24,225" (production/hour)
  • #stockBar — full resource bar text; warehouse/granary capacity parsed positionally (nums[0] = warehouse cap, nums[4] = granary cap) — confirmed correct against live data (240,000 / 720,000).
  • .coinGold — gold amount (never actually observed non-null in testing — worth re-checking selector when resuming)
  • #villageName input's value attribute — clean village name. (NOT #villageName's textContent — that pulls in population, loyalty, and an inline <script> for the rename form; this was a real bug caught and fixed during testing.)

Not built: building queue, troop counts/training queue, multi-village switching. Would need selectors from dorf2.php / build.php?id=30.

Web endpoints (site.ts) — still live, read-only

  • / — dashboard UI (page.ts), shows whatever's in the DB already
  • /api/latest, /api/history?limit=N, /api/log — JSON, read from SQLite only
  • /source — redirects to this val's code

Relationship to the Chrome-automation project

There's a separate, still-active scheduled task ("Centuria 8low: village check

  • Khopesh Warrior training", tracked in this Claude project's centuria-8low-automation.md doc) that uses the Claude-in-Chrome browser extension to click through gold-exchange and troop-training flows from Valentino's own machine/browser — different mechanism, different traceability profile (it's literally his browser, not a datacenter). Not affected by this val being disabled.

Environment

  • CENTURIA_SESSION: PHPSESSID cookie value. Still stored on this val even though nothing reads it anymore (collect.ts, the only consumer, is deleted). Fine to remove for hygiene, or leave for when resuming — it'll be stale by then regardless.