Files
product-fpol/README.md
T
khodowany 09d976e988
ci / frontend (push) Successful in 9m13s
ci / backend (push) Failing after 16m1s
Fix
2026-10-06 04:13:34 -05:00

99 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fantasy Politics
A private fantasy election game for friends, built in C++23 with the shared **Modulus**, **Ligo**, and **Noto/SQLite** libraries. The frontend uses TypeScript and Vite.
The app now has username/password accounts, invitation-based registration, private leagues, timed snake drafts, private queues, rosters, and provisional standings. The main navigation is **Leagues / Candidates / Results**. The earlier scoring simulator lives separately at `/lab.html`, with its APIs enabled only by `--allow-demo`.
**Real drafts remain locked.** The included official catalog has 115 candidates in 30 Michigan/North Carolina races. National candidate coverage, sourced ratings, and live count/outcome verification are still incomplete. League creation and invitations work before those data gates clear. There is no deployed site yet.
## Start locally
Use the sibling `modulus`, `noto`, and **updated `ligo`** checkouts in this workspace. This change extends Ligo's HTTP API; an older published `ligo/latest` package cannot build this app. The workspace helper exports the local recipes into your Conan cache and builds against those revisions, without publishing anything.
Prerequisites: a C++23 compiler (the configured target is GCC 12), CMake 3.25+, Ninja, Python 3, Conan 2.26.2, Node 22.12+, and network access for initial dependencies. CI uses Node 24.
```sh
conan profile detect # once, if you do not already have a profile
python3 tools/build_workspace.py
npm --prefix frontend ci
npm --prefix frontend run build
build/workspace_debug/fpol_admin import data/real/us-2026-10-04-partial.json
build/workspace_debug/fpol_admin create-user YOUR_USERNAME
# Password is prompted privately; use at least 12 characters.
build/workspace_debug/fpol_server --web-root frontend/dist
```
Open **http://127.0.0.1:8080**. The first account created through the local CLI is an administrator. Friends create accounts through private league invitations. All commands default to `var/fpol.sqlite`; use `--database PATH` consistently to select another database.
For Vite development, start the backend with `--origin http://127.0.0.1:5173`, then run `npm --prefix frontend run dev`. Use the exact configured origin, including hostname and port. For Vite preview use origin `http://127.0.0.1:4173`. Cookie security defaults suit loopback development; production uses HTTPS and `--secure-cookies`.
The existing Modulus workflow remains available once the matching Ligo package is in its Conan cache/remote:
```sh
python3 modulus.py configure --all
python3 modulus.py build --all
python3 modulus.py test --all
```
`modulus.py` remains byte-identical to the canonical bootstrap. Do not use `configure --update` to replace the local Ligo revision with an older published API. The [deployment guide](docs/deployment.md) describes a source-based Compose build that includes all four checkouts.
## Try a complete practice draft
```sh
build/workspace_debug/fpol_admin import data/demo/catalog.json data/demo/ratings.json \
data/demo/results-0.json data/demo/results-1.json data/demo/results-2.json \
data/demo/results-3.json data/demo/results-4.json
build/workspace_debug/fpol_server --web-root frontend/dist --allow-demo
```
Create a league and choose the **Practice** candidate pool. Invite a second player, then start from the draft room. Demo data stays explicitly separate from real data. The legacy simulator replays its five synthetic snapshots; those old snapshots are not automatically published as live league results.
## Rules
Leagues have 2–12 teams and 12 snake-draft rounds. Every team has Democrat, Republican, Other, and Flex slots for each of House, Senate, and Governor. A pick fills its party slot before Flex. Candidates are exclusive within a league; legal-pick checks preserve enough candidates for every remaining roster slot.
The server owns the 120-second clock. A timeout takes the first legal private-queue candidate, otherwise a uniformly random legal candidate. Commissioners can pause/resume. A process restart pauses active drafts; resuming gives the current picker a fresh 120 seconds. Browser draft views poll every 2 seconds; results and standings poll every 15 seconds.
`(November first-round / first-choice vote share percentage + 50 for the eventual called/certified winner) × frozen race rating`
Safe ×1, Likely ×1.1, Lean ×1.25, Toss-up ×1.5. Each candidate is rounded half up to two decimals before summing. Counts and outcomes are independent: a runoff changes the winner bonus while November share stays intact. Call retractions remove the bonus; corrections can lower points. Missing counts/ratings are unknown, not zero. Provisional rankings show reporting coverage beside known subtotals. Catalog, ratings, order, and rules freeze at draft start. Trades and waivers remain a later milestone.
## Election data and operations
The C++ `fpol_ingest` worker supports reviewed Open America count mappings, a normalized official-source JSON contract, candidate-source change capture, and a civicAPI capture/probe path. **civicAPI normalization is not implemented until a real response/schema has been validated.** No feed is configured or enabled automatically.
Changed raw payloads and normalized observations are immutable. Failed/ambiguous responses are quarantined; the last good counts remain visible with stale provenance. Replaying a file cannot verify a source or publish to a real catalog. Operators must obtain a successful live capture, review mappings, and explicitly activate coverage.
See [ingestion and source contracts](docs/ingestion.md), [source coverage](docs/data-coverage.md), the [506-contest inventory](data/contests_2026.json), and the [state/office coverage matrix](data/coverage_2026.csv). Official lists can change; review again before freezing. `tools/generate_real_catalog.py` reproduces the reviewed NC import and combined catalog; it does not fetch fresh evidence or claim a new review date.
Password recovery is operator assisted:
```sh
build/workspace_debug/fpol_admin reset-link USERNAME
```
Give that user `https://YOUR_HOST/#reset/TOKEN` using the returned token. It expires in 30 minutes, works once, and revokes all existing sessions on use. There is no email service. See [the API contract](docs/application-api.md) for session, CSRF, and request details.
## Verify
```sh
python3 tools/build_workspace.py --test
npm --prefix frontend run build
node tests/browser.mjs build/workspace_debug/fpol_server
python3 modulus.py format --check
```
The browser smoke test uses installed Chromium (`FPOL_CHROMIUM` can select a binary), Node's standard library, two isolated browser sessions, and the real C++ server. Screenshots go to ignored `build/browser-artifacts/`.
Socket-independent checks can be run separately:
```sh
python3 tests/test_core.py build/workspace_debug/fpol_admin
python3 tests/test_application.py build/workspace_debug/fpol_admin build/workspace_debug/fpol_ingest
```
They do not replace HTTP/browser checks. [The verification record](docs/verification.md) states exactly what ran here and what remains blocked. [Deployment and backup instructions](docs/deployment.md) cover persistent storage, Caddy HTTPS, bootstrap accounts, online backups, and restore.