Files
2026-05-16 20:39:27 +02:00

85 lines
4.5 KiB
Markdown

# Penalty Tracker
A small, self-contained system for tracking competition penalties (e.g. for hot-air balloon competitions).
## Features
- **System Admin** can create competitions and manage all users.
- **Chief Scorer** (per competition) manages pilots, members, settings, and can export penalties as CSV. Chief Scorers can promote others to Chief Scorer or Scorer.
- **Scorer** (per competition) adds penalties. Scorers can only edit/delete their own entries unless the competition setting "allow any scorer to edit" is on.
- Pilots can be added manually or imported from CSV (`number,last_name,first_name,country,balloon_id`).
- Rule catalogues per language are loaded from `rules/*.csv`. The penalty form lets you search rules by number or text and shows the suggested penalty plus repeat-behaviour (same / doubled / escalates).
- All open clients receive **live updates** for a competition via WebSocket — works for 30+ concurrent users on a single SQLite process.
- The penalty table is **client-side sortable** by every column and updates **in-place without flicker** when new rows arrive.
- Multi-lingual UI: English, German, Polish, Russian, French, Spanish, Portuguese (set per user in user settings).
- Clean black / white design with `#2b6cb0` accent, max border-radius `0.375rem`.
## Build & run
```bash
go build -o penaltytracker .
./penaltytracker
```
Then open <http://localhost:8080>.
**Default login (created automatically on first start):**
```
username: admin
password: admin
```
Change the password immediately under the user menu.
## Configuration (env vars)
| Variable | Default | Description |
|-----------------|----------------------|--------------------------------------------------------------------------|
| `ADDR` | `:8080` | HTTP listen address |
| `DB_PATH` | `penaltytracker.db` | SQLite database path |
| `RULES_DIR` | `rules` | Directory containing per-language rule CSV files |
| `WEB_DIR` | `web` | Directory containing the frontend static files |
| `CORS_ORIGINS` | *(empty)* | Comma-separated allowed frontend origins (e.g. `http://127.0.0.1:36823,https://app.example.com`). When set, CORS headers are added. Use `*` to allow any origin. |
| `COOKIE_CROSS_SITE` | *(empty)* | Set to `true` only when the frontend runs on a different *site* (different registrable domain) than the API and you need cross-site cookies. Switches the session cookie to `SameSite=None; Secure` — requires HTTPS on both sides. Leave unset for same-host different-port setups (e.g. `127.0.0.1:36823 → 127.0.0.1:8080`); `SameSite=Lax` already works there. |
### Frontend backend URL
If you host the frontend on a different origin than the API, open the login screen and fill in **Backend URL** (e.g. `http://192.168.0.10:8080` or `https://api.example.com`). It is stored in `localStorage` (`api_base`). Leave it empty to use the same origin as the page. You can also pre-set it by editing `web/config.js` (`DEFAULT_API_BASE`).
Cross-origin cookies require **HTTPS on both sides** (so the `Secure` cookie flag is accepted). For LAN testing on plain HTTP, host the frontend and backend on the same origin (the default).
## Rules CSV format
`rules/<lang>.csv` — one file per language code (`en`, `de`, `pl`, `ru`, `fr`, `es`, `pt`).
```csv
rule_number,rule_text,suggested_penalty,escalation_mode
R1.1,Late at briefing,Warning,escalate:Warning|50 CP|100 CP|DSQ
R3.1,Unsafe flying,200 CP,doubled
R4.2,Incorrect declaration,No Result,same
```
`escalation_mode`:
- `same` — penalty stays the same on repeat.
- `doubled` — penalty doubles each time.
- `escalate:tier1|tier2|tier3|...` — penalty climbs through the listed tiers.
To reload rules without restart, POST `/api/rules/reload` as a system admin.
## Pilot import CSV format
```csv
number,last_name,first_name,country,balloon_id
1,Doe,John,DE,D-OABC
2,Müller,Anna,DE,
```
Header row is optional and auto-detected.
## Notes
- Storage is a single SQLite file in WAL mode — easy to back up by copying the `.db` file (along with `-wal` / `-shm` if present) while the server is briefly stopped.
- The frontend is pure HTML/CSS/JS, no build step.
- The Go binary embeds nothing — it serves `./web` and `./rules` from the working directory.