Skip to main content
Petanque Life

Live Scoring & Official Result Entry

F04.21 27 features Planned

At a glance

Real-time scoring infrastructure: mobile-first live entry with offline support, official scorekeeper role with digital signing, SSE-driven leaderboard updates, push notifications for match events, score correction flow under audit, score protests from team captains, walkover handling, and configurable round timing.

How it works

Live score entry on mobile is offline-capable from the ground up. The scorekeeper opens the match on a phone or tablet, taps points per mène, and the device queues every action locally. When connectivity returns, queued events sync in order with idempotency keys so duplicate replays are safe.

The official scorekeeper role digitally signs the final score with their authenticated session — a cryptographic signature attached to the result record so the line of accountability is traceable. Real-time leaderboard updates push via Server-Sent Events: any subscribed client (player apps, public leaderboards, embedded CMS widgets, scoreboards on venue screens) sees standings refresh within a second of each confirmed mène. Push notifications for match events fan out to subscribers — match starting in 5 min, score 10-10 in your followed match, your team has finished, podium reached.

Subscriptions are granular: per-match, per-player, per-competition, per-club, per-nation. Score correction flow lets the scorekeeper edit a recorded mène with mandatory reason; the original entry stays in the audit trail and a correction event broadcasts so live viewers see the adjustment immediately. Score protest from team captain is a structured action — the captain raises a protest tied to a specific mène or final result, the match enters a protest state, the jury (F05) reviews and resolves, and the outcome locks.

Walkover and WO handling captures the operational reality when one team does not show: the official records WO, the absent team forfeits, the present team advances with a default score per the format, and ranking impact applies the federation's WO rules. Round timing per round (45 min default) enforces session pace for poule rounds and Swiss rounds — the round timer counts down on the official's tablet, with warnings at 10 and 5 minutes, and configurable handling at expiry (current mène completes, no new mène starts).

Key capabilities

  • Mobile-first live score entry with offline queue and idempotent sync
  • Official scorekeeper role with digital signing on the final score
  • SSE-driven real-time leaderboard updates for clients, embeds, and venue scoreboards
  • Push notifications for match events with granular per-match/player/competition subscriptions
  • Score correction flow with mandatory reason and audit trail
  • Score protest from team captain with structured jury workflow
  • Walkover handling and configurable round timing (45 min default) with warnings and expiry rules

In practice

Outdoor Saturday tournament with patchy 4G. The official scorekeeper at court 5 records mène after mène on her tablet; the device is offline for 12 minutes, then back. All queued events sync in order with no duplicates.

The leaderboard widget on the federation site refreshes for spectators. The losing captain protests the final mène measurement; the match flips to protest state and the jury reviews via tablet, examines the photo attached in F04.05, and confirms the original score. The scorekeeper digitally signs the result; ranking points queue for the overnight recompute.

The next round timer starts at 45 minutes and warns at 35 and 40.

Features in this subsystem

27
ID Status Features
F04.21.01 Shipped Live score entry on mobile with offline support ✅ PL-F0421a ✅ PL-F0421a
F04.21.02 Shipped Official scorekeeper role with digital signing ✅ PL-F0421a ✅ PL-F0421a
F04.21.03 Shipped Real-time leaderboard updates (SSE) ✅ PL-F0421a ✅ PL-F0421a
F04.21.04 Shipped Push notifications for match events (subscriptions) ✅ PL-F0421a ✅ PL-F0421a
F04.21.05 Shipped Score correction flow with audit ✅ PL-F0421b ✅ PL-F0421b
F04.21.06 Shipped Score protest from team captain ✅ PL-F0421b ✅ PL-F0421b
F04.21.07 Shipped Walkover and WO handling ✅ PL-F0421b ✅ PL-F0421b
F04.21.08 Shipped Round timing per round (45 min default) ✅ PL-F0421b ✅ PL-F0421b
F04.21.20 Shipped VolunteerScoreEntry — parallel light-weight scoring surface optimised for volunteers, big-button UI, idempotent on (device_id, client_ts, end_number), soft-validation with stable warning codes (zero_score_end / both_teams_scored / score_above_13 / missing_end_<n>) — PL-T222 ✅ PL-T222 ✅ PL-T222
F04.21.21 Shipped Volunteer offline cache — exponential-backoff retry-loop, server-idempotency on tuple guarantees no duplicates, sync-status badge (synced/pending/error) — PL-T222 ✅ PL-T222 ✅ PL-T222
F04.21.22 Shipped Dispute flagging — measure / dead_end / timeout / rule_question / other, sets is_dispute=true + needs_review, dispatchar scoring.dispute_raised till court-marshal via F09.02 — PL-T222 ✅ PL-T222 ✅ PL-T222
F04.21.23 Shipped BulkScoreUpload — fixed-column CSV (competition_match_ref,end_number,team_a_points,team_b_points,scorer_note), parse-job med per-row error/warning, atomic-per-match apply, status uploaded/parsing/validated/applied/partially_applied/failed — PL-T222 ✅ PL-T222 ✅ PL-T222
F04.21.30 Shipped Enhetsregistret scoreboard_device (migration 00161): den fysiska tavlan ägd av PL:s tenant-noll, bunden till hyresgästens match med mjuka referenser, med serial_no/kit_instance_id mot D-EQUIP:s brädregister — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.31 Shipped Signaturverifierad uplink-ingest POST /v1/scoreboards/ingest (LNS-webhook, X-PL-Webhook-Signature, ±5 min färskhetsfönster, fail-closed utan en enda DB-skrivning) — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.32 Shipped Uplink → score_entry med source='board' och device_id: delta mot competition.DeriveScore, ökning ⇒ ny mène, minskning med 1 ⇒ husets undo-rad (is_undo/replaces_entry_id), aldrig negativ poäng eller DELETE — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.33 Shipped Validering mot den resolvade poänggränsen (ResolveScoring, aldrig hårdkodad 13:a) + stabila avvisningskoder (score_above_max, score_decrement_too_large, invalid_score_delta, scoreboard_match_closed, scoreboard_match_mismatch) — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.34 Shipped Replay-skydd på frame counter inom sessions-epok + partiellt unikt index på (device_id, session_epoch, f_cnt) where outcome='applied' ⇒ exakt-en-gång även vid at-least-once-leverans; varje utfall spåras append-only i scoreboard_uplink_event — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.35 Shipped match_final → D-COMP:s egen FSM (Transition + CompleteMatch) med vinnare ur DeriveOutcome; tavlan sätter aldrig confirmed_by_* — det fysiska långtrycket är en inmatning, inte resultatsignering — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-1)
F04.21.36 Shipped Flott-/bindnings-API GET /v1/scoreboards, GET\ PATCH /v1/scoreboards/{id}, POST /v1/scoreboards, POST /v1/scoreboards/{id}/assign-match — ETag/If-Match, cursor-paginering, server-injicerat skop (hyresgästen ser bara enheter med aktiv uthyrning), nyckelfälten projiceras aldrig — 1ee83e2c.m-1 | ✅ 1ee83e2c.m-1 (t-2)
F04.21.37 Shipped Två mandat, inte ett (scoreboard:fleet_admin i den smala systemmallen platform_scoreboard_admin; scoreboard:operate på klubb-/distrikts-/förbundsadmin) + fixturen seed-scoreboard-hw som konsumerar D-EQUIP:s custody-brädor — 1ee83e2c.m-1 ✅ 1ee83e2c.m-1 (t-2)
F04.21.38 Shipped Enhetstelemetri som riktiga rader (migration 00162): scoreboard_device_health (1:1 per enhet — batteri, tavlans egen RSSI, gateway-RSSI/SNR ur rxInfo, senast sedd, härledd presence) + tidsserien scoreboard_health_sample, upsertad i ingestens enda transaktion. Ingen temperaturserie: v1-payloaden mäter ingen temperatur, over_temp är en flagga — 1ee83e2c.m-2 ✅ 1ee83e2c.m-2 (t-1)
F04.21.39 Shipped Larm-inboxen scoreboard_alert + GET /v1/scoreboards/alerts(/{id}, /acknowledge, /resolve): fem typer, warning/critical, en öppen rad per (enhet, typ) via partiellt unikt index, kvittens ≠ lösning (kvittensen är idempotent och fryser eskaleringen), auto-lösning per typ — tamper löses endast manuellt — 1ee83e2c.m-2 ✅ 1ee83e2c.m-2 (t-1)
F04.21.40 Shipped Trösklarna är konfig-data, aldrig konstanter — scoreboard_telemetry_config med treskikts-upplösning enhet → kit → plattform (null = ärv) och GET/PUT /v1/scoreboards/telemetry-config*; en ändring får effekt på nästa uplink utan omstart — 1ee83e2c.m-2 ✅ 1ee83e2c.m-2 (t-1)
F04.21.41 Shipped Downlink-porten och kön (LNSDownlink + register + deterministisk fake + ChirpStack-adapter bakom env): scoreboard_command med den ärliga statusmaskinen queued → sent → acked \ expired | failed, där sent betyder LNS:en accepterade enqueuen, aldrig levererad — 1ee83e2c.m-2 | ✅ 1ee83e2c.m-2 (t-2)
F04.21.42 Shipped Tamper-armering POST /v1/scoreboards/{id}/tamper-arm\ tamper-disarm (202 med kommandoraden, If-Match, konvergent på partiellt unikt index) + kvittensvägen POST /v1/scoreboards/ingest?event=ack på samma signatur-fail-closed: enhetens tamper_armed speglas först vid tavlans egen kvittens — 1ee83e2c.m-2 | ✅ 1ee83e2c.m-2 (t-2)
F04.21.43 Shipped assign-match köar set_match (0x01) och auto-arm/disarm ur D-EQUIP:s egna emitterade scoreboard_inventory_event-rader (received ⇒ arm, returning ⇒ disarm) — läsning, aldrig skrivning i D-EQUIP:s revir; dedup-cursorn lever på m-2:s egen kommandorad — 1ee83e2c.m-2 ✅ 1ee83e2c.m-2 (t-2)
F04.21.44 Shipped Hälsosvepet api run-job scoreboard_health_sweep med fyra plikter (närvaro-larm stale/lost, auto-arm/disarm-avstämning, kommando-TTL + omförsök, retention på tidsserien), now injicerat, batch-takat och idempotent — 1ee83e2c.m-2 ✅ 1ee83e2c.m-2 (t-1/t-2)