diff options
Diffstat (limited to 'CONTEXT.md')
| -rw-r--r-- | CONTEXT.md | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..6fefd53 --- /dev/null +++ b/CONTEXT.md | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | # Context | ||
| 2 | |||
| 3 | zagan-bet is a small play-money casino: one Rust workspace with a shared | ||
| 4 | library, a terminal client, a server, a desktop GUI and a browser frontend. This file names the things the code and the docs talk about. Keep it | ||
| 5 | current when a term changes meaning. | ||
| 6 | |||
| 7 | ## Product terms | ||
| 8 | |||
| 9 | - **Play credit** — the unit a player wins and loses. Registration grants a | ||
| 10 | starting balance. There are no deposits, withdrawals, cash-outs or KYC; the | ||
| 11 | web app is a game, not a regulated gambling service. | ||
| 12 | - **Server** — the authoritative process. It owns the database, the game | ||
| 13 | rules, the balances, the random draws and the clock used to settle crash. | ||
| 14 | - **Frontend** — a presentation adapter over `ClientCore`: the terminal client, | ||
| 15 | the egui desktop app, or the browser app behind the web gateway. Frontends | ||
| 16 | send `Command` values and render `View` values. They never compute payouts. | ||
| 17 | - **ClientCore** — the I/O-free state machine shared by every frontend. It owns | ||
| 18 | navigation, the current game view, the pending request, and the local clock | ||
| 19 | anchor for crash. It contains no terminal, network or egui types. | ||
| 20 | - **Gateway (`webd`)** — a server-side frontend adapter for the browser. It owns | ||
| 21 | one upstream TLS connection and one `ClientCore` per browser session, and | ||
| 22 | translates browser JSON into `Command`/`View`. The browser never speaks the | ||
| 23 | game wire protocol. | ||
| 24 | - **Upstream** — the game server the gateway connects to. Its address and SPKI | ||
| 25 | fingerprint are operator configuration. The browser never sees a certificate. | ||
| 26 | - **Session** — one browser login held by the gateway. Identified by an | ||
| 27 | HttpOnly cookie. A refresh or a new tab reattaches to the same session during | ||
| 28 | the grace window; a later visit starts a new login. | ||
| 29 | |||
| 30 | ## Wire terms | ||
| 31 | |||
| 32 | - **Frame** — `[u32 length][UTF-8 payload]`, length big-endian, at most 64 KiB. | ||
| 33 | The frame is the unit of transport; the payload is text. | ||
| 34 | - **Envelope** — the first token of a frame payload: | ||
| 35 | - `REQ <id> [idem=<token>] <command>` — client request. | ||
| 36 | - `RES <id> <body>` — the reply to that request. | ||
| 37 | - `EVT <seq> <body>` — a server-initiated event, numbered per connection. | ||
| 38 | - **Request id** — a client-chosen `u64`, unique on the connection while its | ||
| 39 | reply is cached. It correlates a reply with the request that caused it. | ||
| 40 | - **Idempotency key** — an optional opaque token on a request. The connection | ||
| 41 | caches the last 256 request ids; resending the same id and payload replays the | ||
| 42 | stored reply instead of performing the action twice. | ||
| 43 | - **Event sequence** — a server-chosen `u64`, incremented once per `EVT` on a | ||
| 44 | connection. Clients use it to drop duplicates and to notice gaps. | ||
| 45 | - **HELLO** — the first request after TLS. Client and server must share | ||
| 46 | `MAJOR.MINOR`; the reply carries the server version, download URL and the | ||
| 47 | server's Unix time in milliseconds. | ||
| 48 | - **Tick** — `EVT crash.tick session=<id> t=<server_ms> m=<multiplier>`, pushed | ||
| 49 | at most every 100 ms while a crash round runs. The server clock still settles | ||
| 50 | a cash-out. | ||
| 51 | - **Commit** — `sha256(seed)` in hex, sent with `CRASH_START` before the player | ||
| 52 | can act. **Reveal** — the seed itself, sent when the round ends. The crash | ||
| 53 | point is a pure function of the seed, so a player can check both. | ||
| 54 | |||
| 55 | ## Deployment terms | ||
| 56 | |||
| 57 | - **Download site** — `web/`: `index.php` lists builds, `latest.php` feeds the | ||
| 58 | stable installers, `install.sh`/`install.ps1` fetch and verify the newest app. | ||
| 59 | - **Play app** — the static browser bundle under `/play/`, built from | ||
| 60 | `web/play/` with esbuild and served by nginx. | ||
| 61 | - **Grace window** — the 60 seconds the gateway keeps an upstream connection | ||
| 62 | after the last browser socket closes. Reattaching within it preserves a live | ||
| 63 | round; expiry closes upstream and the server forfeits per its existing rule. | ||
| 64 | - **Takeover** — a new browser connection presenting an existing session cookie | ||
| 65 | replaces the old socket; the old tab is told it was replaced. | ||
| 66 | |||
| 67 | ## Invariants | ||
| 68 | |||
| 69 | - One payout formula, one place. `process_action` stores raw data; | ||
| 70 | `calculate_result` derives the result. Frontends only render. | ||
| 71 | - Every balance mutation is transactional, and an audit row exists before the | ||
| 72 | balance moves. | ||
| 73 | - A crash point never reaches a client before the round ends. | ||
| 74 | - The server clock, not a browser or gateway clock, settles cash-out. | ||
| 75 | - `MAJOR.MINOR` is lockstep between client and server; only the patch component | ||
| 76 | may differ. A wire change is a MAJOR bump. | ||
