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

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

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).

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

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.
S
Description
No description provided
Readme 226 KiB
Languages
JavaScript 51.7%
Go 40.7%
CSS 6.2%
HTML 1.4%