# Changelog User-visible changes to RC RaceCore are recorded here, starting with the 1.1.0 baseline. Earlier development has not been reconstructed as individual releases. The application version is maintained in `package.json` and displayed in the administration menu. Add changes under **Unreleased** as they are made. When preparing a release, move those entries into a dated version section and update the version in both `package.json` and `package-lock.json`. ## Unreleased No changes recorded yet. ## 1.21.1 - 2026-09-12 ### Changed - Re-ran the security/dependency audit against everything shipped since 2026-08-28 (`docs/security-performance-audit.md`). `npm audit` stayed clean (0 vulnerabilities); no new SQL-injection or shell-injection risk found in any new code. One new notable finding: `POST /api/update/run` (the in-app update checker) is an unauthenticated trigger that unconditionally stops and restarts the server, making it a more direct denial-of-service primitive than the app's other already-documented unauthenticated endpoints - no code change made, tracked for the deferred permissions/auth work. ## 1.21.0 - 2026-09-12 ### Changed - The Guide page is now split into 5 tabs (Getting started, Create a race, Run a race, Training & results, Video guides) instead of ~20 panels stacked on one very long page. ### Added - `tests/browser_guide_tabs.js`: permanent regression coverage for the new Guide tabs, wired into `npm run test:browser`. Investigated a reported "feels slow" concern about the Guide page while making this change: measured its actual render time in a real browser (median 0.6ms, comparable to or faster than Settings/Timing) - no rendering performance issue found. The perceived slowness was the page's length, which this change addresses directly. ### Changed - Brought `docs/javascript-architecture.md` back up to date with this session's changes: documented `src/track_layouts_logic.js`, `buildEventSchedule`, the Settings/Event Manager tab layouts, and the new `Event.raceConfig.scheduleStartAt`/`scheduleGapMin` and `Session.trackLayoutId` fields; added a real SQLite table contract section and a full field-by-field `Settings` shape (both previously just TODO notes); documented several previously-undocumented backend routes (`/api/update-status`, `/api/update/run`, `/api/network/public-address`, `/api/passings/purge`, the public-training self-service actions); and listed every file `tests/browser_smoke.js` actually invokes. ## 1.20.1 - 2026-09-12 ### Changed - Refreshed the in-app Guide screenshot (`docs/screenshots/guide.jpg`) to show its current content (the new Schedule and Video guides sections, missing from the old capture) and added a new screenshot of Event Manager's tabbed layout (`race-manage-tabs.jpg`), linked from both READMEs. Added `scripts/capture-screenshots.mjs`, a reusable capture tool built on the same isolated-server pattern as the video/test tooling. ## 1.20.0 - 2026-09-11 ### Added - Committed all 7 recorded video guides to `docs/videos/` and linked them from the in-app Guide page (a new "Video guides" section, both sv/en), `README.md` and `README.sv.md`. `scripts/record-video-guides.mjs` now writes there by default instead of the previous gitignored `video-guides/` folder, so re-running it and committing the result is how these get kept current. ## 1.19.0 - 2026-09-11 ### Added - Four more narrated video-guide clips covering core new-user onboarding: `connect-decoder`, `add-drivers-cars`, `create-race`, and `run-a-session` (Race Day start/pause/resume/finish with a real countdown and start lights). `scripts/record-video-guides.mjs` gained a `prepare()` hook so a clip can spin up a fake decoder socket before the app is seeded, and a `clickNav()` helper that exercises the app's real client-side navigation instead of a full page reload. ## 1.18.2 - 2026-09-11 ### Changed - `scripts/record-video-guides.mjs` now narrates with Piper (a small local neural TTS) instead of espeak-ng - espeak-ng's formant synthesis was reported as barely intelligible ("robotröst från 80-talet"). Requires `pipx install piper-tts` plus a downloaded voice model; see the script's header comment. ## 1.18.1 - 2026-09-11 ### Changed - `scripts/record-video-guides.mjs` now records narrated video guides, not silent screen captures: each clip is a sequence of spoken lines (synthesized offline with `espeak-ng`) timed to the on-screen action they describe, mixed onto the video's real measured timing so narration and action stay in sync. ## 1.18.0 - 2026-09-11 ### Added - `scripts/record-video-guides.mjs`: records short MKV screen-capture clips of the UI (currently: Settings tabs, Event Manager tabs, and the race day Schedule panel) against a real, isolated instance of the app - same throwaway server/browser pattern as the browser test suite, so it never touches real installation data. Output lands in the gitignored `video-guides/` folder for use as new-user video guide material; run with `node scripts/record-video-guides.mjs [clip-name ...]`. ## 1.17.2 - 2026-09-11 ### Changed - Added permanent browser regression tests for the three UIs restructured this session: Settings tabs (default tab, panel switching, selection surviving an in-place save/re-render), Event Manager tabs (default tab, panel switching, the quick-jump step cards and Open Grid button correctly switching tabs before scrolling), and the race day Schedule panel (saving/clearing the schedule, running-order table, and the Delayed badge for a session that started late). All added to the `npm run test:browser` suite. ## 1.17.1 - 2026-09-11 ### Changed - Updated the in-app Guide (sv/en) for everything shipped this session: the new race-day Schedule feature (new "Race day time schedule" section, plus an overview card), staggered-start car call-outs and the per-driver "Done" flag, the new Settings and Event Manager tab layouts, and the driver transponder-conflict warning. Also corrected an outdated line claiming Open/Free Practice was the only thing that skipped the start ceremony - a scheduled "Practice" session in a structured event now gets the full sequence too. ## 1.17.0 - 2026-09-11 ### Changed - Event Manager's race-mode page (a long scroll of participants, teams, race format, live grid/standings, schedule and print/PDF tools) is now split into four tabs - Participants & teams, Format, Live & results, Schedule & print - so a specific section is a click away. The existing step-card overview and "fix this" warning links now switch to the right tab automatically before jumping to it. Track/sponsor events, which only ever had a handful of panels, keep the simple untabbed layout. ## 1.16.1 - 2026-09-10 ### Fixed - A scheduled "Practice" session inside a structured race/sponsor event (as opposed to the standalone Quick Open Practice shortcut) silently skipped the entire start ceremony - no countdown, no lights, no start tone - jumping straight to running instead of matching qualifying/heat/final. It now gets the same countdown/lights/start-tone sequence; only Quick Open Practice and free practice still start instantly. ## 1.16.0 - 2026-09-10 ### Added - Events can now have a time-of-day schedule: set a start time and a gap between sessions on the "Schedule" panel in Event Manager, and every session's planned clock time is worked out automatically in running order (practice, then qualifying, then finals). Once a session actually starts or finishes, everything after it shifts forward to match reality - a late start or a session that runs long (including any pause) automatically pushes the rest of the day's plan, no manual "reschedule" step needed. The scheduled time is now also shown on the printed/PDF start lists. ### Fixed - `getSessionSortWeight`, which decides run order for printed start lists/results and the new schedule above, silently sorted `open_practice` sessions (weight 0) dead last instead of first, because `0 || 99` treats a valid zero weight as missing and falls back to the "unknown type" bucket. Practice sessions now correctly sort first, matching how a race day actually runs. ## 1.15.0 - 2026-09-10 ### Changed - The session picker in Timing (and the session replay picker) now group sessions by event, most recently created event first, instead of one long flat list of every session ever created - much easier to find the right one once a club has run several races. ## 1.14.1 - 2026-09-10 ### Fixed - A staggered heat's car call-outs (and its start list, and its fallback grid seeding before any practice has been run) followed the drivers directory's internal creation order instead of the order participants were actually selected for the event - so the announced order, and the start list shown in Race Day, could look scrambled relative to how the event was actually entered. - A staggered heat's shared clock and auto-finish timer only ever counted a flat session duration (e.g. 5:00), not accounting for the staggered release schedule itself - so with several drivers being released a few seconds apart, the last-released driver's own personal window could still be running when the session force-finished. The shared clock now starts from duration + the full release schedule (e.g. 5:09 for 4 drivers 3 seconds apart) instead of just the flat duration, while each driver's own personal 5-minute quota is unchanged. ## 1.14.0 - 2026-09-10 ### Added - A staggered-start qualifying heat now announces each driver's car (transponder) number in grid order, about 3 seconds apart, right after the official start - a mass/position-start session is unaffected and still starts everyone together with the usual countdown and start sound. - The Timing leaderboard and every overlay/leaderboard display now show a green "Done" flag next to a driver's name once their own personal timing window has elapsed in a staggered-start heat, even while the session is still running for other drivers who started their own window later. ## 1.13.0 - 2026-09-10 ### Added - Registering or editing a driver now warns if the transponder you entered is already used by a different driver (e.g. someone in another class) - naming who and which class - before saving, instead of silently allowing it. Saving anyway is still possible for genuine cases (e.g. a reused loaner transponder); the same physical transponder reused across one person's own multiple class entries is not flagged. ## 1.12.2 - 2026-09-10 ### Fixed - The race clock shown next to a driver's result (e.g. laps/total time in Timing, Overlay, Results archive, Team Race stint logs, and Training's stint duration) rendered a malformed, doubled-up time like `02:48.20:207` instead of a clean `02:48.207`. `formatRaceClock` computed both a 2-digit centiseconds value and a 3-digit milliseconds value and concatenated both into the string; only the milliseconds part was ever meant to be there. This had been broken since the feature was first written and was easy to miss because it only shows once a session actually has recorded lap results - found while building fuller demo data for the documentation screenshots below. ## 1.12.1 - 2026-09-10 ### Fixed - Clicking a race-audio "Test" button (either the general one, or a per-event one in the sound table) saved the settings form to the database on every click, including any other unsaved edits sitting in the form at the time. Testing a sound is now purely a local preview - it still uses whatever's currently in the form, but no longer writes it to the database. The database is written only when you press Save, or edit a field directly (unchanged). ## 1.12.0 - 2026-09-10 ### Changed - The Settings page no longer stacks every section into one long scroll. It's now split into four tabs - Connection (decoder + managed AMMC), Audio, Appearance & overlay (branding, track layouts, OBS), and System & backup (updates, storage/backup, race presets, clear data) - so a specific setting is a click away instead of a scroll. ## 1.11.0 - 2026-09-10 ### Added - A driver left alone in the last qualifying heat (e.g. 7 drivers at 3 per heat) can now be moved into another heat directly - edit a heat and tick the driver on, and they're automatically moved out of whichever heat they were on before, with a warning shown before you save. ## 1.10.3 - 2026-09-10 ### Fixed - Qualifying reseed could scramble the grid in rounds with 10+ heats (heats were sorted as text, so "H10" came before "H2"), and silently dropped drivers or left empty "ghost" heats when the participant count changed - it now reseeds numerically and warns clearly instead of failing silently. - A driver with zero laps in a qualifying heat or final (DNS) used to vanish entirely rather than showing as a real last-place result - including silently from every future round and the final grid. They now show up correctly as "Ej start (DNS)". - Bump-up did nothing at all when "reserve bump slots" was turned off, and a promoted driver could stay gridded in their old main's upcoming leg at the same time as their new one. Both fixed; an oversized bump count can also no longer blow past 26 mains. - Undoing a judging correction (e.g. a time penalty) out of order could leave a driver with a live penalty even though every log entry showed "undone" - undo now always nets to the correct result regardless of order. - A paused heat's results weren't comparable to an unpaused heat's in qualifying ranking, and a session finished while paused kept showing a growing elapsed time afterward. Both now correctly exclude paused time. ## 1.10.2 - 2026-09-10 ### Fixed - Moving a driver from one Team Race team to another (by ticking them on the new team's edit form) used to leave them on both teams at once, so their laps only ever counted for one of them. Team edit/create now shows a warning naming the driver's current team before you tick them elsewhere, and saving genuinely moves them. Also fixed: the team driver picker was showing every driver in the club instead of just the event's own participants, and deleting a driver or car left them behind in team rosters forever. ## 1.10.1 - 2026-09-10 ### Added - A new version is now flagged right in the sidebar, next to the current version number - not only inside Settings. Clicking it jumps straight into Settings with the update ready to run. ## 1.10.0 - 2026-09-10 ### Added - Track layouts now also scope the driver training profile's personal-best, pace-trend and consistency statistics (both on the admin Training page and the driver's own mobile link) - the part of the app actually most affected by a layout change, since it's built from ongoing Open Practice. Lifetime totals (laps, sessions, training days, milestone badges) still count everything a driver has ever done; only pace/record comparisons are now scoped to the currently active layout. ## 1.9.0 - 2026-09-10 ### Added - Clubs that reconfigure their track layout (common when running indoors in the same building) can now add track layouts under Settings, each with a name and a start date/time. Every session is tagged with whichever layout was active when it started, so the "track record" audio cue and the Results Archive (which now shows each session's layout) only compare lap times run on the same physical track. With no layouts added, everything behaves exactly as before. ## 1.8.0 - 2026-09-09 ### Added - Settings now shows whether a newer version of RC RaceCore is available - checked against the actual git remote this installation was cloned from, so it works the same whether that's GitHub or a self-hosted server, and needs no account or API key. When an update is available it shows the new version number (read from the remote's package.json) and an "Uppdatera nu" / "Update now" button that stops the server, pulls the new code, reinstalls dependencies and starts back up automatically, with a confirmation dialog that warns explicitly if a race/session is currently active. The page then reloads on its own once the server is back, reusing the app's existing update-detection so no extra polling logic was needed on the client. No git knowledge is required to update - a single click does the whole thing. ## 1.7.1 - 2026-09-09 ### Fixed - Swedish å/ä/ö/Å/Ä/Ö rendered as garbled characters (or vanished entirely) in every PDF export - race results, start lists, heat sheets, team reports and the results archive - because the PDF's font never declared a character encoding and its text was written as UTF-8 instead of the single-byte encoding a PDF font actually expects. Both are now fixed at the shared PDF renderer, so every export is corrected at once. ## 1.7.0 - 2026-09-09 ### Added - Completing a training session - the general practice timer, "Jämna varv", or "Stegträning" - is now automatically recorded to a permanent history, visible on both the driver's mobile profile ("Träningshistorik") and the admin Training page, so a driver (or coach) can look back at past sessions and see improvement over time. A completion is verified against the driver's real recorded laps before being saved, the same way live progress already is, so it can't be faked. Each completed session earns a prominent credit with an emoji badge, and both per-driver and club-wide goals can now target "complete N sessions" as an alternative to "N laps", using the same reward system as today. ### Fixed - A goal targeting completed sessions always showed 0 progress regardless of how many sessions were actually completed, due to a pre-existing helper in the admin app that silently dropped the new argument needed to compute it. ## 1.6.1 - 2026-09-09 ### Fixed - "Rensa data" (Settings -> Clear data) for the drivers/cars/races/all-competition-data scopes left every affected session's raw timing rows behind in the database, the same gap already fixed for deleting a single event/session - now purged there too. ### Documentation - The in-app Guide page now covers this session's new features: the two guided practice exercises and their mobile self-service controls, the end-of-practice summary, and the new Resultatarkiv view. Corrected outdated text claiming raw timing rows are always retained. ## 1.6.0 - 2026-09-09 ### Added - A new "Resultatarkiv" (results archive) view lists every completed session across all events, searchable by event/session name, class, driver and date - no more needing to already know which event a session belonged to. Opening a session shows its standings, penalties/corrections, and a per-driver lap history, and offers the same PDF and race-package (JSON) export already available from Event Manager. Deleting an event or session now also removes its raw timing rows from the database instead of leaving them behind indefinitely - driver-visible training statistics and session replay are unaffected, since they already keep their own independent copy. ### Fixed - Opening a session's lap history in the archive (or anywhere reusing the same lookup) crashed if that session's result was missing its passings list - e.g. an older or hand-edited/imported race package. It's now backfilled the same way other missing result fields already were. ## 1.5.0 - 2026-09-09 ### Added - A "Pass avslutat" (practice complete) summary now appears on the driver's personal mobile profile the moment their 5-minute practice timer finishes: how their pace and consistency compared to their recent sessions, any goal or lap-count milestone reached during that pass with its reward shown prominently, and one suggested next goal - scoped to their current class, with a plain explanation whenever there isn't enough data yet to judge pace or consistency. ## 1.4.3 - 2026-09-09 ### Fixed - Two admin browsers open at once could silently overwrite each other's work: any save pushed a browser's entire in-memory copy of the data, so an idle tab's next save - even an unrelated one - could revert another browser's more recent changes, including a live race's in-progress results. Live results computed from real timing data are now protected from being reverted for a short window after they arrive, and every view now quietly refreshes its data in the background every 15 seconds (without ever discarding an open, unsaved edit), so the data behind any save stays fresh instead of getting stale over hours. ## 1.4.2 - 2026-09-09 ### Fixed - Sync and backups could fail everywhere with an unexplained "Failed to fetch", while the server itself was completely healthy, whenever the page was opened via a different address (e.g. a LAN IP) than the one saved in Settings under "Backend URL" - browsers treat those as different origins, and the browser's own security check (CORS) silently blocks the requests without explaining why. Settings now detects this mismatch, names the page's actual address, and offers a one-click button to fix it. ## 1.4.1 - 2026-09-09 ### Fixed - A backup failure at startup (e.g. no write permission for the backups folder, a path beyond Windows' MAX_PATH, a OneDrive/cloud-sync folder locking it, or antivirus interference) could crash the entire server before it started listening, instead of just leaving backups unavailable. Backup-directory creation is now non-fatal and retried on each backup attempt, and a file rename right after a backup completes now retries briefly if a file is momentarily locked by antivirus/cloud-sync scanning. ## 1.4.0 - 2026-09-09 ### Added - "Jämna varv" and "Stegträning" can now be configured, started and stopped directly from the driver's own personal mobile profile link, the same way the existing self-service practice timer already works there - independent of whether an admin has the Training page open. Live progress (streak, today's best, tolerance-based lap coloring, step pills) is computed server-side from the driver's own share token, so raw lap rows and driver IDs never reach the mobile page - only sanitized aggregates, matching the existing public-profile security boundary. Each exercise tracks its own elapsed time independently of the general 5-minute practice timer and of each other. ## 1.3.0 - 2026-09-09 ### Added - "Stegträning" (step training): a second guided practice exercise inside an active Open Practice session. Configure a sequence of steps (lap count plus calm/controlled/fast effort per step, defaulting to the classic pyramid); the Training page shows the current step, remaining laps, and a per-step progress pill, and once two "controlled" steps have laps it shows the plain pace difference between the first and last one - never labeled as fatigue. ## 1.2.0 - 2026-09-09 ### Added - "Jämna varv" (even laps): a guided practice exercise inside an active Open Practice session. Set a target lap time, tolerance and lap count (with a suggested target from the driver's own personal best); the Training page shows the live streak and today's best streak, and a missed lap starts a new streak without losing the best one. - Personal mobile profiles show last successful data retrieval, stale-data and failed-update warnings, and a Retry button without replacing loaded statistics or active forms. Requests time out after 15 seconds and cannot overlap. - Browser coverage for Race Day start/pause/resume/finish and switching to the next queued heat, against a simulated decoder socket. - Browser coverage for opening the OBS overlay as a real popup window (not a direct URL load): compact layout, and live clock updates that freeze on pause, polling independently of the admin page. - Browser coverage for decoder auto-reconnect after a dropped socket (simulated network interruption): reconnects onto exactly one connection, never a duplicate, and stops retrying once auto-reconnect is turned off. ### Fixed - Open Practice sessions on a sponsor (track-mode) event could show a ready/green Race Day preflight yet refuse to start, blocked by a stricter assignment check the preflight never warned about. Open Practice is now exempt from that check everywhere, matching the preflight. - The Race Day view did not refresh when the decoder connected, disconnected, or errored, so its Start button and preflight checklist could stay stale after a page load until something else triggered a re-render. - Printing or exporting start lists, results, heat sheets and team reports always showed a false "popup blocked" error and produced nothing, in every modern browser. Opening the OBS overlay as a popup had the same false "blocked" check and its window never received focus. Both used `window.open(..., "noopener,noreferrer,...")`, which returns `null` even on success by current browser standards; both now open without those flags. - The Training page crashed for any driver with fewer than 3 laps in every stint - a common state, e.g. a driver's first couple of laps in a session - because a dedup step read a property off a `null` "best stint" entry. ## 1.1.2 - 2026-09-08 ### Reliability checks - Browser coverage for sponsor-event edits, endurance race creation, team membership changes/deletion, session-type conversion and lap-limit persistence. - Overlay sorting headings share the same column tracks as driver rows. Narrow displays scroll the headings and values together. ### Added - Browser-local decoder/socket diagnostics in Settings: per-channel counters, bounded logs, pause/clear/copy and independent updates that preserve form drafts. - A prioritized ROADMAP.md with completion checklists. - Server/save status, last load/save times, stale/offline warnings and manual retry of local changes. - Isolated browser regression checks for class/driver/car creation and editing, retained drafts, reload persistence and offline save recovery (`npm run test:browser`). ### Fixed - New browser profiles connect to the page origin rather than assuming backend port 8081. - Correct chronological sorting of zero-padded times and deterministic ordering of distinct numeric-looking driver/car names. Name and identifier columns are explicitly treated as text. - OBS race-info and standings panels wrap on narrow sources. Driver names retain space and timing fields wrap instead of overflowing. ## 1.1.1 - 2026-09-07 ### Added - Sortable columns in the leaderboard, recent passings, and training tables/lists, with each list remembering its own sort choice. - OBS overlay leaderboard layout split into a race-info panel (left) and a driver-stats panel (right), so each can be positioned independently on stream. ### Fixed - Sorting by driver or car name no longer merges differently zero-padded numbers (e.g. "09" and "9") into the same position. - Sorting the interactive overlay no longer changes the row order shown on the OBS broadcast source. ## 1.1.0 - 2026-09-05 ### Added - Visible application version in the menu, read from the running server's package version. - This changelog as the starting point for tracking future changes. ### Baseline The existing feature set includes race and sponsor-event setup, team racing, AMMC timing, Race Day preflight, overlays and OBS views, Swedish and English race audio, training statistics, personal mobile profiles, import/export, and backups. See the README and in-app guide for configuration and usage. Recent improvements included in this baseline: - More compact mobile training profiles and consistent class-selector text sizing. - Mobile refresh protection while entering data, selecting a class, or saving a car change. - Separate unsaved car-change notes per class during page updates and class switching. - Preservation of loaded mobile statistics during temporary refresh failures. - Race Day preflight lists blockers first and provides shortcuts to the relevant configuration.