Commit Graph

51 Commits

Author SHA1 Message Date
larssand
2bbbd6e995 Fix Swedish åäö rendering as mojibake in PDF exports
buildSimplePdf's font declared no /Encoding at all, so PDF viewers fell
back to a standard font's built-in encoding, which has no å/ä/ö glyphs
- and separately, the content stream was written as UTF-8 instead of a
single-byte encoding, so even a correctly-encoded font would receive
the wrong bytes (a multi-byte UTF-8 sequence where PDF expects exactly
one byte per character): the classic "åäö" mojibake pattern.

Fixed by declaring /Encoding /WinAnsiEncoding and writing the content
stream through a proper WinAnsi (~CP1252) byte mapper instead of UTF-8.
This is the single shared renderer behind every PDF export (race
results, start lists, heat sheets, team reports, the results archive),
so the fix applies everywhere at once, matching what was reported.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 21:31:01 +02:00
larssand
1c4a06b69e Record completed training sessions, credit them, and add session-count goals
A driver completing the practice timer, "Jämna varv", or "Stegträning"
now gets a permanent history entry instead of the outcome only existing
as a one-off notification - visible on both their mobile profile and
the admin Training page, so progress over past sessions is actually
reviewable. Each completion earns a prominent emoji-badged credit.

The completion is verified server-side against the driver's real
recorded laps before being saved, reusing the same progress builders
live tracking already uses - the client can only ask for a completion
to be checked and recorded, never supply the outcome itself, so a
driver can't fabricate a completed session (and the reward tied to it)
any more than they could fabricate a lap time.

Both per-driver and club-wide goals can now target "complete N
sessions of one exercise kind" as an alternative to "N laps", sharing
the existing reward/claim mechanism and forms.

Fixes a real bug found while building this: a pre-existing two-argument
wrapper around getTrainingGoalProgress in app.js silently dropped the
new third argument, so every sessions-metric goal displayed 0 progress
regardless of how many sessions were actually completed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:43:47 +02:00
larssand
94794350e5 Add a results archive and purge orphaned passing rows on delete
Until now there was no way to find a completed session without already
knowing which event it belonged to - navigation was strictly Events ->
one event -> its sessions. A new "Resultatarkiv" view lists every
finished session across all events, searchable by event/session name,
class, driver and date range.

Opening a session reuses the existing single-session leaderboard
builder for standings and the existing per-competitor lap lookup for
lap history - no new results logic - plus a session-wide penalties/
corrections list (resultsBySession[id].adjustments), previously only
visible in the live judging action log. Export buttons reuse the
existing per-event PDF and race-package JSON export functions rather
than adding a new format.

Investigated what should happen to raw timing data when a race is
deleted. Training statistics and session replay already read from
their own independent, deliberately-retained copies that survive
deletion by existing design - unaffected either way. The one thing
that outlived deletion with no purpose was the raw `passings` SQLite
rows (write-only; nothing in the app reads them), growing forever with
driver IDs never purged. A new POST /api/passings/purge endpoint now
removes exactly the deleted session(s)' rows, called as a best-effort
side call from both delete-event and delete-session.

Also fixes a real bug found while building this: ensureSessionResult
guarded adjustments/splits/pitEvents/pitStops against being missing on
an already-existing result, but not passings itself, so viewing lap
history for such a result (e.g. an older/imported race package)
crashed outright.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 15:49:10 +02:00
larssand
643902ff15 Add end-of-practice summary to the driver's mobile profile
When a driver's personal 5-minute practice timer finishes, a "Pass
avslutat" card now appears immediately: how this pass's pace and
consistency compared to their recent sessions, any goal or lap-count
milestone crossed during the pass with its reward text made prominent,
and one suggested next goal (reusing the existing pace recommendation,
falling back to the next milestone when there isn't enough data yet).
Scoped to the driver's current class, and explicit about insufficient
sample sizes instead of showing a misleading number.

Adds a per-session consistency calculation to
buildPublicTrainingWindowStats server-side; everything else needed
(stats, goals, recommendation, milestone) was already sent to the
client, so the summary itself is computed there from data already in
hand - no raw laps or driver IDs added to what the public endpoint
exposes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 15:05:49 +02:00
larssand
3373f8dddd Protect live race results and shrink cross-browser staleness
Investigated whether two admin browsers open at once can overwrite each
other's changes, per an explicit request to report the risk before
making bigger changes. Found that POST /api/state always replaces the
entire stored document with a client's in-memory copy, with no version
check and no per-field merge - and a browser only ever pushes, never
re-fetching server state after page load except on the Overlay view.
An idle browser's next save, even an unrelated edit, could silently
revert another browser's more recent changes, worst case a live race's
in-progress results.

Two scoped fixes instead of the bigger optimistic-locking rework (that
needs real UX decisions about conflicting saves, deferred separately):

1. server.js now remembers which session results were just written by
   a real live decoder passing (/api/passings) and protects that key
   for 15 seconds against being reverted by a stale full-state save,
   while still applying the rest of that save normally.
2. Every non-Overlay view now quietly refreshes its data in the
   background every 15 seconds (skipped while a local edit is
   pending), without ever calling renderView(), so it can never
   discard an open, unsaved edit form - shrinking how stale a
   browser's next save can be from hours to seconds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 12:56:58 +02:00
larssand
c53f31bf35 Backup directory failures must not crash the whole server
A fresh Windows install reported the server failing around backups.
createBackupService created the backups subdirectory once, synchronously,
at startup with no error handling - any failure there (permissions, a
path beyond Windows' MAX_PATH, a OneDrive/cloud-sync lock, antivirus)
crashed the entire Node process before it started listening, taking
down timing with it instead of just leaving backups unavailable.

Directory creation is now retried lazily and non-fatally on each backup
attempt, and a post-backup file rename retries briefly on EBUSY/EPERM
since a freshly written file is sometimes momentarily locked by
antivirus/cloud-sync scanning on Windows.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 10:59:39 +02:00
larssand
2846b4c0fe Expose guided training exercises on the driver's mobile profile link
"Jämna varv" and "Stegträning" previously only lived on the admin
Training page. A driver's own personal mobile profile link now offers
the same self-service configure/start/stop flow already used for the
5-minute practice timer there, with live progress computed server-side
from the driver's own share token so raw lap rows and driver IDs never
reach the client.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 09:37:38 +02:00
larssand
01e1165748 lägg till stegträning-övning + v1.3.0
Andra guidade träningsövningen i Open Practice: konfigurera en
stegserie (antal varv + lugnt/kontrollerat/snabbt per steg),
förvalt till klassiska pyramiden. Training-sidan visar aktuellt
steg, kvarvarande varv och en progress-pill per steg. När
sekvensen är klar jämförs de två kontrollerade stegens snitt
neutralt (t.ex. "+0.90s"), utan att kalla en försämring för
trötthet.

syncTrainingLedger sprider nu resten av det normaliserade
training-objektet istället för att lista fält manuellt, så
samma klass av bugg som drabbade Jämna varv inte kan upprepas
för framtida fält.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 09:02:44 +02:00
larssand
9122e91f2e lägg till jämna varv-övning + v1.2.0
Ny guidad träningsövning i Open Practice: sätt måltid, tolerans
och antal varv, se aktuell serie och dagens bästa live på
Training-sidan. Ett missat varv startar en ny serie utan att
radera bästa resultatet.

Hittade och fixade två buggar under vägen:
- syncTrainingLedger byggde om training-state vid varje sparning
  utan att föra vidare det nya evenLaps-fältet, så sparade
  konfigurationer försvann direkt
- Training-sidan kraschade för alla förare med färre än 3 varv i
  varje stint (t.ex. de första varven i ett pass) eftersom en
  dedupe-funktion läste en egenskap på ett null-värde

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 08:51:50 +02:00
larssand
d18cd7fb5e decoder reconnect 2026-09-09 08:08:56 +02:00
larssand
09524944dd fix obs popup issues 2026-09-09 07:52:07 +02:00
larssand
acab99ed4d race day tester + fixa open practice start och decoder-omritning
Nytt browser-test för start/paus/fortsätt/finish och byte till
nästa heat i kön, mot en simulerad decoder-socket (ingen riktig
AMMC-hårdvara). Hittade och fixade två buggar under vägen:

- Open Practice på sponsor/track-event kunde inte startas trots
  grönt ljus i förkontrollen (separat, striktare kontroll saknade
  samma undantag)
- Race Day-vyn ritades aldrig om när decodern anslöt/kopplades ner

Testramverket hanterar nu även native alert()/confirm()-dialoger
automatiskt, annars fryser en headless körning helt.
2026-09-09 06:59:54 +02:00
larssand
b3bec531de connecton satus mobil profile 2026-09-08 19:27:37 +02:00
larssand
a0c3d3039e Separat status och mottagningsräknare för varje kanal.
Senaste råmeddelande, fel och ignoreringsorsaker.
Pausa visning, rensa och kopiera logg.
Uppdateras utan att störa inställningsfält eller tidtagning.
2026-09-08 18:37:47 +02:00
larssand
8aedf83826 fix all overlays 2026-09-08 18:26:30 +02:00
larssand
443434d569 fix status and roadmap 2026-09-08 17:26:55 +02:00
larssand
9e6fe2386d fix sort and obs panels 2026-09-08 13:21:29 +02:00
larssand
9c74c1f256 add version 2026-09-05 13:39:50 +02:00
larssand
78c650bde7 raceday kontroller 2026-09-05 09:59:55 +02:00
larssand
bfe13de59c fixrefresh in mbil prof 2026-09-05 09:49:19 +02:00
larssand
285babcfcf add more stats to mobile and fix refresh stint 2026-09-04 16:41:51 +02:00
larssand
4068cc7c19 add more stats to mobile profile 2026-09-04 16:17:45 +02:00
larssand
142c45be04 add replay session 2026-09-04 15:58:24 +02:00
larssand
2d56b74731 Add local and public QR sharing for training profiles 2026-09-03 20:15:13 +02:00
larssand
4f847610dc Improve training statistics, achievements and stable pace audio 2026-09-03 06:36:17 +02:00
larssand
483a9dbd5a Fix lap limits and five-minute stint statistics 2026-09-02 19:36:25 +02:00
larssand
f561dd8feb new raceday and backup 2026-09-01 07:07:23 +02:00
larssand
5ed193cdeb fix import av csv 2026-08-30 16:14:45 +02:00
larssand
694aba5f3d Add motivational training challenges and shared club goals 2026-08-30 09:16:11 +02:00
larssand
e5e1754185 add more train stats per driver 2026-08-29 09:56:45 +02:00
larssand
28e5c96010 fix tränings länken och race day 2026-08-28 21:55:28 +02:00
larssand
375bfb2416 förbättreing tränings 2026-08-28 21:44:23 +02:00
larssand
c6262aceab fix live leaderbord details 2026-08-28 21:12:43 +02:00
larssand
3cf68cf34a branding och namechange 2026-08-28 20:56:58 +02:00
larssand
0a05f04075 fix tränings statse sidan 2026-08-28 14:12:09 +02:00
larssand
34e55ff7f6 add custome voice 2026-08-28 13:47:25 +02:00
larssand
fa3e5ee379 add save sound 2026-08-28 13:39:12 +02:00
larssand
5f79228941 Add configurable manifest-driven race audio system 2026-08-28 13:29:27 +02:00
larssand
e5af42ce2d Add CSV imports and granular competition data cleanup 2026-08-27 17:56:50 +02:00
larssand
32acc0e9c7 fix rendering och refresh så det inte uppdatera sidan vid inställningar 2026-08-27 14:47:24 +02:00
larssand
84302a770d Mobilprofilen visar nu per vald klassom det finns depå,mellantids
decoders
2026-08-25 20:04:14 +02:00
larssand
abf887dccd Split- och depåstatistik är implementerad 2026-08-25 20:00:55 +02:00
larssand
8ea8b3a84e Add multi-decoder split and pit timing support 2026-08-25 19:45:40 +02:00
larssand
6f02e955a5 Add class-specific driver training profiles and metadata 2026-08-24 22:05:50 +02:00
larssand
3aeb77a042 add stat 2026-08-24 21:28:38 +02:00
larssand
355a1ad3b0 Förbättrat ljudsystemet 2026-08-24 19:40:39 +02:00
larssand
2e6866a013 Add simplified Open Practice flow and reorganize 2026-08-24 19:25:21 +02:00
larssand
5a6e51c51b Add persistence and SQLite integration tests 2026-08-24 19:08:21 +02:00
larssand
0ca1679e2a Add race timing and judging regression tests 2026-08-24 18:58:40 +02:00
larssand
1365da7f3c publika träningslogik är nu utbruten och testbar 2026-08-24 18:50:02 +02:00