85 lines
4.5 KiB
Markdown
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.
|