Add architecture documentation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-01 11:08:54 -05:00
co-authored by Claude Opus 4.8
parent 22e59d6290
commit 5011c70414
+232
View File
@@ -0,0 +1,232 @@
# PQS — Player Queueing System
Documentation generated from a full read of the codebase (2026-07-01).
## 1. What this is
PQS is a **player queueing and mission-management system for a pod-based
mech-combat simulator** (Virtual World / BattleTech-style networked cockpits).
It is deployed at large venues to register, queue, and cycle several thousand
players through a fixed number of physical pods across a day.
The system runs entirely on an **air-gapped LAN**. There is no external
internet dependency and DB credentials (`pqs`/`pqs` on `localhost`) are a
formality of that closed network.
Branding strings in the code reference "FallOut Shelter" and "Cougar CON"
(the operator / an event); the sim itself is referred to as **FS** (the game
pods that consume `getFS*.php`).
## 2. Technology stack
| Layer | Technology |
|-------|-----------|
| Server | PHP (written for PHP 5.4/5.5, `mysqli` procedural API) |
| Database | MySQL 5.15.5, MyISAM/InnoDB mix (`pqs` schema) |
| Frontend | Static HTML + jQuery 1.x, AJAX polling via `setInterval` |
| Pod / kiosk hardware | Raspberry Pi running `omxplayer` for intro/trainer videos, GPIO buttons (`docs/omx_button.py`, `docs/get.py`) |
| Time sync | `time.php` shells out to `sudo date -s` to set box clock from a browser |
There is **no framework, no router, no build step, no dependency manager**.
Each `.php` file is a standalone page reached directly by URL. Shared logic
lives in `includes/`.
## 3. Physical / deployment topology
```
┌─────────────────────────────────────────┐
│ Air-gapped venue LAN (10.0.0.x) │
│ │
Players ─────▶│ Registration kiosk → callsign.php │
│ │
Staff ─────▶│ Reg console → registration.php │
Staff ─────▶│ Game/ops console → console.php │
│ │
Big TVs ─────▶│ Queue displays → combinedqueue.php │
│ smallcombinedqueue │
│ genconqueue.php │
│ │
Game pods ────▶│ Poll getFSgame.php (mission settings) │
(FS sim) │ Poll getFSplayers.php (roster/pods CSV) │
│ │
Pi video ────▶│ Poll playFSTrainer.php (missing file) │
│ → triggers omxplayer intro video │
└─────────────────────────────────────────┘
All → single PHP + MySQL host
```
## 4. Core domain model
The whole system revolves around **missions** (one pod launch) that fill up
with **players**, then get **committed** (launched) one at a time.
### Lifecycle of a mission
1. **Build** — missions are pre-created (`registration.php?build=N`) or created
on demand when a player registers and no open mission exists.
2. **Fill** — players self-register at `callsign.php` (kiosk) or staff add them
in `registration.php`. Each mission holds up to `MissionSize` players
(= number of active pods).
3. **Lock** — staff can lock a mission so no new players join
(`locked = 1`).
4. **Commit** — at `console.php` ("Commit Mission"), the lowest-numbered queued
mission's players are:
- copied into `pqs_currentmission` (who is in the pods right now),
- archived into `pqs_pastmissions` (history, with `ctime` timestamp),
- deleted from `pqs_queue`,
- the mission row marked `Completed = 1`.
5. **Display**`ctime` of the last commit + `timepergame + timetoreset`
drives every "ETD" (estimated departure) and countdown on the display walls.
### Group registration (squads)
`callsign.php` supports **Group Leader / Group Member** flows: a leader reserves
`N` slots in one mission, creating placeholder rows `LEADER-2`, `LEADER-3`…;
members later "claim" a placeholder by matching `CallSign LIKE 'who-%'`.
Gated by the `GroupAvalible` config flag.
## 5. Database schema (`docs/pqs.sql`)
| Table | Purpose |
|-------|---------|
| `pqs_queue` | Players currently waiting, keyed to a `MissionID`. Core working set. |
| `pqs_mission` | One row per mission: size, #players, completed/locked flags, gametype, map, time. |
| `pqs_currentmission` | Snapshot of who is in the pods for the mission that just launched. |
| `pqs_pastmissions` | Append-only history (callsign, mech, mission, `ctime`). Drives all ETD math. |
| `pqs_gameconfig` | Single-row global settings: pod count, time-per-game, weather, radar, friendly fire, etc. |
| `pqs_pods` | Single-row 16 booleans: which physical pods (`pod01`..`pod16`) are active. |
| `pqs_mechinfo` | Static catalog of ~63 mechs (class, tons, stats, roster #, image). |
| `pqs_mapinfo` | Static catalog of maps and which game types each supports. |
| `pqs_gametype` | Static catalog of the 10 game modes. |
| `pqs_infopanel` | Single `Updated` flag used to trigger display-wall ad rotation refresh. |
Notes:
- `pqs.sql` is the canonical schema; `dbbuild.sql` is an older SQLyog dump with
sample data.
- "Number of pods" is duplicated in three places (`pqs_gameconfig.numpods`,
the 16 booleans in `pqs_pods`, and each `pqs_mission.MissionSize`) and kept
in sync manually by `console.php` on every config save.
## 6. File-by-file reference
### Player-facing (kiosk)
- **`callsign.php`** — the player registration kiosk. 1024×768 themed screen:
enter callsign, pick class → mech, optional group role, submit. Inserts into
`pqs_queue`, auto-creating a mission if none is open. Shows the assigned
mission # and ETD, then returns to itself.
### Staff-facing
- **`registration.php`** — staff registration console. Add / edit / delete
players, add one player to multiple future missions, build missions in bulk,
edit a mission's game type & map, lock missions, search. Polls
`includes/getreg.php` every 1s.
- **`console.php`** — game-ops console. Sets global game configuration
(time limits, pods active, weather/radar/damage rules, etc. → `pqs_gameconfig`
+ `pqs_pods`), locks and **commits** missions. Polls `getconsole.php` +
`mechpods.php` every 2s.
- **`history.php`** — paginated per-mission history viewer (prev/next), reads
`pqs_pastmissions` joined to `pqs_mission`.
- **`search.php`** — look up a callsign across queued missions with ETDs.
- **`time.php`** — sets the server clock from the browser's JS time via
`sudo date -s` (keeps the air-gapped box's clock correct without NTP).
### Display walls (read-only, auto-refresh)
- **`combinedqueue.php`** — main wall: next mission + groups 25 + current pods
+ clock + rotating info panel. 10s refresh.
- **`smallcombinedqueue.php`** — compact version of the main wall (missions
15 + current pods + info panel), 5s refresh.
- **`genconqueue.php`** — "extended" wall showing missions 615 (further-out
queue). 30s refresh.
- **`combinedqueue2.php`** — mid-range wall showing missions 610 + current pods
+ clock + info panel, 10s refresh.
### Pod / hardware integration (plain-text output, no HTML)
- **`getFSgame.php`** — emits the next mission's settings as newline-delimited
values (gametype, map, visibility, weather, … cameraship) for the sim to read.
- **`getFSplayers.php`** — emits 16 CSV lines (one per pod slot):
`active,callsign,rosterNum,team,unit` — the pod loadout for the next mission.
- **`playFSTrainer.php`** — *referenced by `docs/get.py` but missing from the
repo*; was polled by a Raspberry Pi to trigger the trainer video.
### `includes/` (AJAX fragments & shared code)
- `config.php` — DB connect + load `pqs_gameconfig`/`pqs_pods` into `$_SESSION`.
- `getreg.php` / `getqueue.php` / `getconsole.php` / `getcurrent.php` /
`getgroup.php` — HTML fragments rendered into the consoles/walls via AJAX.
- `now.php` — clock + "estimated time remaining" for current mission.
- `mechpods.php` — echoes active pod count from session.
- `api.php` — tiny AJAX endpoint: toggle a player's "merc" flag, poll the
infopanel `Updated` flag.
- `infopanel.php` / `smallinfopanel.php` — rotating advertisement/announcement
slides (jQuery Cycle).
- `graph.php` — GD-generated progress-bar PNG (appears unused by current pages).
### `docs/` (assets & operator scratch)
- `pqs.sql`, `dbbuild.sql` — schema / seed dumps.
- `omx_button.py`, `get.py` — Raspberry Pi video-kiosk helper scripts.
- `Clear Code.txt` — the SQL to reset for a new event (truncate the 4 live tables).
- `readme screen adjust.txt`, `SQL_TCPip_Fixes.reg`, installer `.exe`s, `.mp4`
intro/roleplay videos, spare image sets.
## 7. Known issues, risks & technical debt
These matter most for the "improve vs. rewrite" decision.
**Correctness / concurrency**
- **No transactions or locking.** Filling a mission is a read-`numplayers`
compare → `UPDATE +1` sequence with no atomicity. With thousands of players
and a kiosk plus staff console writing concurrently, **race conditions can
overfill a pod bay** ("Containment Bay OVERLOADED" is literally a handled UI
state). `numplayers` is a manually-maintained counter that can drift from the
actual `COUNT(*)` in `pqs_queue`.
- Pod-count is denormalized across three tables and reconciled by hand.
**Security (mitigated only by the air gap)**
- **SQL injection is pervasive** — nearly every query interpolates `$_GET`/
`$_POST` directly (e.g. `console.php` `nummercs`, `api.php` `playerid`,
callsign fields). Safe *only* because the network is closed and trusted.
- `time.php` passes a request value into `exec("sudo date -s …")` — command
execution by design; would be dangerous on any reachable network.
- `api.php` and parts of `registration.php`/`console.php` still emit `DEBUG:`
output to the page.
**Maintainability**
- Presentation, business logic, and SQL are fully interleaved in every file;
connection boilerplate is copy-pasted dozens of times.
- Deprecated `mysql_error()` calls remain alongside `mysqli_*` (would fatal on
PHP 7+). The code targets an EOL PHP 5.x runtime.
- 16 pods are hard-coded as `pod01..pod16` everywhere (schema, console, FS
output) — changing pod count is a code edit, not config.
- Display refresh is fixed-interval full-fragment polling (no change detection
except the one infopanel flag).
- Inline `<font>` tags, table layouts, and absolute pixel sizes throughout.
**Runtime assumptions**
- Timezone hard-coded to `America/Chicago` in most files.
- URLs hard-coded to `/pqs/…` and to server IP via `$_SERVER['SERVER_ADDR']`.
## 8. Strengths worth preserving
- The **domain model is sound and battle-tested**: mission → fill → lock →
commit → history, with ETD projected from the last commit time. Any rewrite
should keep this exact lifecycle.
- It is **operationally simple**: drop PHP files on one box, point kiosks and
TVs at URLs. No build, no services to orchestrate — valuable at a venue.
- Feature set is complete for real events: group/squad reservations, per-mission
game/map overrides, merc tracking, bulk mission build, history, live walls,
and direct pod integration.
## 9. Improve vs. rewrite — starting point
If **improving in place**, the highest-value, lowest-risk fixes first:
1. Make mission-fill atomic (transaction + `SELECT … FOR UPDATE`, or derive
`numplayers` from `COUNT(*)`) to end overfill races.
2. Parameterize all queries (mysqli prepared statements) and remove `DEBUG:`
output.
3. Centralize DB access into one include; replace remaining `mysql_*` calls.
4. Make pod count and timezone configuration-driven, not hard-coded.
If **rewriting from scratch**, preserve section 4's lifecycle and section 5's
tables as the spec, and treat `getFSgame.php` / `getFSplayers.php` output
formats as a **hard contract** the physical pods depend on — document those
byte-for-byte before changing anything on the sim side.
```