From abed53fb325744b44ddf11cacaef9077600fe259 Mon Sep 17 00:00:00 2001 From: larssand Date: Tue, 13 Oct 2026 07:44:23 +0200 Subject: [PATCH] docs(readme): restructure both READMEs and cover every current feature Contents, highlights and quick start first, then features in the order a club uses them, then installation, decoders and development. Adds the start count-down, series hub, practice tooling, audio, OBS and security features, and removes outdated statements. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 17 + README.md | 1055 ++++++++++++-------------------------------- README.sv.md | 1077 +++++++++++++-------------------------------- ROADMAP.md | 6 + package-lock.json | 4 +- package.json | 2 +- 6 files changed, 611 insertions(+), 1550 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fb6cc5..4277bf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,23 @@ The application version is maintained in `package.json` and displayed in the adm No changes recorded yet. +## 1.39.1 - 2026-10-13 + +### Changed + +- README (English and Swedish) rewritten with a clear structure: contents, highlights, screenshots, quick start, the features in the order a club uses them (race day, creating races, series/cup, practice, audio, overlays, sponsor events, data, security), then video guides, installation, decoders/AMMC and development. It now covers every current feature, including: + - the EFRA/IFMAR start count-down, flying start and transponder check; + - judging-only penalties in races; + - track layouts with their own lap window; + - suspect-lap flagging and lap clean-up; + - practice/race lap sources and reset keeping stats; + - series hub with per-round formats; + - Piper voices, passing-tone-only race calls and the pronunciation test; + - OBS places gained; + - the public address setting and admin PIN. + + Outdated statements were removed: penalties on Timing, the legacy beep/name passing sound, and Piper listed as future work. The README went from 913 to 420 lines. + ## 1.39.0 - 2026-10-11 ### Added diff --git a/README.md b/README.md index 46a38a4..69eb976 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,46 @@ # RC RaceCore -Planned work and completion checklists are tracked in [ROADMAP.md](ROADMAP.md). +RC timing and race control for clubs: live timing from AMB/MyLaps decoders through AMMC, race day control with EFRA/IFMAR-style start procedures, qualifying and finals, series and cups, practice statistics with mobile driver profiles, announcements with an offline voice, and overlays for screens and OBS. Everything runs locally on one computer (Windows or Linux) with a SQLite database - no cloud service and no internet needed at the track. -The running version is shown at the bottom of the menu and comes from `package.json`. Changes are recorded in [CHANGELOG.md](CHANGELOG.md). +Swedish version: [README.sv.md](README.sv.md) · Changes: [CHANGELOG.md](CHANGELOG.md) · Plans: [ROADMAP.md](ROADMAP.md) · The running version is shown at the bottom of the menu. -English README. Swedish version: [`README.sv.md`](README.sv.md) +## Contents -RC RaceCore is an RC timing and race-control system with support for sponsor events with shared cars/transponders, AMMC WebSocket input, and local persistence through SQLite. +- [Highlights](#highlights) +- [Screenshots](#screenshots) +- [Quick start](#quick-start) +- [Using RaceCore](#using-racecore) + - [Race day](#race-day) + - [Creating races](#creating-races) + - [Series / cup](#series--cup) + - [Practice and training statistics](#practice-and-training-statistics) + - [Audio and announcements](#audio-and-announcements) + - [Overlays and OBS](#overlays-and-obs) + - [Sponsor events with shared cars](#sponsor-events-with-shared-cars) + - [Data, backups and import/export](#data-backups-and-importexport) + - [Security](#security) +- [Video guides](#video-guides) +- [Installation](#installation) +- [Decoders and AMMC](#decoders-and-ammc) +- [Development and tests](#development-and-tests) -## Architecture +## Highlights -- JavaScript module overview: `docs/javascript-architecture.md` -- Security and performance audit: `docs/security-performance-audit.md` -- Swedish operational guide: `README.sv.md` - -## Windows Quick Start - -For a new Windows 11 computer, open **PowerShell** and follow these steps. - -1. Check whether Git is installed: - -```powershell -git --version -``` - -2. If `git` is not recognized, install it and reopen PowerShell: - -```powershell -winget install --id Git.Git --exact --source winget -``` - -3. Download RC RaceCore and enter the project directory: - -```powershell -Set-Location $HOME -git clone https://git.dio.nu/Public/Live_RC.git Live_RC -Set-Location .\Live_RC -``` - -4. Run the complete installer. It installs/checks Node.js, installs npm dependencies, verifies SQLite and starts the server in the background: - -```powershell -.\windows\install.bat -``` - -5. Verify the server and open `http://localhost:8081`: - -```powershell -npm.cmd run status -Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" -``` - -If `winget` is missing, install [Git for Windows](https://git-scm.com/download/win). You can also download the repository as a ZIP without Git. See the complete [Installation](#installation) section for ZIP installation, LAN access, updates and troubleshooting. +- **Race Day page** with heat queue, preflight checks and one-click start. +- **Start procedure as in EFRA/IFMAR:** a count-down with announcements (2 min, 1 min, 30 s, 10 s, 9..3), hold for the grid, flying start for qualifying, and grid start with lights and a random start signal for finals. +- **Transponder check** during the count-down: a green tick for every driver seen, and a wrong transponder fixed in one click. +- **Qualifying and finals:** generated from the entry list with evenly split heats, A/B/C finals, bump-ups, points tables, tie-breaks and a drag-and-drop grid. +- **Series / cup:** a points table, best N or drop X, a club-members-only option, standings per class, and each round run from the series page. +- **Judging:** penalties and lap changes, all logged and undoable. +- **Practice statistics** per driver, class and track layout: stints, consistency, achievements, goals, and a personal mobile profile with a QR code. +- **Clean statistics:** suspiciously short practice laps (shortcuts) are flagged automatically and removed in one click. +- **Announcements** in Swedish or English with a local neural voice (Piper, offline). Races play the passing tone only, as timing systems do. +- **Overlays** for screens and OBS, with places gained/lost since the start. +- **Safe data:** SQLite, an automatic backup before every start, full export/import, and an optional admin PIN. ## Screenshots -Current layouts for race operation, live presentation, training and system configuration. Click an image to open the full-resolution version. +Click an image to open the full-resolution version. @@ -71,8 +56,12 @@ Current layouts for race operation, live presentation, training and system confi + + + + @@ -80,326 +69,201 @@ Current layouts for race operation, live presentation, training and system confi - - - -
Detailed practice statistics with pace heatmap and stint analysis
Detailed practice statistics
Series / cup with numbered steps
Series / cup
Judging and race corrections
Judging and race corrections
Race sounds and announcements
Race sounds and announcements
Event Manager's Live & results tab
Event Manager's Live & results tab
Decoder configuration
Decoder configuration
In-app setup guide
In-app setup guide
Event Manager's Live & results tab
Event Manager's Live & results tab
Series / cup with numbered steps
Series / cup
-## Video Guides +## Quick start -Short narrated screen recordings for new users, also linked from the in-app Guide page. Click a link to download/play the `.mkv` (H.264/AAC). +**Windows 11** (PowerShell): -**Getting started** -- [Connect a decoder](docs/videos/connect-decoder.mkv) - link the decoder in Settings, and see auto-reconnect after a dropped connection -- [Add drivers and cars](docs/videos/add-drivers-cars.mkv) - create a class, a driver and a car -- [Create a race](docs/videos/create-race.mkv) - the 4-step Race Setup wizard, start to finish -- [Run a session](docs/videos/run-a-session.mkv) - Start with a real countdown and start lights, Pause, Resume, Finish, then Timing +```powershell +winget install --id Git.Git --exact --source winget # only if "git --version" fails +Set-Location $HOME +git clone https://git.dio.nu/Public/Live_RC.git Live_RC +Set-Location .\Live_RC +.\windows\install.bat +``` -**Interface tour** -- [Settings tabs](docs/videos/settings-tabs.mkv) -- [Event Manager tabs](docs/videos/event-manager-tabs.mkv) -- [Race day schedule](docs/videos/event-schedule.mkv) - -These are regenerated with `node scripts/record-video-guides.mjs` (see the script header) whenever a covered flow changes enough that the recording no longer matches reality. - -## Better Offline Voice (Piper) - -Announcements can use a local neural voice instead of the browser's system voice - free, no account, and it keeps working with no internet at the track. Swedish and English are installed together: +**Linux (Ubuntu/Debian)** with Node.js 22 or 24: ```bash -npm run tts:install +git clone https://git.dio.nu/Public/Live_RC.git Live_RC +cd Live_RC +npm ci && npm run verify +npm start ``` -or click **Install** under Settings -> Audio -> Voice engine. This downloads the standalone Piper release for your OS (Linux, Windows, macOS - no Python needed) plus one male and one female voice per language - Swedish NST (male) and Lisa (female), English Ryan (male) and Lessac (female) - into `piper/` (about 300 MB). Internet is only needed while it installs. Then choose **Local voice**, pick the Swedish and English voice you want (male is preselected), and click **Pre-generate phrases and driver names** before race day. If Piper is missing or slow, the browser voice takes over automatically. More voices can be downloaded one at a time under **More voices** in the same panel (about 63 MB each): Swedish Alma (female), British Alan and Northern English (male), Cori (female), Scottish Alba (female), and American Joe, John and Norman (male). Optional overrides: `RC_PIPER_BIN` (path to a piper executable) and `RC_PIPER_VOICES_DIR` (extra voice folder). +Then open `http://localhost:8081`, or `http://:8081` from another computer on the race network. The in-app **Guide** (menu) and the [video guides](#video-guides) walk through the first decoder connection, drivers and the first race. Full steps: [Installation](#installation). -## Public Overlay And OBS +## Using RaceCore -The app now supports a dedicated public overlay route so you do not need to expose the full admin UI externally. +The menu follows how a race day works: **Start** (Dashboard, Race Day), **Create** (Race Setup, Sponsor events, Series / cup), **Run and follow** (Timing, Judging, Overlay, Training stats, Results archive), **Directory** (Classes, Drivers, Cars) and **System and help** (Settings, Guide). The interface is in Swedish or English. -- Public overlay route: `/public-overlay/` -- OBS mode: `/public-overlay/obs` -- OBS overlay can be configured from the `Overlay` menu: - - rows - - layout: `leaderboard`, `grid`, `lowerthird` - - theme: `panel`, `transparent`, `chroma` - - visible columns and blocks -- Use `Copy OBS URL` to generate a ready-to-paste browser-source link for OBS. +### Race day -If you want simple protection for public overlays, set this environment variable on the server: +**Race Day** is the operator's page: +- The **heat queue** shows the current, next and after-next heat. +- **Preflight** checks the decoder, participants, transponders (missing or duplicated), the lap window, the grid and audio. Blockers come first, each with a shortcut to the right setting. The min/max lap time can be edited right there. +- **An automatic SQLite backup** is taken before every start. -```bash -PUBLIC_OVERLAY_TOKEN=your-secret-token -``` +**Start procedure (EFRA/IFMAR):** Start runs a count-down first. Choose Go, 30 s, 1, 1:30, 2, 3 or 5 min; the default is set per event for qualifying and finals. +- **During the count-down:** + - The track is open. + - The announcer calls "Heat 3 starts in 2 minutes", then every minute, 30 s and 10 s. + - For a grid start it also calls "cars to the grid" at 30 s and counts 9..3. +- **Buttons:** + - **Hold** (while cars are put on the grid) and **Resume**. + - **+1 min**. + - **To 30 s** (grid restart). + - **To 10 s**. + - **Go now**, which warns about drivers not seen. + - **Cancel**. +- **When the count-down runs out the heat starts by itself.** + - **Grid start** (mass/position): start lights and a random 0-5 s start signal. + - **Flying start** (default for qualifying): the signal and "Clock is running". Each car's clock starts at its own first crossing, and a late car's clock starts at the latest 150 % of a lap (EFRA 9.3). + - **Staggered start:** cars are called out one by one. +- **Transponder check:** every driver in the heat gets a green tick when their transponder crosses during the count-down. A missing driver's transponder can be changed in the panel, or linked to an unknown transponder that just crossed. +- **Pause, resume and finish** work during the heat. Follow-up time lets the last lap finish after the clock. -This token gates the overlay route only. Changes through the admin API can be protected with an optional admin PIN (Settings -> System & backup; off by default) and restricted to specific addresses with `RC_ADMIN_ALLOWED_CIDRS` (comma-separated IPv4 CIDRs or exact IPs, e.g. `192.168.1.0/24`). Reads are not PIN protected, so still do not expose port `8081` directly to the internet. Use a trusted race LAN, VPN, or authenticated reverse proxy. If the UI is intentionally served from another origin, list it in `RC_ALLOWED_ORIGINS` (comma-separated). See [`docs/security-performance-audit.md`](docs/security-performance-audit.md). +**Timing** shows the live leaderboard (laps, gap to leader and ahead, own delta, best and last lap), recent passings with invalid short laps marked, the grid for position starts, a session replay (1-10x), and the speaker panel. -Then the public overlay URL must include: +**Judging** is where race corrections are made: ±laps, ±seconds and reset, plus removing or restoring any lap. Everything is logged with time and can be undone; the log exports as JSON. In qualifying, heats and finals this is the only place for penalties; Timing shows the corrections and has an **Open in Judging** button. Practice has no penalties, but laps can be cleaned up right on Timing (see [practice](#practice-and-training-statistics)). -```text -/public-overlay/obs?token=your-secret-token -``` +Lap validation: +- **Min lap time** rejects shortcuts and false hits. +- **Max lap time** starts a new statistics stint after a break; the long lap still counts in the race. -Recommended deployment: -- publish only `/public-overlay/*` through your reverse proxy -- keep the main app/admin UI internal +### Creating races -## Features -- Event modes: - - `Race (driver transponders)` - - `Track Event (shared cars)` -- UI separation: - - `Event` = sponsor events with shared cars/transponders - - `Race Setup` = untimed Open Practice or competition races with personal driver transponders -- Grouped navigation follows the operating flow: `Start`, `Create`, `Run and follow`, `Directory`, and `System and help`. -- `Dashboard -> Getting started` links directly to system setup, driver registration, race/practice creation, Timing, and Overlay. -- Race Day operation: - - focused current/next/after-next heat queue - - preflight for decoder, participants, transponders, duplicate IDs, lap window, grid and audio - - blockers and warnings shown first, with shortcuts to the relevant settings or register; lap limits can be edited directly in Race Day - - shared start/finish/pause logic with the existing Timing view - - automatic consistent SQLite backup before every session start, full data import and data clear operation - - latest 30 server backups listed under `Settings -> Storage` - - isolated session replay in `Timing` with play, pause, reset, and 1x/2x/5x/10x speed; source results are never modified -- Storage/import tools: - - full race-data export/import for backup or moving to another machine - - directory export/import for only classes, drivers and cars - - CSV export and safe merging CSV import for drivers and cars through Excel or LibreOffice - - single race-package export/import from `Race Setup -> Manage -> Race Actions` -- Race Setup includes: - - `Quick Open Practice`: enter only a name, create an untimed all-transponder session, and continue directly to Timing - - no class, registered drivers, preset, qualifying, finals, or duration is required for Quick Open Practice - - grouped `Participants` and `Teams` sections in `Manage` - - a four-step `Create Race Wizard` for new races - - `Manage` split into `Setup`, `Format`, `Generation`, and `Live / results` - - Basic mode now reacts to the selected preset, including a cleaner endurance view - - `Basic / Advanced` mode for `Race Format` - - a right-side race summary card - - a preset-aware summary card that changes between endurance and normal race focus - - status badges for `Setup`, `Format`, `Generation`, and `Live / results` - - summary warnings when participants, sessions, teams, or lap-window settings are missing - - clickable summary warnings that jump to the relevant Manage section - - clickable step cards that act as quick navigation inside `Manage` - - compact step cards with live counters such as drivers, teams, sessions, and active/results state - - separate `Race actions` for generation, reseeding and bump-up - - reorganized in-app `Guide` with overview cards and two-column sections - - explicit race participant selection - - practice standings - - qualifying standings with `points` or `best result` - - built-in step-by-step guide - - inline descriptions for all `Race Format` fields - - `Follow-up time` after scheduled race time before a heat fully closes - - `Min lap time` rejects shortcuts/false hits; `Max lap time` starts a new statistics stint without removing the race lap - - seeding modes for practice/qualifying: best N laps total, average, or consecutive - - selectable qualifying points tables and tie-break rules - - `Race Format` presets for short technical tracks, club races, IFMAR-style layouts, and endurance - - schedule drift on `Dashboard` between planned and actual runtime - - session type `Free Practice` for rolling lap-time display without seeding - - automatic qualifying heat generation from practice standings or class list - - re-seeding of upcoming qualifying heats from current standings - - automatic `A/B/C...` finals generation from rankings - - persistent manual grid per session with drag-and-drop grid editor - - auto-reseed skips heats with locked manual grid - - explicit `Lock/Unlock grid` per session - - multi-leg final standings with counted final legs - - optional bump-up between finals - - reserved bump-up slots in higher finals - - visual finals matrix with reserved bump slots - - drag-and-drop grid editor for position starts - - print/export of heat sheets per qualifying/final - - overlay modes for external display screens - - multiple overlay modes: leaderboard, speaker, results, TV, team - - speaker overlay with event markers and separate speaker cues - - live speaker panel in `Timing` - - speaker cues and club branding for the sidebar, overlays, public training profiles, and PDFs from `Settings` - - club logo upload for the sidebar, overlays, public training profiles, and PDFs from `Settings` - - per-event/per-race branding in `Manage` - - extra speaker cues for `session start`, `new best lap`, and `top 3 change` - - selectable PDF themes: `classic`, `minimal`, `motorsport` - - branded print and PDF exports - - server-generated PDF exports with embedded logo - - generated qualifying/finals inherit duration and start mode from race format - - finish sound uses a siren instead of browser TTS -- Sessions: - - `practice` - - `qualification` - - `heat` - - `final` - - `free_practice` - - `open_practice` - - `team_race` -- Sponsor event tools: - - automatic round creation (`qualification`, `heat`, `final`) - - auto-assign driver -> car per session -- Live timing from AMMC WebSocket (`msg: "PASSING"`) -- Managed AMMC from the web UI: - - backend can start/stop local `ammc-amb` on Windows, Linux, and macOS - - bundled binaries from `AMMC/windows64`, `AMMC/linux_x86-64`, `AMMC/apple_m` -- Editing in UI: - - classes, event names/dates, drivers, and cars can be edited directly - - drivers and cars support optional `brand` fields for team, sponsor, manufacturer, or model data - - `Drivers` and `Cars` can be searched by name, transponder, or brand directly in the UI - - race start lists and heat sheets include driver brand in print, CSV, and PDF exports -- Live race control: - - countdown during timed sessions - - auto-finish at end of session time with `Race is finished` - - leaderboard sorting by laps first, then nearest to target time when applicable - - configurable browser audio for start, finish, and passings (`beep` or driver name) - - selectable operating-system speech voice, speech rate/pitch, and per-driver phonetic spoken name - - session start types: `Mass start`, `Position start`, `Staggered` - - `Timing` shows grid/order for the active `Position start` session - - leaderboard shows `gap to leader`, `gap ahead`, and `own delta` - - `Recent Passings` distinguishes invalid `Short lap` passings from counted long laps that start a new stint - - manual corrections in `Timing -> Details`: `+1/-1 lap`, `+1/+5/-1 sec`, reset - - practice/qualifying seeding on best `2` or `3` laps -- Persistence: - - frontend state in browser `localStorage` - - same state and passings persisted to local SQLite through the Node backend -- Built-in `Guide` page in the app covering: - - sponsor events (for example 10 drivers / 4 cars) - - standard race setup - - invalid laps, follow-up, and manual corrections - - AMMC + npm setup on Windows and Linux -- UI language selection: - - `SV` - - `EN` +**Race Setup** has two ways in: +- **Quick Open Practice:** just a name. It creates an untimed all-transponder session and goes straight to Timing; no class, drivers or format are needed. +- **Create Race Wizard:** Basics → Participants → Session plan → Confirm. Choose a class and a preset, pick the drivers, and the practice/qualifying (or team race) sessions are created. -## Training And Rewards +After creation the race is managed in four tabs (Race Setup → Manage): +- **Participants & teams:** tick who races, and manage teams for endurance. +- **Format:** + - qualifying rounds, cars per heat, duration and start mode (mass, position, staggered, flying); + - seeding (best N laps total, average, or consecutive); + - qualifying points table (placement, by field size, 10-9-8...) and tie-break; + - finals: legs, counted legs, bump-ups and reserved bump slots; + - count-down length, follow-up time and the min/max lap time; + - presets: short technical track, club race, IFMAR style, endurance, or your own saved club presets; + - **Race actions** at the bottom of the tab: + - create qualifying from practice (or the entry list); heats are split as evenly as possible, e.g. 9 drivers with max 8 per heat gives 5 + 4; + - reseed upcoming heats; locked manual grids are respected; + - create A/B/C finals and apply bump-ups; + - export the race as a package. +- **Live & results:** + - grid editor (drag and drop) and lock; + - practice, qualifying and final standings, and a finals matrix; + - print and branded PDF exports; + - split and pit summaries. +- **Schedule & print:** the day's running order with planned times, and heat sheets. -The `Training` menu provides a non-race progression view for registered drivers: +The **Dashboard** shows schedule drift (planned vs actual). The **Results archive** finds finished races without going through Race Setup. -The default view is a club overview with totals and one row per driver and class. Select a driver from the list to open the intentionally simple personal view with four key statistics, the next lap target, today's practice plan and active rewards. Goal administration, mobile sharing and detailed history remain available in collapsed sections when needed. +### Series / cup -When Open Practice, Free Practice, or Practice is running, the selected driver gets a compact live card with current valid laps, best lap, average, and latest lap. The session remains shared by everyone; only the mobile personal timer and profile link are unique per driver and class. The primary action at the top creates or opens that link. +Menu **Series / cup** runs a championship over any number of rounds, with freely chosen classes. Each class gets its own standings. -One person can have separate driver entries for classes such as 2WD and 4WD and link them to the same `Practice profile` under `Drivers`. The person then has one profile and one mobile link, while every performance statistic is selected and calculated separately per class. Multiple transponders within the same class are combined in that class's statistics. +1. **Name and classes.** +2. **Points:** + - **Who scores:** every driver (open series), or club members only. With members only, drivers from other clubs race and appear in the day result but get no series points, and members are re-ranked without them. + - **Points table:** the ÖRC table (100, 90, 82, 75, 69 … then −4 per place, min 10), 100-80-70, F1, or your own list. + - **Counted results:** best N (e.g. 9 of 12), or all run rounds except the X worst. A cancelled round then lowers the count automatically. +3. **Rounds:** paste the dates, and one race per date and class is created with the chosen number of qualifying rounds, finals and max cars per heat. Each round is then run from its row: + - pick drivers; + - **Copy from previous** round; + - **New driver** for a late entry; + - change the format for that round (it can differ between rounds and classes); + - **Create qualifying** (heats follow the size of the field) and **Create finals**; + - **Status** and **Open**. +4. **Standings:** + - The day placing comes from the final standings (A before B), then qualifying order. + - No registered lap gives 0. Absence counts as 0 and can be dropped. + - Ties go to most wins, then 2nd places, then the latest common round. + - Print, or export as PDF (wide tables switch to landscape). -The personal profile can also store `Club` and `Country`. These values are inherited when another class entry is linked to the same practice profile and are included in full JSON and driver CSV exports. They are not disclosed by the public profile link. +### Practice and training statistics -- durable lifetime valid-lap ledger synchronized from stored session results -- practice days, recorded sessions, personal best, overall/recent averages, controlled-lap streak, and recent consistency spread -- automatic stint boundaries at the configured `Max lap time`, with a 2-minute fallback for legacy/unconfigured data -- best 3 consecutive laps plus best 5-minute result and its average pace -- the best 5-minute result counts the final lap when it started before `5:00` (`300 s`), even when the result finishes after the cutoff -- mobile profile pace chart, recent class-specific stint summaries, and daily history for the latest practice days -- per-profile publishing controls for development, achievements, performance/stints, goals/rewards, and history; disabled detail sections are filtered by the public API -- personal development trend comparing the latest 30 valid laps with the preceding 30, always isolated per class -- automatic achievements for first practice, lap totals, practice days, controlled streaks, and completed five-minute stints -- optional personal stable-pace voice feedback after five controlled laps in one practice stint, using the configured driver spoken name and a per-driver cooldown -- three optional daily challenges for valid laps, controlled consecutive laps, and a completed five-minute stint -- a positive personal summary that recognizes today's volume, personal best, pace, consistency, and endurance without ranking drivers -- a recent club progress feed ordered by activity rather than driver position or lap-count ranking -- a configurable shared club target that counts every new valid practice lap from all registered drivers from the moment the target is created -- one collapsed More statistics section with active 30-minute pace blocks based on a trimmed average -- class-specific setup markers for tires, suspension, car changes, or custom notes, including an automatic 30-minute before/after comparison -- detailed stint analysis with normal pace, best 10-lap race pace, outlier laps, pace retention, and strong finishes -- personal control zone, stint-scoped flow streaks, clean five-minute runs, and latest split-time improvement -- automatic progression levels at useful lap totals without manual setup -- a configurable practice timer split into maximum-focus and controlled 80-90% blocks -- custom lap milestones with quick targets at `500`, `1000`, and `1500` laps -- optional reward text and a delivered/redeemed state -- responsive layout for opening the same server from a phone on the local network +**Practice sessions:** +- Open Practice can run all season; Free Practice is a rolling best-lap session. +- **Reset data** on Timing clears the session for a new day, but every lap stays in the training statistics. -Direct mobile/bookmark link: `http://:8081/?view=training`. Selecting a profile and class adds both to the URL so the exact view can be bookmarked. +**Track layouts:** +- Press **New layout** (on Training stats, Race Day or the Dashboard) when the track is rebuilt. A running practice moves onto the new layout, and best laps start over. +- Each layout can have its own **min/max lap time** for practice. Races always use the event's values. +- Statistics are per layout, with an "all layouts" overview. -Training statistics currently include only valid laps linked to a registered driver. Anonymous Open Practice transponders are intentionally excluded until they are assigned to a driver. +**Suspiciously short laps** (practice only): +- A lap far quicker than the driver's own pace (under 85 % of their median, after 5 laps) is flagged ⚠ - typically a shortcut by a new driver or a child. +- It counts as a lap but not as a best lap, record or statistic until someone **Approves** it. +- **Remove** is one click, in the panel on Timing and Race Day, or in the driver's lap list. -Judging corrections update ledger laps while the source session still exists. Once a session is deleted, its synchronized training laps remain in the ledger so lifetime progression is not lost. Full data export includes the ledger, reward goals, and setup markers. +**Training stats** (menu): +- The club overview and one page per driver and class show: + - personal best, averages and consistency; + - best 3 consecutive laps and the best 5-minute result; + - stint analysis, 30-minute pace blocks and setup markers with before/after comparison; + - daily history and achievements; + - goals with rewards, daily challenges and a shared club goal. +- **Based on: Practice** (default), **Races** or **All.** Race laps are kept separate and marked 🏁 with race, session and series. Under Races they are listed per race session; a race never forms stints. +- One person can race several classes. Link the class entries to the same practice profile under Drivers; statistics stay per class. -### Restricted mobile profile +**Mobile profile:** +- Each driver can get a personal link with a QR code. It shows their own statistics, a practice timer, setup markers and exercises (even laps, step training), and has a choice of practice or race laps. +- The link uses a random token; no transponders or other drivers are shown. +- For use over the internet, set the **public address** once for everyone under Settings → System & backup → Public address (domain / DynDNS), e.g. `https://club.dyndns.org:8443`. Left empty, links use the local network address. +- Proxy only these paths to the internet: `/public-training/*`, `/src/public_training.js` and `/src/public_training.css`. Ready-made Teltonika files are in `scripts/teltonika/`. -Each registered driver can have an optional personal mobile link: +### Audio and announcements -1. Open `Training` and select the driver. -2. Open `Goals and mobile profile`, then click `Enable mobile profile`. -3. For internet sharing, set the public address once for every driver under `Settings` -> `System & backup` -> `Public address (domain / DynDNS)`, for example `https://racecore.example.org` or `https://club.dyndns.org:8443`, and click `Save`. Each driver's share panel shows the address in use with a `Change in Settings` button. Leave it empty to use the local network address (same wifi only). -4. Scan `Local QR code` on the same network as RaceCore, or `Public QR code` over the internet. The local QR is generated from the RaceCore server LAN address, so it also works when the admin UI was opened as `localhost`. -5. Use `Create new link` to revoke the previous URL, or `Disable profile` to turn sharing off. `Detect public IP` is an explicit suggestion only; use the FQDN when the TLS certificate is issued for the domain. +Settings → Audio: +- **Race sounds:** + - start lights, random start delay and passing tones (optionally a different tone per driver/car); + - announcements in Swedish or English for the start, the clock (1 min, 30 s, 10 s), final lap, finish, winner and podium, pit, penalties and race control (track call, red flag, false start, marshal); + - each event can be switched on or off for effect and voice. +- **Calls during a race:** "Passing tone only" (default, like timing systems) or "Speaker" with names, personal bests and new leaders. Practice always gets the full calls. +- **Local neural voice (Piper):** free and works offline. Install from Settings → Audio → Voice engine, or with `npm run tts:install`. + - Standard voices: Swedish NST (male) and Lisa (female), English Ryan (male) and Lessac (female). + - Under **More voices**, one at a time (about 63 MB each): Swedish Alma; British Alan, Northern English, Cori and Alba (Scottish); American Joe, John and Norman. + - Pre-generate phrases and driver names before race day. + - If Piper is missing, the browser voice takes over. +- **Spoken name per driver:** enter a pronunciation or nickname under Drivers and press **🔊 Test pronunciation** to hear it in real announcements. -The URL uses a 192-bit random bearer token rather than a driver ID. The same link provides a class selector with fully separate lap times and practice results for each linked class. The public API does not return transponder IDs, other driver names, club ranking, race setup or admin state. The only server-side mobile action is adding a setup marker for the token owner and selected linked class. +### Overlays and OBS -Mobile auto-refresh pauses while editing a field or saving a car change. Unsaved car-change notes remain separate per class during page updates and class switching (until the page is reloaded). Temporary refresh failures keep the last loaded statistics visible. +The **Overlay** menu has leaderboard, speaker, results, TV and team modes, plus an OBS mode with layout (leaderboard, grid, lower third), theme (panel, transparent, chroma), rows and columns: +- Columns: laps, result, best, gap, and **places since the start** (▲/▼ in heats and finals). +- **Copy OBS URL** gives a browser-source link; the chosen columns are part of the link. +- Public overlays live at `/public-overlay/` and can require a token: set `PUBLIC_OVERLAY_TOKEN` and add `?token=...`. Publish only `/public-overlay/*` through your reverse proxy. +- Club branding (name, logo, PDF theme) is applied to the sidebar, overlays, mobile profiles and PDFs; branding can also be set per event. -The performance section also shows active 30-minute pace blocks and lets the driver mark a class-specific car/setup change. Open detail sections remain expanded during live polling. +### Sponsor events with shared cars -The mobile page also includes a local practice timer where the driver chooses minutes for `Maximum focus` and `Controlled`. The default is `10 + 10`, while a five-minute heat can for example use `5 + 0`. While a shared Free Practice session keeps running, the card shows that driver's lap count, best lap and average since the personal timer started. Timer state and duration choices stay in that phone's browser, separately per driver and class, and do not modify race data. Durations are locked while a session runs and can be changed after finishing or resetting it. +**Sponsor events** (track events) let many drivers share a few cars and transponders, e.g. 10 drivers and 4 cars: +- rounds are created automatically and drivers are assigned to cars per session; +- within one session every car needs a unique transponder, but the same transponder can be used again in the next session. -For internet publishing, proxy only these paths: +### Data, backups and import/export -```text -/public-training/* -/src/public_training.js -/src/public_training.css -``` +- **Storage:** + - Everything is stored in `data/rc_timing.sqlite`; the browser keeps a local copy and syncs. + - The menu shows the save status (saved, pending, failed, with **Retry**). + - Judge corrections are sent straight to the server. +- **Backups:** + - automatic before every session start, plus manual ones; + - the latest 30 are listed under Settings; + - restore with `npm run backup:restore` (see [Installation](#restore-a-server-backup)). +- **Export/import** (Settings → Storage): + - full JSON, or the directory only (classes, drivers, cars); + - CSV for drivers and cars (Excel/LibreOffice; comma, semicolon or tab). The CSV import merges: it matches on ID, then transponder, then name + class. + - a single race package from Race Setup; + - club presets. +- **Clearing:** drivers, cars, classes, races or training statistics can each be cleared separately, every one with its own confirmation. Export first. -Do not expose `/api/state` or the full admin application. Ready-to-copy Teltonika files are in `scripts/teltonika/`; the init script recreates Nginx RAM-backed temporary directories at every boot and does not use `nginx-util`. Static serving is restricted to `/src` and `/docs`; `data/`, server scripts and bundled binaries are not public static files. - -Regression tests use Node's built-in test runner and require no extra test-framework dependency. The suite covers training profiles, race generation and timing, judging corrections, frontend/backend state synchronization, and an isolated SQLite API round-trip using a temporary data directory: - -```bash -npm test -``` - -The integration test starts its own backend on a temporary localhost port and never reads or writes the normal `data/rc_timing.sqlite` database. - - -## Create Race Wizard -- `Race Setup` now starts with a four-step wizard for new races: - - `Basics` - - `Participants` - - `Session plan` - - `Confirm` -- The wizard is intended to create the first race structure quickly: - - choose class and preset - - scope valid race drivers - - create practice, qualifying, and/or team-race sessions automatically -- Finals are still generated later from `Race Actions` after practice or qualifying is complete. - -## Series / cup - -Menu **Series / cup** groups several races into a championship: -- **Classes:** choose any classes; each gets its own table. -- **Rounds:** any number. Create them from a list of dates (one race per date and class) with the number of qualifying rounds, finals and max cars per heat, or add an existing race. -- **Running the season from the series page (step 3)**, one row per round: - - **Drivers:** click the number to tick who takes part. All drivers in the class are ticked to begin with. **Copy from previous** takes the field from the previous round of the same class, and **New driver** registers a late entry in the class (and the series' club) and ticks it. - - **Format per round:** qualifying rounds, finals and max cars per heat. Each round and class can differ; the format locks once qualifying is created. - - **Create qualifying:** the number of heats follows the number of drivers, split evenly (9 drivers, max 8 per heat → 5 + 4, never 8 + 1). - - **Create finals** once qualifying is done. **Status** shows not started, qualifying created/running/done, finals, done. **Open** goes to the race in Race Setup. -- **Points table:** the ÖRC table (100, 90, 82, 75, 69 ... then -4 per place, min 10), 100-80-70 ..., F1, or your own list with a step and minimum after it. -- **Counted results:** best N (e.g. 9 of 12), or all run rounds except the X worst. A cancelled round then lowers the count by itself. Absence counts as 0 and can be dropped. -- **Who scores series points** is a choice per series: - - **Every driver (open series)**, the default. Drivers from any club race and score. - - **Club members only.** Pick the club; the club comes from each driver in the driver register. Drivers from other clubs still race and appear in the day result, but get no series points, and members are re-ranked without them (place 1 among members gets the winner's points). -- **Day result:** each round is ranked by its final standings (A before B), then drivers without a final in qualifying order, or by qualifying alone if no finals ran. A driver with no registered lap gets 0. -- **Ties:** most wins among counted results, then 2nd places and so on, then the latest common round. -- **Standings:** shown per class with dropped results in brackets. They can be printed or exported as PDF; wide tables switch to landscape. - -## Manage workflow -- After the race is created, `Manage` is split into four clear stages: - - `Setup` - - `Format` - - `Generation` - - `Live / results` -- `Setup` handles race participants and teams. The top step cards also act as quick navigation between the four blocks. -- `Format` handles practice/qualifying, finals, validation, presets, and advanced settings. In Basic mode, endurance hides most qualifying/finals fields until Advanced is opened. -- `Generation` is kept separate so actions like qualifying generation, reseeding, finals generation, and bump-up do not clutter the format form. -- `Live / results` is where grid, standings, print, PDF, and finals matrix are used once the structure is ready. - -## Export / Import -- `Settings -> Storage` now supports: - - full JSON export/import for the complete competition database - - directory JSON export/import for only classes, drivers, and cars - - CSV export and merging CSV import for drivers and cars; comma, semicolon, and tab delimiters are supported - - separate clearing of drivers, cars, classes, races/sessions, or training statistics - - `Clear all competition data` retains decoder, theme, branding, and server settings -- `Race Setup -> Manage -> Race Actions` now supports single race packages: - - export one race with its sessions, results, and referenced classes/drivers/cars - - import that package into another installation as a new race entry -- JSON export files now include export metadata and a schema version field so future imports can be handled more safely. -- CSV imports from the application's own exports preserve IDs. External lists without IDs first match by transponder and then by name + class. Empty fields do not overwrite existing information, and new class names are created automatically. -- Driver imports only require the `name` column. The recommended minimum is `name;transponder;class`. Optional columns such as `brand`, `spoken_name`, `club`, `country`, and `profile_id` may be omitted; unknown columns are ignored and rows without a name are skipped. +Example driver CSV (only `name` is required): ```csv name;transponder;class;brand;club;country @@ -407,252 +271,60 @@ Anna Andersson;123456;2WD;;JMK;SE Erik Eriksson;654321;4WD;Associated;; ``` -- An empty CSV template can be downloaded directly from the driver import area under `Settings -> Storage`. -- Create a JSON backup before clearing data. Every clear button requires a separate confirmation and cannot be undone. -- Web clearing removes canonical application data but retains the separate raw SQLite `passings` table as an audit log. A physical factory reset of the database must be performed locally on the stopped server, never through an unauthenticated LAN route. +### Security -## Race features +RaceCore is meant for a trusted race network: +- **Admin PIN** (Settings → System & backup, off by default) protects every change through the API. The login lasts 30 days and is throttled against guessing. +- **`RC_ADMIN_ALLOWED_CIDRS`** restricts admin changes to certain addresses or networks, e.g. `192.168.1.0/24`. +- **`RC_ALLOWED_ORIGINS`** is for a UI deliberately served from another address. +- **Don't expose port 8081 to the internet.** Reads are not PIN protected. Publish only the public overlay and mobile profile paths through a reverse proxy or VPN. -### Follow-up time -- Configure it in `Race Setup -> Manage -> Race Format` -- It can also be set per session when creating or editing a session -- When scheduled time ends, the session enters follow-up first -- When follow-up ends, the session closes automatically -- Generated qualifying/finals inherit follow-up from race format +See [docs/security-performance-audit.md](docs/security-performance-audit.md). -### Min / Max lap time -- Configure it in `Race Setup -> Manage -> Race Format` -- `Min lap time`: - - laps faster than the threshold are ignored as shortcuts or false hits -- `Max lap time`: - - a slower passing starts a new statistics stint - - the transition lap still counts in race results, but is excluded from pace and five-minute averages +## Video guides -Example: -- track around `16 sec/lap` -- `Min lap time = 11 sec` -- `Max lap time = 120 sec` to begin a new stint after a two-minute interruption +Short narrated recordings (`.mkv`, H.264/AAC), also linked from the in-app Guide: -### Invalid passings -- `Timing -> Recent Passings` shows both valid and invalid passings -- displayed statuses include: - - `Short lap` for an invalid shortcut/false hit - - `Long lap · counted · new stint` when max is exceeded -- invalid passings are visually highlighted; counted long laps remain in the race result +- **Getting started:** [Connect a decoder](docs/videos/connect-decoder.mkv) · [Add drivers and cars](docs/videos/add-drivers-cars.mkv) · [Create a race](docs/videos/create-race.mkv) · [Run a session](docs/videos/run-a-session.mkv) +- **Interface tour:** [Settings tabs](docs/videos/settings-tabs.mkv) · [Event Manager tabs](docs/videos/event-manager-tabs.mkv) · [Race day schedule](docs/videos/event-schedule.mkv) -### Manual corrections -- open `Timing` -- click `Details` on a driver or team -- available actions: - - `+1 lap` - - `-1 lap` - - `+1 sec` - - `+5 sec` - - `-1 sec` - - `Reset correction` -- leaderboard and results update immediately - -### Best laps / average / consecutive -- Configure per session with `Seed Method` when `Best laps for seeding` is greater than `0` -- available modes: - - `Best N laps, total` - - `Best N laps, average` - - `Best N consecutive laps` -- leaderboard and standings use the correct format: - - total: `3/00:48.321` - - average: `3 avg 16.107` - - consecutive: `3 con 00:49.005` - -### Points tables and tie-break -- Configure in `Race Setup -> Manage -> Race Format` -- qualifying points tables: - - `Placement values (1,2,3...)` - - `Descending by field size` - - `10-9-8-7-6-5-4-3-2-1` -- qualifying tie-break options: - - `Compare counted rounds` - - `Best single lap` - - `Best round / heat result` -- qualifying standings also show an inline tie-break note in the table - -### Race format presets -- `Race Setup -> Manage -> Race Format` -- choose a preset and click `Apply preset` -- built-in presets: - - `Short technical track 16s` - - `Club race qual + finals` - - `IFMAR-style qual/finals` - - `Endurance / team race` -- after applying, all fields can still be adjusted manually and saved as usual -- `Save club preset` stores your own local presets in app state -- `Delete club preset` removes a local preset -- `Settings -> Club presets` can export/import the preset library as JSON between installations - -### Schedule drift on Dashboard -- `Dashboard` shows whether the day is ahead of or behind schedule -- planned time includes: - - session duration - - follow-up time -- actual time includes: - - real time from start to stop - - or live runtime if the session is still running - -### Invalid-lap marker in leaderboard -- if the latest passing for a driver or team is invalid, the row is marked in both leaderboard and overlay -- this makes it easier to see problems without staying in `Recent Passings` - -### Manual invalidate / restore last lap -- `Timing -> Details` -- `Invalidate last lap` marks the latest counted lap as manually invalid -- leaderboard, overlay, and lap history update immediately -- `Restore latest manually invalidated lap` puts the latest manually invalidated lap back if needed - -### Judging view -- separate `Judging` menu -- shows active session, leaderboard, lap history, and judging log in one view -- same corrections as `Timing -> Details` -- row filters: - - `All` - - `Invalid` - - `Corrected` - - `Team race` -- judging log can be exported per session as JSON -- supports `Undo latest` and per-log-row undo for multiple recent manual actions - -## Future improvements -- Optional neural text-to-speech for more natural start, finish, and driver-name announcements. -- Preferred design: generate speech through the backend, cache short audio files under `data/tts/`, and play cached audio without network delay during a race. -- Keep provider credentials on the backend only. Never expose API keys to the browser or public overlay. -- Retain the current system voice and passing beep as offline fallbacks. -- Support uploaded or prerecorded WAV/MP3 clips for fixed start and finish announcements. +Recorded with `node scripts/record-video-guides.mjs`, against an isolated test server. ## Installation -RC RaceCore runs on 64-bit Windows 11 and Linux. Use Node.js 22 or 24 LTS and npm 10 or newer. The repository includes `package-lock.json`, so use `npm ci` rather than `npm install` for repeatable installations. +RaceCore runs on 64-bit Windows 11 and Linux with Node.js 22 or 24 LTS and npm 10+. Use `npm ci` (the repository has a `package-lock.json`). -### Windows 11 - new computer +### Windows 11 -#### 1. Install Git +1. **Git:** run `git --version`. If it's missing, run `winget install --id Git.Git --exact --source winget` and reopen PowerShell, or use [Git for Windows](https://git-scm.com/download/win). Without Git, download the ZIP from [the repository](https://git.dio.nu/Public/Live_RC) and extract all of it. +2. **Download:** + ```powershell + Set-Location $HOME + git clone https://git.dio.nu/Public/Live_RC.git Live_RC + Set-Location .\Live_RC + ``` +3. **Install:** run `.\windows\install.bat` (or double-click it). It does the following: + - installs Node.js LTS if needed, plus the Visual C++ runtime that AMMC needs; + - runs `npm.cmd ci`; + - verifies Express, SQLite and AMMC; + - creates `data\` and `logs\`; + - starts RaceCore in the background. +4. **Check:** + ```powershell + npm.cmd run status + Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" + ``` + Then open `http://localhost:8081`, or `http://:8081` from another computer. -Open PowerShell and check whether Git is available: +Use `npm.cmd` in PowerShell; it avoids the "running scripts is disabled" error. Manual install without the script: `npm.cmd ci`, `npm.cmd run verify`, `npm.cmd start`. Don't use `--ignore-scripts`, because SQLite needs its install script. -```powershell -git --version -``` - -If Windows reports that `git` is not recognized, install Git with Windows Package Manager: - -```powershell -winget install --id Git.Git --exact --source winget -``` - -Close and reopen PowerShell after installation, then run `git --version` again. If `winget` is unavailable, install Git for Windows from [git-scm.com](https://git-scm.com/download/win). - -#### 2. Download RC RaceCore - -Clone the public repository from a normal PowerShell prompt: - -```powershell -Set-Location $HOME -git clone https://git.dio.nu/Public/Live_RC.git Live_RC -Set-Location .\Live_RC -``` - -Enter the raw URL exactly as shown. Do not paste Markdown syntax such as `[https://...](https://...)` into PowerShell. - -If you do not want to install Git, open [the public repository](https://git.dio.nu/Public/Live_RC), download its ZIP archive, and extract the complete archive. Make sure `package.json`, `server.js`, `src\`, and `windows\` are all in the same project directory. - -#### 3. Run the Windows installer - -From the project directory: - -```powershell -.\windows\install.bat -``` - -You can also double-click `windows\install.bat` in Explorer. The installer: - -- installs Node.js LTS through `winget` when Node is missing or unsupported -- installs/checks the Microsoft Visual C++ runtime used by AMMC -- runs `npm.cmd ci` using the locked dependency versions -- verifies Express, SQLite, and bundled AMMC files -- creates `data\` and `logs\` -- runs `npm.cmd restart` and leaves RC RaceCore running in the background - -If the installer cannot install Node automatically, install Node.js 22 or 24 LTS from [nodejs.org](https://nodejs.org/en/download), reopen PowerShell, and run the installer again. - -#### 4. Verify and open the application - -```powershell -npm.cmd run status -Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" -``` - -Open: - -```text -http://localhost:8081 -``` - -To open RC RaceCore from another computer on the race LAN, run `ipconfig` on the server and use: - -```text -http://:8081 -``` - -Use `npm.cmd` in PowerShell. This bypasses the common `npm.ps1 cannot be loaded because running scripts is disabled` error. Plain `npm` normally works in Command Prompt. - -#### Windows manual installation - -If you do not use `install.bat`: - -```powershell -node --version -npm.cmd --version -npm.cmd ci -npm.cmd run verify -npm.cmd start -``` - -Do not use `npm.cmd ci --ignore-scripts`. The native SQLite dependency needs its install script. - -### Linux - Ubuntu/Debian - -#### 1. Install Git and basic tools - -```bash -sudo apt update -sudo apt install -y git curl build-essential -git --version -``` - -#### 2. Install Node.js 22 LTS when needed - -Check the installed version: - -```bash -node --version -npm --version -``` - -If Node is missing or older than version 22, install Node.js 22 from NodeSource: +### Linux (Ubuntu/Debian) ```bash +sudo apt update && sudo apt install -y git curl build-essential +# Node.js 22 if "node --version" is missing or older: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs -node --version -npm --version -``` - -Node.js 22 or 24 LTS is recommended. Node.js 18 and 20 are not supported by the current native SQLite dependency. - -The bundled x86-64 Linux AMMC tools in `AMMC/linux_x86-64` require **GLIBC 2.39 or newer**. This includes the decoder converters and `ammc-sim`. Check the host before race day with `ldd --version` and `npm run verify`. Older distributions can still run RC RaceCore, but must use AMMC binaries built for their GLIBC version or run AMMC on another compatible host. - -#### 3. Clone, install, and start - -```bash -mkdir -p ~/git -cd ~/git git clone https://git.dio.nu/Public/Live_RC.git Live_RC cd Live_RC npm ci @@ -660,104 +332,33 @@ npm run verify chmod +x AMMC/linux_x86-64/ammc-* npm start npm run status -curl http://127.0.0.1:8081/api/health ``` -`npm start` launches RC RaceCore in the background. Open `http://localhost:8081`, or find the Linux server address with `hostname -I` and open `http://:8081` from another computer. - -If the bundled AMMC reports `version 'GLIBC_2.39' not found`, the host is too old for that binary. Use a compatible AMMC build or a Linux distribution with GLIBC 2.39+. Do not manually replace the operating system's GLIBC because that can break the whole system. - -`AMMC/linux_x86-64/ammc-sim` and `AMMC/windows64/ammc-sim.exe` can emulate an AMB decoder with selected transponders. This is useful for training, overlay tests, and load tests without a physical decoder. See `docs/decoder-setup.md` for a complete example. +Open `http://localhost:8081`, or `http://:8081`. The bundled Linux AMMC needs **GLIBC 2.39+** (`ldd --version`). On older systems, use a matching AMMC build or run AMMC on another host; never replace the system GLIBC. ### Runtime commands -Windows PowerShell: +| Command (Windows: `npm.cmd ...`) | What it does | +|---|---| +| `npm start` | Start in the background | +| `npm run status` | Is it running? (PID in `data/server.pid`) | +| `npm restart` | Restart after an update | +| `npm stop` | Stop | +| `npm run start:fg` | Run in the terminal and show errors directly | +| `npm run tts:install` | Install Piper and the standard voices | -```powershell -npm.cmd start -npm.cmd run status -npm.cmd restart -npm.cmd stop -npm.cmd run start:fg -``` +Logs go to `logs/server.out.log` and `logs/server.err.log`; data is kept in `data/`. -Linux: +The `windows\` helper scripts: +- `install.bat`: install, verify and restart. +- `start_backend.bat` and `restart_backend.bat`: start or restart the server. +- `start_ammc.bat`: start AMMC. +- `start_all.bat`: start AMMC and the server, then open the browser. +- `stop_all.bat`: stop the server and AMMC. -```bash -npm start -npm run status -npm restart -npm stop -npm run start:fg -``` +### Update without losing data -- `start` runs the backend in the background -- `status` reports whether the PID in `data/server.pid` is running -- `restart` reloads backend changes -- `stop` stops the managed process -- `start:fg` runs in the current terminal and displays startup errors directly -- stdout is written to `logs/server.out.log` -- stderr is written to `logs/server.err.log` -- SQLite data is stored in `data/rc_timing.sqlite` - -### Windows helper scripts - -- `windows\install.bat`: install dependencies, verify, and restart -- `windows\start_backend.bat`: start the backend in the background -- `windows\restart_backend.bat`: restart after copied or pulled updates -- `windows\start_ammc.bat`: start bundled AMMC manually -- `windows\start_all.bat`: start AMMC and backend, then open the browser -- `windows\stop_all.bat`: stop the backend and `ammc-amb.exe` - -### Restore a server backup - -Backups are stored in `data/backups/`. Restore is intentionally a local server command and is not exposed through the unauthenticated web API. - -1. Stop RC RaceCore. -2. Copy the backup filename from `Settings -> Storage` or list the files in `data/backups/`. -3. Run the restore command with the explicit confirmation flag. -4. Start RC RaceCore again. - -Windows PowerShell: - -```powershell -npm.cmd stop -$backup = Get-ChildItem .\data\backups\*.sqlite | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -$backup.Name -npm.cmd run backup:restore -- $backup.Name --confirm -npm.cmd start -``` - -Linux: - -```bash -npm stop -backup=$(find data/backups -maxdepth 1 -name '*.sqlite' -printf '%T@ %f -' | sort -nr | head -n 1 | cut -d' ' -f2-) -printf 'Restoring %s -' "$backup" -npm run backup:restore -- "$backup" --confirm -npm start -``` - -The restore command validates the selected SQLite file and creates a `pre_restore` backup of the current database before replacing it. - -### Update an existing installation without losing data - -The SQLite database and local configuration are in `data/`. Do not delete or replace this directory during an update. - -Windows: - -```powershell -npm.cmd stop -git pull --ff-only -npm.cmd ci -npm.cmd run verify -npm.cmd restart -npm.cmd run status -``` - -Linux: +Never delete `data/`. To update: ```bash npm stop @@ -765,149 +366,55 @@ git pull --ff-only npm ci npm run verify npm restart -npm run status ``` -If the installation came from a ZIP archive instead of Git, back up `data/`, extract the new application files, restore/retain the existing `data/` directory, run `npm ci`, and restart. Never copy `node_modules/` between Windows and Linux. +On Windows, use the same commands with `npm.cmd`. The menu shows when an update is available, and the update can also be run from Settings → System & backup. For a ZIP installation, keep `data/` and never copy `node_modules/` between Windows and Linux. -## Connect to AMMC -There are two supported modes. +### Restore a server backup -For the complete network diagram, ready-to-use 1/2/3/4-decoder examples, firewall setup, and troubleshooting, see [`docs/decoder-setup.md`](docs/decoder-setup.md). Swedish: [`docs/decoder-setup.sv.md`](docs/decoder-setup.sv.md). +Backups are in `data/backups/`. Restore is a local command, on purpose: -### A. Managed AMMC from the web UI -Important: -- AMMC runs on the same host where the backend was started with `npm.cmd start` -- if you only browse from another laptop, no process starts there -- the `AMMC executable` field in `Settings` is a path on the backend host, not the client browser machine - -#### Decoder topology - -| Role | Physical placement | Example decoder IP | AMMC WS port | Effect | -|---|---|---:|---:|---| -| Main start/finish | Start/finish loop | `192.168.1.10` | `9000` | Counts laps and controls lap time | -| Split | Intermediate loop | `192.168.1.11` | `9001` | Records split from the latest main crossing; never counts a lap | -| Pit entry | Entry to pit lane | `192.168.1.12` | `9002` | Opens a pit stop | -| Pit exit | Exit from pit lane | `192.168.1.13` | `9003` | Closes and times a pit stop | - -The decoder IP and WebSocket address are different things. The decoder IP points from AMMC to physical hardware. The browser connects to AMMC on the backend host, for example `ws://192.168.1.100:9001`. Each decoder must have a unique network address and each AMMC process must have a unique WebSocket port. - -Use only the channels physically installed at the track. One decoder on `9000` remains the default and needs no optional settings. Split timing requires one additional decoder. Pit timing requires two additional decoders because entry and exit are separate events. A complete setup therefore uses four decoders. - -Split and pit data is available in several places: -- `Timing` shows the active heat summary and complete pit-stop log live. -- `Race Setup -> Manage -> Live / results` shows the summary and pit log for every heat, including long 45-minute endurance heats. -- regular and team result exports include split/pit summaries and the complete entry/exit log in PDF. -- `Training -> More statistics` aggregates split and pit performance for the selected personal driver profile and class; different classes are never mixed. -- the personal mobile profile shows only sanitized counts and aggregate times for the selected class. It never exposes transponders, other drivers, or the raw pit-stop log. - -If a team changes driver or car between pit entry and pit exit, the completed stop remains attributed to the driver, car, and transponder detected at pit entry. The exit transponder is retained separately for diagnostics. - -1. Place AMMC binaries in the `AMMC/` project folder. -2. Open `Settings`. -3. Enable `Managed AMMC`. -4. Set the Main `Decoder IP / host`, verify port `9000`, and optionally enable/configure Split and Pit channels from the table above. -5. Click `Start AMMC`. -6. Click `Use server WS URL` so the client uses for example `ws://:9000`. - -Default binaries: -- Linux host: `AMMC/linux_x86-64/ammc-amb` -- Windows host: `AMMC/windows64/ammc-amb.exe` -- macOS host: `AMMC/apple_m/ammc-amb` - -### B. Manual start -Example: -```powershell -ammc-amb.exe -w 9000 192.168.1.10 -``` - -Complete four-decoder example, using four separate terminals/processes: -```powershell -ammc-amb.exe -w 9000 192.168.1.10 -ammc-amb.exe -w 9001 192.168.1.11 -ammc-amb.exe -w 9002 192.168.1.12 -ammc-amb.exe -w 9003 192.168.1.13 -``` - -In the app: -1. Open `Settings` -2. Set `WebSocket URL`, for example `ws://127.0.0.1:9000` -3. Set `Backend URL` to `http://127.0.0.1:8081` -4. Click `Test Backend` -5. Go to `Timing` and click `Connect Decoder` - -If Linux firewall/UFW is enabled: ```bash -sudo ufw allow 8081/tcp -sudo ufw allow 9000:9003/tcp +npm stop +npm run backup:restore -- .sqlite --confirm +npm start ``` -## Auto reload during development -- The server watches `index.html`, `src/app.js`, and `src/styles.css` -- When files in `Live_RC` change, the client reloads automatically -- If backend code changes on Windows, run `npm.cmd restart` +On Windows, find the latest file with `Get-ChildItem .\data\backups\*.sqlite | Sort-Object LastWriteTime -Descending | Select-Object -First 1`. The restore validates the file and first takes a `pre_restore` backup of the current database. -## Verify SQLite persistence -Latest passings via API: -- `http://localhost:8081/api/passings` +## Decoders and AMMC -Saved app state via API: -- `http://localhost:8081/api/state` +The full guide, with network diagrams, 1-4 decoder examples, firewall setup and troubleshooting, is [docs/decoder-setup.md](docs/decoder-setup.md) (Swedish: [docs/decoder-setup.sv.md](docs/decoder-setup.sv.md)). -## Important rule for sponsor events -- In the same running session, every active car must have a unique transponder ID -- The same transponder ID can be reused in the next session (`Heat 1 -> Heat 2 -> Heat 3 -> Final 1 ...`) +| Role | Placement | Example decoder IP | AMMC WS port | Effect | +|---|---|---:|---:|---| +| Main | Start/finish loop | `192.168.1.10` | `9000` | Counts laps | +| Split | Intermediate loop | `192.168.1.11` | `9001` | Split time, never a lap | +| Pit entry | Pit lane entry | `192.168.1.12` | `9002` | Opens a pit stop | +| Pit exit | Pit lane exit | `192.168.1.13` | `9003` | Closes and times it | -## AMMC JSON reference -Official quick start: -- https://www.ammconverter.eu/docs/intro/quick-start/ +**Managed AMMC** (Settings): +1. Enable Managed AMMC. +2. Enter the decoder IP for each channel. +3. Click **Start AMMC**, then **Use server WS URL**. + +AMMC runs on the server computer, not in the browser. The bundled binaries are in `AMMC/windows64`, `AMMC/linux_x86-64` and `AMMC/apple_m`. + +**Manual start:** run one `ammc-amb -w ` per decoder. In Settings, set the WebSocket URL (e.g. `ws://:9000`) and press **Connect decoder**. The browser connects to the AMMC host, not the decoder itself. On Linux with UFW, run `sudo ufw allow 8081/tcp` and `sudo ufw allow 9000:9003/tcp`. + +**Diagnostics:** Settings → Decoder / socket diagnostics shows each channel's connection, frames and passings, the latest raw message and 50 events. **`ammc-sim`** emulates a decoder with chosen transponders, for training and testing without hardware. + +AMMC sends PASSING messages like this ([AMMC docs](https://www.ammconverter.eu/docs/intro/quick-start/)): -Example message: ```json -{ - "msg": "PASSING", - "passing_number": 1, - "transponder": 232323, - "rtc_time": "2022-10-11T22:57:36.099+02:00", - "strength": 0.0, - "resend": false, - "tran_code": "ID:232323", - "loop_id": "55" -} +{ "msg": "PASSING", "passing_number": 1, "transponder": 232323, "rtc_time": "2022-10-11T22:57:36.099+02:00", "strength": 0.0, "resend": false, "loop_id": "55" } ``` -## Race audio and start lights +## Development and tests -The repository includes `rc-race-sound-pack/`. `sound_manifest.json` is the source of truth for event-to-WAV and Swedish/English announcement mappings. The server exposes it at `/race-sounds/sound_manifest.json`; WAV files are served from `/race-sounds/sounds/effects/`. - -1. Open `Settings -> Race sounds and announcements`. -2. Select `sv` or `en`, choose an installed Race voice, then set its speed, pitch, and master/effects/voice/passing volume. The offline race-controller defaults are speed `1.08` and pitch `0.90`; prerecorded or neural clips are still required for genuinely human announcer quality. -3. Enable or disable effect and voice independently for each event and use its Test button. Changes save automatically, and the section also has its own Save button. WAV effects are prerecorded; voice announcements use the operating system Web Speech voices. -4. Select a 0/10/30/60-second pre-start, start lights, and random delay limits. For timed race sessions the clock starts at the same callback that initiates the start tone. Open/Free Practice starts immediately. -5. Use the Race Control buttons in `Timing` for Track call, Track clear, Red flag, False start, and Marshal warning. - -Effects are asynchronous and never awaited by decoder processing. Critical speech interrupts lower-priority speech; short passing effects may overlap. Missing WAV files are ignored safely. A driver or car may select `pass_01.wav` through `pass_08.wav`; until those optional files exist under `rc-race-sound-pack/sounds/effects/`, playback falls back to `transponder_pass.wav`. - -Implemented automatic hooks include passings, personal/meeting best, fastest lap, historical class track record, leader and position changes, pit entry/exit, 60/30/10 seconds remaining, final lap/time expired, finish, winner, and podium. Penalty announcements reuse the existing judging correction action. - -## Reliability checks and save status - -The menu shows server connection, pending changes, saving, confirmed saves and save failures. It also shows the latest successful data load/save times. A visible warning indicates a lost or stale server connection; a successful health check does not clear a failed save. Use **Retry** to resend local changes. Server connection and decoder connection are separate indicators. Keep the tab open while changes are unsaved. - -New browser profiles use the page origin (including its port) as the default backend URL. An explicitly configured backend URL takes precedence. - -Run `npm test` for logic and API regression tests. Run `npm run test:browser` (Windows PowerShell: `npm.cmd run test:browser`) for real create/edit/reload checks of classes, drivers and cars, draft retention during background polling, and offline-save/retry behavior. Chrome, Chromium or Edge must be installed; set `CHROME_PATH` if its executable is not found automatically. The runner creates a temporary server database and browser profile and removes them on exit. It does not use your normal race data or start a decoder. See ROADMAP.md for workflows not yet covered. - -Browser coverage also includes sponsor-event edits, the endurance race wizard, team creation/membership edits/deletion, Open Practice to team-race conversion, and lap-limit persistence. Overlay sort headings align with their columns; narrow displays scroll the headings and rows together. - -### Decoder Socket Diagnostics - -Open **Settings > Decoder / socket diagnostics** to inspect Main, Split, Pit entry and Pit exit independently. Each channel shows its saved WebSocket URL, the actual socket URL, connection/reception times and counters. A connected socket alone does not prove that the decoder is sending passings. - -Use the AMMC host IP in WebSocket URLs (for example `ws://192.168.1.75:9000`), not the physical decoder IP. Give each AMMC channel its own port; enable only installed channels. `127.0.0.1` means the computer running the browser. - -Frames include all received WebSocket messages; PASSING counts recognized passing messages, not accepted laps. Handled includes split/pit events and start references. Ignored, invalid laps and JSON errors are separate. Select a channel to inspect its latest raw frame and 50 diagnostic events. Pause freezes only this display; Clear resets only that channel's diagnostic counters/log, preserving connection timestamps. Copy provides a manual fallback on plain HTTP. Diagnostics are local to this browser, memory-only, capped at 512 characters per sample, and reset on page reload. They neither change timing nor expose a new public API. Logs may contain transponder numbers; review before sharing. - -### Mobile Profile Connection Status - -The personal training link displays the last successful data retrieval. After 30 seconds without applying fresh data, it warns that statistics may be outdated (including when updates are deferred during input). A failed request keeps existing statistics and shows **Retry**. Finish any active input before retrying. Requests time out after 15 seconds; automatic polling continues every 10 seconds while the page is visible, without overlapping requests. The status describes profile retrieval, not decoder connectivity or confirmation that a car-change marker was saved. +- **Unit, logic and API tests:** `npm test`. The SQLite integration tests start their own server against a temporary database and never touch `data/`. +- **Browser tests:** `npm run test:browser`. They need Chrome, Chromium or Edge (set `CHROME_PATH` if it isn't found), and run against an isolated server with a fake decoder. +- **Screenshots and video guides:** `node scripts/capture-screenshots.mjs [name]` and `node scripts/record-video-guides.mjs`. +- **Docs:** the module overview is [docs/javascript-architecture.md](docs/javascript-architecture.md), and planned and finished work is in [ROADMAP.md](ROADMAP.md). +- **Auto reload:** the client reloads when `index.html` or frontend files change. After backend changes, run `npm restart`. +- **Raw data:** `/api/passings` (latest passings) and `/api/state` (app state), on the local network only. diff --git a/README.sv.md b/README.sv.md index e41dc4e..90d532a 100644 --- a/README.sv.md +++ b/README.sv.md @@ -1,394 +1,282 @@ # RC RaceCore -Planerade förbättringar och avbockningsbara delmål finns i [ROADMAP.md](ROADMAP.md). +Tidtagning och tävlingsledning för RC-klubbar. Systemet har livetidtagning från AMB/MyLaps-decoders via AMMC och en Race Day-sida med startförfarande som i EFRA/IFMAR. Det har också: +- kval och finaler, serier och cuper; +- träningsstatistik med personliga mobilprofiler; +- utrop med offlineröst; +- overlays för skärmar och OBS. -Versionen som körs visas längst ned i menyn och hämtas från `package.json`. Ändringar dokumenteras i [CHANGELOG.md](CHANGELOG.md). +Allt körs lokalt på en dator (Windows eller Linux) med en SQLite-databas. Ingen molntjänst och inget internet behövs på banan. -RC timing app med sponsor-eventflöde (delade bilar/transpondrar mellan olika heat/finaler), AMMC WebSocket och lokal SQLite-lagring på Windows. +English version: [README.md](README.md) · Ändringar: [CHANGELOG.md](CHANGELOG.md) · Planer: [ROADMAP.md](ROADMAP.md) · Versionen som körs visas längst ner i menyn. -## Arkitektur +## Innehåll -- JavaScript-modulöversikt: `docs/javascript-architecture.md` -- Säkerhets- och prestandaaudit: `docs/security-performance-audit.md` -- Primär engelsk README: `README.md` +- [Höjdpunkter](#höjdpunkter) +- [Skärmbilder](#skärmbilder) +- [Snabbstart](#snabbstart) +- [Använda RaceCore](#använda-racecore) + - [Race day](#race-day) + - [Skapa race](#skapa-race) + - [Serie / cup](#serie--cup) + - [Träning och träningsstatistik](#träning-och-träningsstatistik) + - [Ljud och utrop](#ljud-och-utrop) + - [Overlays och OBS](#overlays-och-obs) + - [Sponsorevent med delade bilar](#sponsorevent-med-delade-bilar) + - [Data, backup och export/import](#data-backup-och-exportimport) + - [Säkerhet](#säkerhet) +- [Videoguider](#videoguider) +- [Installation](#installation) +- [Decoders och AMMC](#decoders-och-ammc) +- [Utveckling och tester](#utveckling-och-tester) -## Snabbinstallation På Windows 11 +## Höjdpunkter -Öppna **PowerShell** på den nya Windows-datorn och följ stegen nedan. - -1. Kontrollera om Git är installerat: - -```powershell -git --version -``` - -2. Om `git` inte känns igen installerar du det och öppnar sedan PowerShell på nytt: - -```powershell -winget install --id Git.Git --exact --source winget -``` - -3. Hämta RC RaceCore och gå till projektmappen: - -```powershell -Set-Location $HOME -git clone https://git.dio.nu/Public/Live_RC.git Live_RC -Set-Location .\Live_RC -``` - -4. Kör hela installationen. Den installerar/kontrollerar Node.js, installerar npm-dependencies, verifierar SQLite och startar servern i bakgrunden: - -```powershell -.\windows\install.bat -``` - -5. Kontrollera servern och öppna `http://localhost:8081`: - -```powershell -npm.cmd run status -Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" -``` - -Om `winget` saknas installerar du [Git för Windows](https://git-scm.com/download/win). Repot kan även hämtas som ZIP utan Git. Se den kompletta delen [Installation](#installation) för ZIP-installation, LAN-åtkomst, uppdateringar och felsökning. +- **Race Day-sida** med heat-kö, förkontroll och start med ett klick. +- **Startförfarande som i EFRA/IFMAR:** nedräkning med utrop (2 min, 1 min, 30 s, 10 s, 9..3), paus medan bilarna ställs upp, flygande start för kval och gridstart med startljus och slumpad startsignal för finaler. +- **Transponderkontroll** under nedräkningen: grön bock för varje förare som passerat, och fel transponder rättas med ett klick. +- **Kval och finaler:** skapas från deltagarlistan med jämnt fördelade heat, A/B/C-finaler, bump-up, poängtabeller, tie-break och grid med dra-och-släpp. +- **Serie / cup:** poängtabell, bästa N eller stryk X, val för endast klubbmedlemmar, ställning per klass och varje deltävling sköts från seriesidan. +- **Domarvy:** straff och varvändringar, allt loggat och ångringsbart. +- **Träningsstatistik** per förare, klass och banlayout: stints, jämnhet, utmärkelser, mål och en personlig mobilprofil med QR-kod. +- **Ren statistik:** misstänkt korta träningsvarv (genvägar) flaggas automatiskt och tas bort med ett klick. +- **Utrop** på svenska eller engelska med lokal neural röst (Piper, offline). Under race spelas bara passeringsljud, som i tidtagningssystem. +- **Overlays** för skärmar och OBS, med placeringar vunna/förlorade sedan start. +- **Säker data:** SQLite, automatisk backup före varje start, full export/import och valfri admin-PIN. ## Skärmbilder -Aktuella layouter för racedrift, livevisning, träning och systemkonfiguration. Klicka på en bild för att öppna den i full upplösning. +Klicka på en bild för full upplösning. - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + +
Översikt med aktiv session
Översikt med aktiv session
Race Setup-wizard
Race Setup-wizard
Race Setup-guiden
Race Setup-guiden
Komplett live-overlay
Komplett live-overlay
Fullständig liveoverlay
Fullständig liveoverlay
Leaderboard-overlay
Leaderboard-overlay
Träningsöversikt
Träningsöversikt
Fördjupad träningsstatistik med tempo-heatmap och stintanalys
Fördjupad träningsstatistik
Domare och racekorrigeringar
Domare och racekorrigeringar
Raceljud och utrop
Raceljud och utrop
Decoderinställningar
Decoderinställningar
Hanterad AMMC-konfiguration
Hanterad AMMC-konfiguration
Inbyggd uppstartsguide
Inbyggd uppstartsguide
Event Managers flik Live & resultat
Event Managers flik Live & resultat
Översikt över träningsstatistik
Träningsstatistik, översikt
Detaljerad träningsstatistik med tempokarta och stintanalys
Detaljerad träningsstatistik
Serie / cup med numrerade steg
Serie / cup
Domarvy och racekorrigeringar
Domarvy och korrigeringar
Raceljud och utrop
Raceljud och utrop
Event Managers flik Live & resultat
Event Managers flik Live & resultat
Decoderinställningar
Decoderinställningar
Hanterad AMMC
Hanterad AMMC
Inbyggd guide
Inbyggd guide
-## Videoguider +## Snabbstart -Korta berättade skärminspelningar för nya användare, länkade även från den inbyggda Guide-sidan. Klicka på en länk för att ladda ner/spela upp `.mkv`-filen (H.264/AAC). +**Windows 11** (PowerShell): -**Kom igång** -- [Koppla en dekoder](docs/videos/connect-decoder.mkv) - länka dekodern i Settings, och se automatisk återanslutning efter en tappad anslutning -- [Lägg till förare och bilar](docs/videos/add-drivers-cars.mkv) - skapa en klass, en förare och en bil -- [Skapa ett race](docs/videos/create-race.mkv) - Race Setup-wizardens 4 steg, från start till mål -- [Kör en session](docs/videos/run-a-session.mkv) - Start med riktig nedräkning och startljus, Pause, Resume, Finish, och sedan Timing +```powershell +winget install --id Git.Git --exact --source winget # bara om "git --version" inte fungerar +Set-Location $HOME +git clone https://git.dio.nu/Public/Live_RC.git Live_RC +Set-Location .\Live_RC +.\windows\install.bat +``` -**Genomgång av gränssnittet** -- [Settings-flikar](docs/videos/settings-tabs.mkv) -- [Event Manager-flikar](docs/videos/event-manager-tabs.mkv) -- [Race day-schema](docs/videos/event-schedule.mkv) - -Dessa genereras om med `node scripts/record-video-guides.mjs` (se skriptets header) när ett täckt flöde ändras så mycket att inspelningen inte längre stämmer med verkligheten. - -## Bättre Röst Offline (Piper) - -Utropen kan använda en lokal neural röst i stället för webbläsarens systemröst - gratis, inget konto, och den fungerar även utan internet vid banan. Svenska och engelska installeras tillsammans: +**Linux (Ubuntu/Debian)** med Node.js 22 eller 24: ```bash -npm run tts:install +git clone https://git.dio.nu/Public/Live_RC.git Live_RC +cd Live_RC +npm ci && npm run verify +npm start ``` -eller klicka **Installera** under Inställningar -> Ljud -> Röstmotor. Det hämtar den fristående Piper-versionen för ditt operativsystem (Linux, Windows, macOS - ingen Python behövs) plus en manlig och en kvinnlig röst per språk - svenska NST (man) och Lisa (kvinna), engelska Ryan (man) och Lessac (kvinna) - till `piper/` (cirka 300 MB). Internet behövs bara under installationen. Välj sedan **Lokal röst**, välj svensk och engelsk röst (man är förvald) och klicka **Förgenerera fraser och förarnamn** före racedagen. Saknas Piper eller dröjer den tar webbläsarens röst över automatiskt. Fler röster hämtas en i taget under **Fler röster** i samma panel (ca 63 MB var): svenska Alma (kvinna), brittiska Alan och Northern English (män), Cori (kvinna), skotska Alba (kvinna) och amerikanska Joe, John och Norman (män). Valfria inställningar: `RC_PIPER_BIN` (sökväg till en piper-fil) och `RC_PIPER_VOICES_DIR` (extra röstmapp). +Öppna sedan `http://localhost:8081`, eller `http://:8081` från en annan dator i racenätverket. **Guiden** i menyn och [videoguiderna](#videoguider) visar hur man ansluter decodern, lägger in förare och skapar första racet. Alla steg: [Installation](#installation). -## Publik Overlay Och OBS +## Använda RaceCore -Appen har nu en separat publik overlay-route så att du inte behöver exponera hela admin-UI:t externt. +Menyn följer hur en tävlingsdag går till: +- **Start:** Översikt, Race Day. +- **Skapa:** Race Setup, Sponsor Event, Serier / cup. +- **Kör och följ:** Tidtagning, Domare, Overlay, Träningsstatistik, Resultatarkiv. +- **Register:** Klasser, Förare, Bilar. +- **System och hjälp:** Inställningar, Guide. -- Publik overlay-route: `/public-overlay/` -- OBS-läge: `/public-overlay/obs` -- OBS-overlay konfigureras från menyn `Overlay`: - - antal rader - - layout: `leaderboard`, `grid`, `lowerthird` - - tema: `panel`, `transparent`, `chroma` - - vilka kolumner och block som ska visas -- Använd `Kopiera OBS-url` för att få en färdig browser-source-länk till OBS. +Gränssnittet finns på svenska och engelska. -Om du vill ha ett enkelt skydd för publika overlays, sätt denna miljövariabel på servern: +### Race day -```bash -PUBLIC_OVERLAY_TOKEN=din-hemliga-token -``` +**Race Day** är operatörens sida: +- **Heat-kön** visar aktuellt, nästa och därpå följande heat. +- **Förkontrollen** kontrollerar decoder, deltagare, transpondrar (saknade eller dubbletter), varvtidsgränser, grid och ljud. Blockerare visas först, var och en med en genväg till rätt inställning. Min/max-varvtid kan ändras direkt där. +- **En automatisk SQLite-backup** tas före varje start. -Tokenen skyddar bara overlay-routen. Ändringar via admin-API:t kan skyddas med en valfri admin-PIN (Inställningar -> System & backup; av som standard) och begränsas till vissa adresser med `RC_ADMIN_ALLOWED_CIDRS` (kommaseparerade IPv4-CIDR eller exakta IP:n, t.ex. `192.168.1.0/24`). Läsning är inte PIN-skyddad, så exponera fortfarande inte port `8081` direkt mot internet. Använd betrott race-LAN, VPN eller en autentiserad reverse proxy. Om webbgränssnittet avsiktligt körs från en annan origin anges den i `RC_ALLOWED_ORIGINS` (kommaseparerat). Se [`docs/security-performance-audit.md`](docs/security-performance-audit.md). +**Startförfarande (EFRA/IFMAR):** Start kör först en nedräkning. Välj Go, 30 s, 1, 1:30, 2, 3 eller 5 min; standard sätts per tävling för kval och final. +- **Under nedräkningen:** + - Banan är öppen. + - Speakern ropar "Heat 3 startar om 2 minuter", sedan varje minut, 30 s och 10 s. + - Vid gridstart ropar den dessutom "bilarna till startplatsen" vid 30 s och räknar 9..3. +- **Knappar:** + - **Pausa** (medan bilarna ställs upp) och **Fortsätt**. + - **+1 min**. + - **Till 30 s** (omstart av gridet). + - **Till 10 s**. + - **Go nu**, som varnar om förare som inte setts. + - **Avbryt**. +- **När tiden går ut startar heatet av sig självt.** + - **Gridstart** (mass/position): startljus och en slumpad startsignal inom 0-5 s. + - **Flygande start** (standard för kval): signalen och "Klockan går". Varje bils tid startar vid dess första passering, och en sen bil får klockan startad senast efter 150 % av ett varv (EFRA 9.3). + - **Staggered start:** bilarna ropas ut en och en. +- **Transponderkontroll:** varje förare i heatet får en grön bock när transpondern passerar under nedräkningen. Saknas någon kan transpondern bytas direkt i panelen, eller kopplas till en okänd transponder som just passerat. +- **Paus, fortsätt och avsluta** fungerar under heatet. Follow-up-tid låter sista varvet köras klart efter klockan. -Då måste den publika overlay-länken innehålla: +**Tidtagning** visar livetopplistan (varv, gap till ledaren och framför, eget delta, bästa och senaste varv), senaste passeringar med ogiltiga korta varv markerade, grid vid positionsstart, repris av sessionen (1-10x) och speakerpanelen. -```text -/public-overlay/obs?token=din-hemliga-token -``` +**Domare** är platsen för korrigeringar i race: ±varv, ±sekunder och nollställ, samt ta bort eller återställa vilket varv som helst. Allt loggas med tid och kan ångras; loggen kan exporteras som JSON. I kval, heat och final är Domarvyn enda stället för straff; Tidtagning visar korrigeringarna och har knappen **Öppna i Domarvyn**. Träning har inga straff, men varv kan städas direkt i Tidtagning (se [träning](#träning-och-träningsstatistik)). -Rekommenderad deploy: -- publicera bara `/public-overlay/*` via reverse proxy -- håll huvudappen/admin internt +Varvkontroll: +- **Minsta varvtid** stoppar genvägar och falska träffar. +- **Längsta varvtid** startar en ny statistik-stint efter en paus; det långa varvet räknas ändå i racet. -## Vad som ingår -- Event-lägen: - - `Race (driver transponders)` - - `Track Event (shared cars)` -- UI-separering: - - `Event` = sponsor-event med delade bilar/transpondrar - - `Race Setup` = otidsstyrd Open Practice eller riktiga race med personlig transponder per förare -- Grupperad meny följer arbetsordningen: `Start`, `Skapa`, `Kör och följ`, `Register` samt `System och hjälp`. -- `Översikt -> Kom igång` länkar direkt till systeminställningar, förarregister, race/practice, Tidtagning och Overlay. -- Race Day-drift: - - förkontroll visar blockerare och varningar först med genvägar till rätt inställningar eller register; min/max-varvtid kan ändras direkt i Race Day - - fokuserad heat-kö med Pågår, Nästa och Därefter - - förkontroll av decoder, deltagare, transpondrar, dubbla ID, varvfönster, grid och ljud - - samma start-, stopp- och pauslogik som den befintliga Tidtagning-vyn - - automatisk konsistent SQLite-backup före varje sessionstart, full dataimport och datarensning - - de 30 senaste serverbackuperna visas under `Inställningar -> Lagring` - - isolerad session replay i `Tidtagning` med spela, pausa, reset och 1x/2x/5x/10x; källresultatet ändras aldrig -- Lagring/import: - - full export/import av race-data för backup eller flytt till annan maskin - - register-export/import för bara klasser, förare och bilar - - CSV-export och säker sammanslagande CSV-import för förare och bilar via Excel eller LibreOffice - - export/import av ett enskilt racepaket via `Race Setup -> Hantera -> Race actions` -- `Race Setup` innehåller nu även: - - `Snabbstart Open Practice`: ange bara ett namn, skapa en otidsstyrd session för alla transpondrar och fortsätt direkt till Tidtagning - - ingen klass, registrerad förare, preset, kval, final eller tidslängd krävs för Snabbstart Open Practice - - grupperade sektioner för `Deltagare` och `Lag` i `Hantera` - - en fyrstegs `Create Race Wizard` för nya race - - `Hantera` uppdelad i `Setup`, `Format`, `Generering` och `Live / resultat` - - Grundläge reagerar nu på valt preset, inklusive renare endurance-vy - - `Grundläge / Avancerat` för `Raceformat` - - en sammanfattningspanel till höger - - ett presetstyrt sammanfattningskort som växlar mellan endurance- och vanligt race-fokus - - statusbrickor för `Setup`, `Format`, `Generering` och `Live / resultat` - - sammanfattningsvarningar när deltagare, sessioner, lag eller varvfönster saknas - - klickbara sammanfattningsvarningar som hoppar till rätt del av Hantera - - klickbara stegkort som fungerar som snabbnavigering i `Hantera` - - kompaktare stegkort med levande räknare för t.ex. förare, lag, sessioner och aktiv/resultat-status - - separata `Race actions` för generering, reseeding och bump-up - - omgjord inbyggd `Guide` med översiktskort och tvåkolumnslayout - - välj exakt vilka förare som är med i racet - - practice-ranking - - kval-ranking med `poäng` eller `bästa resultat` - - inbyggd guide för hur man skapar race steg för steg - - beskrivningar direkt i alla fält under `Raceformat` - - `Follow-up tid` efter ordinarie racetid innan heatet stängs - - `Min varvtid` underkänner shortcuts/felträffar; `Max varvtid` startar en ny statistikstint utan att ta bort racevarvet - - seedmetoder för practice/kval: bästa N varv som summa, snitt eller konsekutiva varv - - valbar kval-poängtabell och tie-break-regler - - presets i `Raceformat` för kort teknisk bana, klubbrace, IFMAR-liknande upplägg och endurance - - schemaavvikelse på `Översikt` mellan planerad och faktisk körtid - - sessionstyp `Free Practice` för löpande varvtider utan seedning - - auto-generering av kvalheat från practice-ranking eller klasslista - - reseeding av kommande kvalheat från aktuell ranking - - auto-generering av `A/B/C...` finaler från ranking - - sparad manuell grid per session via dragbar grid-editor - - auto-reseed hoppar över heat där manuell grid har låsts tills du återställer den - - tydlig `Lås/Lås upp grid` i grid-editorn per session - - final-ranking över flera leg med räknade finalheat - - valbar `bump-up` mellan finaler - - reserverade bump-platser i högre finaler - - visuell finalmatris med reserverade bump-platser - - dragbar grid-editor för positionsstart - - utskrift/export av heatsheets per kval/final - - overlay-vy för extern leaderboard-skärm - - flera overlay-lägen: leaderboard, speaker och results - - speaker-overlay med eventmarkörer och separata speaker-cues - - live speaker-panel i `Timing` för att slå av/på cues under pågående session - - speaker-cues och klubbbranding för sidomeny, overlay, publik träningsprofil och PDF styrs från `Inställningar` - - uppladdad klubblogotyp används i sidomeny, overlay, publik träningsprofil och PDF - - branding per event/race med egen logo, tagline, footer och PDF-tema i `Hantera` - - extra speaker-cues för `session start`, `new best lap` och `top 3 change` - - valbart PDF-tema: `classic`, `minimal`, `motorsport` - - utskrift av startlistor och resultat med vald branding - - servergenererad PDF-export för startlistor, heatsheets och resultat med inbäddad logo - - genererade kval/finaler ärver tid och starttyp från raceformatet - - finish-ljud som siren i stället för browser-röst -- Sessioner: `practice`, `qualification`, `heat`, `final` -- Sponsor-verktyg: - - Skapa rundor automatiskt (`qualification`, `heat`, `final`) - - Auto-assign förare -> bil per session -- Live timing från AMMC WebSocket (`msg: "PASSING"`) -- Hanterad AMMC från webbgränssnittet: - - backend kan starta/stoppa lokal `ammc-amb` på Windows, Linux och macOS - - läser bundlade binärer från `AMMC/windows64`, `AMMC/linux_x86-64`, `AMMC/apple_m` -- Redigering i UI: - - Klasser, eventnamn/datum, förare och bilar kan redigeras direkt - - förare och bilar har valfria brandfält för team, sponsor, märke eller modell - - `Förare` och `Bilar` kan sökas på namn, transponder eller brand direkt i UI - - startlistor och heatsheets tar med förarens brand i print, CSV och PDF-export -- Live race-kontroll: - - Nedräkning under pågående session - - Auto-finish vid tidslut med status `Race is finished` - - Leaderboard-sortering: varv först, därefter närmast måltid för sessionen (t.ex. 5 min = 300s) - - Konfigurerbart browserljud för start, mål och passing (`blipp` eller tala förarnamn) - - Valbar systemröst, talhastighet/tonhöjd och separat fonetiskt uttalsnamn per förare - - Sessioninställningar för `Mass start`, `Position start`, `Staggered` - - `Timing` visar grid/startordning för aktiv `Position start`-session - - leaderboard visar både `gap till ledaren`, `gap till bilen framför` och `eget delta` mot förra varvet - - `Senaste passeringar` skiljer ogiltiga `För kort varv` från räknade långa varv som startar en ny stint - - manuella korrigeringar i `Tidtagning -> Detaljer`: `+1/-1 varv`, `+1/+5/-1 sek`, `Nollställ korrigering` - - Practice/Kval kan seedas på bästa `2` eller `3` varv i sessionsinställningar -- Persistens: - - Frontend state i browser (`localStorage`) - - Samma state + passeringar sparas i lokal SQLite via Node-backend -- Inbyggd `Guide`-meny i appen med steg-för-steg för: - - Sponsor-event (10 personer / 4 bilar) - - Vanligt race - - ogiltiga varv, follow-up och manuella korrigeringar - - AMMC + npm setup på Windows och Linux -- Språkval i UI: `SV` / `EN` +### Skapa race -## Träning Och Belöningar +**Race Setup** har två ingångar: +- **Snabbstart Open Practice:** bara ett namn. Den skapar en otidsatt session för alla transpondrar och går direkt till Tidtagning; ingen klass, förare eller format behövs. +- **Skapa race-guiden:** Grunder → Deltagare → Sessionsplan → Bekräfta. Välj klass och förval, bocka i förarna, och träning, kval (eller lagrace) skapas. -Menyn `Träning` ger förarna utveckling och delmål även mellan tävlingarna: +Efter det hanteras racet i fyra flikar (Race Setup → Hantera): +- **Deltagare & lag:** bocka i vilka som kör, och hantera lag för endurance. +- **Format:** + - kvalomgångar, bilar per heat, tid och starttyp (mass, position, staggered, flygande); + - seedning (bästa N varv sammanlagt, snitt eller i följd); + - poängtabell för kval (placering, efter fältstorlek, 10-9-8...) och tie-break; + - finaler: antal finalheat, räknade finalheat, bump-up och reserverade bump-platser; + - nedräkningens längd, follow-up-tid och min/max-varvtid; + - förval: kort teknisk bana, klubbrace, IFMAR-stil, endurance, eller egna sparade klubbförval; + - **Race actions** längst ner i fliken: + - skapa kval från träningen (eller deltagarlistan); heaten delas så jämnt som möjligt, till exempel 9 förare och max 8 per heat → 5 + 4; + - omseeda kommande heat; låsta manuella grid respekteras; + - skapa A/B/C-finaler och bump-up; + - exportera racet som ett paket. +- **Live & resultat:** + - grid-redigerare (dra och släpp) och låsning; + - ställning för träning, kval och final samt finalmatris; + - utskrift och PDF med klubbens profil; + - sammanfattning av split- och depåtider. +- **Schema & utskrift:** dagens körordning med planerade tider, och heatlistor. -Grundvyn är en klubböversikt med totaler och en separat rad per förare och klass. Välj en förare i listan för att öppna den avsiktligt enkla personliga vyn med fyra nyckeltal, nästa varvmål, dagens träningspass och aktiva belöningar. Administration av mål, mobildelning och detaljhistorik finns kvar i utfällbara sektioner när de behövs. +**Översikt** visar schemaavvikelse (planerad mot faktisk tid). **Resultatarkivet** hittar avslutade race utan att gå via Race Setup. -När Open Practice, Free Practice eller Practice pågår får vald förare ett kompakt livekort med aktuella giltiga varv, bästa varv, snitt och senaste varv. Sessionen är fortfarande gemensam för alla; endast mobilens personliga timer och profillänk är unik per förare och klass. Primärknappen högst upp skapar eller öppnar länken. +### Serie / cup -En person kan ha flera förarposter för exempelvis 2WD och 4WD och länka dem till samma `Träningsprofil` under `Förare`. Personen får då en profil och en mobillänk, men all prestandastatistik väljs och beräknas separat per klass. Flera transpondrar inom samma klass summeras däremot i den klassens statistik. +Menyn **Serier / cup** kör ett mästerskap över valfritt antal deltävlingar, med fritt valda klasser. Varje klass får en egen ställning. -Förarprofilen kan även lagra `Klubb` och `Land`. Värdena ärvs när ytterligare klassposter länkas till samma träningsprofil och följer med full JSON- och förar-CSV-export. De lämnas inte ut av den publika profillänken. +1. **Namn och klasser.** +2. **Poäng:** + - **Vem får poäng:** alla förare (öppen serie), eller endast klubbmedlemmar. Med endast medlemmar kör förare från andra klubbar och syns i dagens resultat men får inga seriepoäng, och medlemmarna rangordnas om utan dem. + - **Poängtabell:** ÖRC-tabellen (100, 90, 82, 75, 69 … sedan −4 per plats, lägst 10), 100-80-70, F1, eller en egen lista. + - **Räknade resultat:** bästa N (t.ex. 9 av 12), eller alla körda utom X sämsta. Då minskar antalet automatiskt om en deltävling ställs in. +3. **Deltävlingar:** klistra in datumen, så skapas ett race per datum och klass med valt antal kvalomgångar, finaler och max bilar per heat. Varje deltävling sköts sedan från sin rad: + - välj förare; + - **Kopiera från förra** deltävlingen; + - **Ny förare** för en efteranmälan; + - ändra formatet för just den deltävlingen (det kan skilja mellan deltävlingar och klasser); + - **Skapa kval** (heaten följer fältets storlek) och **Skapa finaler**; + - **Status** och **Öppna**. +4. **Ställning:** + - Dagens placering kommer från slutresultatet (A före B), sedan kvalordningen. + - Inget registrerat varv ger 0. Frånvaro räknas som 0 och kan strykas. + - Lika poäng avgörs av flest segrar, sedan andraplatser, sedan senaste gemensamma deltävling. + - Skriv ut eller exportera som PDF (breda tabeller blir liggande A4). -- beständig logg med totalt antal giltiga varv synkad från sparade sessionsresultat -- träningsdagar, antal sessioner, personbästa, total-/30-varvssnitt, kontrollerad varvserie och spridning -- automatisk ny stint vid inställd `Max varvtid`, med 2 minuter som reservregel för äldre eller okonfigurerad data -- bästa 3 sammanhängande varv samt bästa femminutersresultat med dess avg pace -- femminutersresultatet räknar slutvarvet om det startade före `5:00` (`300 s`), även när målgången sker efter tidsgränsen -- mobilprofil med tempograf, senaste klasspecifika stintar och daglig historik för de senaste träningsdagarna -- publiceringsval per profil för utveckling, utmärkelser, prestation/stints, mål/belöningar och historik; avstängda detaljsektioner filtreras av det publika API:t -- personlig utvecklingstrend som jämför de senaste 30 giltiga varven med föregående 30, alltid separat per klass -- automatiska achievements för första passet, varvmängd, träningsdagar, kontrollerade varvserier och fullföljd femminutersstint -- valbar personlig röstfeedback efter fem kontrollerade varv i samma practice-stint, med förarens uppläsningsnamn och cooldown per förare -- tre frivilliga dagsutmaningar för giltiga varv, kontrollerade varv i följd och fullföljd femminutersstint -- en positiv personlig summering som ger kredit för dagens mängd, personbästa, tempo, jämnhet och uthållighet utan att ranka förare -- klubbfeed sorterad på senaste aktivitet i stället för placering eller totalvarvsranking -- konfigurerbart gemensamt klubbmål som räknar alla nya giltiga träningsvarv från registrerade förare från det att målet skapas -- en gemensam hopfällbar Mer statistik-del med aktiva 30-minutersblock baserade på trimmat snitt -- klasspecifika setupmarkörer för däck, dämpare, bilbyte eller egen notering med automatisk jämförelse 30 minuter före/efter -- detaljerad stintanalys med normaltempo, bästa race pace över 10 varv, avvikande varv, tempohållning och starka avslutningar -- personlig kontrollzon, flytserier inom samma stint, rena femminuterspass och senaste förbättring av mellantid -- automatiska utvecklingsnivåer vid lämpliga varvantal utan manuell konfiguration -- rekommenderat träningspass med valbara minuter för maxfokus och kontrollerad körning på 80-90 procent -- egna varvmål med snabbval på `500`, `1000` och `1500` varv -- valfri reward/belöning och markering när den har delats ut -- responsiv layout som kan öppnas från mobilen via samma server i det lokala nätet +### Träning och träningsstatistik -Direktlänk för mobil/bokmärke: `http://:8081/?view=training`. När en profil och klass väljs läggs de i länken så rätt vy kan sparas som bokmärke. +**Träningspass:** +- Open Practice kan köras hela säsongen; Free Practice rankar på bästa varv. +- **Nollställ data** i Tidtagning rensar passet inför en ny dag, men alla varv finns kvar i träningsstatistiken. -Träningsstatistiken räknar just nu bara giltiga varv som är kopplade till en registrerad förare. Anonyma transpondrar från Open Practice räknas inte förrän de kopplats till en förare. +**Banlayouter:** +- Tryck **Ny layout** (på Träningsstatistik, Race Day eller Översikt) när banan byggs om. Ett pågående träningspass flyttas till den nya layouten, och bästa varven börjar om. +- Varje layout kan ha egen **min/max-varvtid** för träning. Race använder alltid tävlingens värden. +- Statistiken visas per layout, med en översikt för alla layouter. -Domarkorrigeringar uppdaterar loggade varv så länge källsessionen finns kvar. När sessionen senare tas bort ligger de synkade träningsvarven kvar så förarens livstidsutveckling inte försvinner. Full dataexport inkluderar varvloggen, belöningsmålen och setupmarkörerna. +**Misstänkt korta varv** (bara träning): +- Ett varv som är mycket snabbare än förarens egen nivå (under 85 % av medianen, efter 5 varv) flaggas ⚠, oftast en genväg av en nybörjare eller ett barn. +- Det räknas som ett varv men inte som bästa varv, rekord eller i statistiken förrän någon **Godkänner** det. +- **Ta bort** görs med ett klick, i panelen på Tidtagning och Race Day eller i förarens varvlista. -### Begränsad mobilprofil +**Träningsstatistik** (menyn): +- Klubböversikten och en sida per förare och klass visar: + - personbästa, snittider och jämnhet; + - bästa 3 varv i följd och bästa 5-minutersresultat; + - stintanalys, 30-minuters tempoblock och setup-markeringar med före/efter-jämförelse; + - dagshistorik och utmärkelser; + - mål med belöningar, dagliga utmaningar och ett gemensamt klubbmål. +- **Underlag: Träning** (standard), **Race** eller **Alla.** Racevarv hålls separat och märks 🏁 med tävling, pass och serie. Under Race visas de per racepass; ett race delas aldrig upp i stints. +- En person kan köra flera klasser. Koppla klassposterna till samma träningsprofil under Förare; statistiken hålls per klass. -Varje registrerad förare kan få en valfri personlig mobillänk: +**Mobilprofil:** +- Varje förare kan få en personlig länk med QR-kod. Den visar förarens egen statistik, en träningstimer, setup-markeringar och övningar (jämna varv, stegträning), och har val för tränings- eller racevarv. +- Länken använder en slumpad nyckel; inga transpondrar eller andra förare visas. +- För användning via internet, ange **den publika adressen** en gång för alla under Inställningar → System & backup → Publik adress (domän / DynDNS), till exempel `https://klubben.dyndns.org:8443`. Lämnas den tom används den lokala nätverksadressen. +- Publicera bara de här sökvägarna mot internet: `/public-training/*`, `/src/public_training.js` och `/src/public_training.css`. Färdiga Teltonika-filer finns i `scripts/teltonika/`. -1. Öppna `Träning` och välj föraren. -2. Öppna `Mål och mobilprofil` och klicka sedan `Aktivera mobilprofil`. -3. För internetdelning: ange den publika adressen en gång för alla förare under `Inställningar` -> `System & backup` -> `Publik adress (domän / DynDNS)`, exempelvis `https://racecore.example.org` eller `https://klubben.dyndns.org:8443`, och klicka `Spara`. Varje förares delningspanel visar adressen som används och har knappen `Ändra under Inställningar`. Lämna tomt för att använda den lokala nätverksadressen (fungerar bara på samma wifi). -4. Skanna `Lokal QR-kod` på samma nätverk som RaceCore, eller `Publik QR-kod` via internet. Den lokala QR-koden skapas från RaceCore-serverns LAN-IP och fungerar därför även om adminvyn öppnades som `localhost`. -5. Använd `Skapa ny länk` för att återkalla den gamla eller `Stäng av profil` för att stoppa delningen. Knappen `Hämta publik IP` är endast ett manuellt förslag; FQDN är rätt val när TLS-certifikatet använder domännamnet. +### Ljud och utrop -Länken använder en slumpad 192-bitars bearer-nyckel i stället för förar-ID. Samma länk visar profilens klasser i ett klassval, med helt separata varvtider och träningsresultat. Det publika API:t lämnar inte ut transponder-ID, andra förares namn, klubbrankning, race setup eller admin-state. Den enda skrivande mobilfunktionen är att lägga till en setupmarkör för länkens förare och vald kopplad klass. +Inställningar → Ljud: +- **Raceljud:** + - startljus, slumpad startfördröjning och passeringsljud (valfritt olika ton per förare/bil); + - utrop på svenska eller engelska för start, klocka (1 min, 30 s, 10 s), sista varv, målgång, vinnare och pall, depå, straff och tävlingsledning (stopp på banan, röd flagga, tjuvstart, marshal); + - varje händelse kan slås på eller av för effekt och röst. +- **Utrop under race:** "Bara passeringsljud" (standard, som tidtagningssystem) eller "Speaker" med namn, personbästa och ny ledare. Träning får alltid alla utrop. +- **Lokal neural röst (Piper):** gratis och fungerar offline. Installera under Inställningar → Ljud → Röstmotor, eller med `npm run tts:install`. + - Standardröster: svenska NST (man) och Lisa (kvinna), engelska Ryan (man) och Lessac (kvinna). + - Under **Fler röster**, en i taget (ca 63 MB var): svenska Alma; brittiska Alan, Northern English, Cori och Alba (skotsk); amerikanska Joe, John och Norman. + - Förgenerera fraser och förarnamn före racedagen. + - Saknas Piper tar webbläsarens röst över. +- **Uttalsnamn per förare:** skriv ett uttal eller smeknamn under Förare och tryck **🔊 Testa uttal** för att höra det i riktiga utrop. -Mobilens automatiska uppdatering pausas medan du redigerar ett fält eller sparar en biländring. Osparade bilanteckningar behålls separat per klass vid uppdateringar och klassbyte (tills sidan laddas om). Vid tillfälliga uppdateringsfel ligger senast laddad statistik kvar. +### Overlays och OBS -Prestationssektionen visar även aktiva 30-minutersblock och låter föraren markera en klasspecifik bil- eller setupändring. Öppna detaljsektioner ligger kvar utfällda under live-polling. +Menyn **Overlay** har lägena leaderboard, speaker, resultat, TV och lag, plus ett OBS-läge med layout (leaderboard, grid, lower third), tema (panel, transparent, chroma), rader och kolumner: +- Kolumner: varv, resultat, bästa, gap och **placering sedan start** (▲/▼ i heat och finaler). +- **Kopiera OBS-URL** ger en länk för browser source; valda kolumner ingår i länken. +- Publika overlays finns på `/public-overlay/` och kan kräva en nyckel: sätt `PUBLIC_OVERLAY_TOKEN` och lägg till `?token=...`. Publicera bara `/public-overlay/*` via din reverse proxy. +- Klubbprofilen (namn, logga, PDF-tema) används i menyn, overlays, mobilprofiler och PDF; den kan även sättas per tävling. -Mobilsidan har också en lokal träningstimer där föraren själv väljer minuter för `Maxfokus` och `Kontrollerad`. Standard är `10 + 10`, men ett femminutersheat kan exempelvis köras som `5 + 0`. Medan en gemensam Free Practice fortsätter vara igång visar kortet just den förarens antal varv, bästa varv och snitt sedan den personliga timern startades. Timer och tidsval sparas bara i mobilens webbläsare, separat per förare och klass, och ändrar ingen racedata. Tiderna låses medan passet pågår och kan ändras efter målgång eller nollställning. +### Sponsorevent med delade bilar -Vid extern publicering ska bara dessa paths proxas: +**Sponsor Event** låter många förare dela på några få bilar och transpondrar, till exempel 10 förare och 4 bilar: +- omgångar skapas automatiskt och förarna tilldelas bilar per session; +- inom en session måste varje bil ha en unik transponder, men samma transponder kan användas igen i nästa session. -```text -/public-training/* -/src/public_training.js -/src/public_training.css -``` +### Data, backup och export/import -Exponera inte `/api/state` eller hela admin-appen. Färdiga Teltonika-filer finns i `scripts/teltonika/`; init-scriptet skapar Nginx temporära RAM-kataloger vid varje boot och använder inte `nginx-util`. Statisk servering är begränsad till `/src` och `/docs`; `data/`, serverscripts och bundlade binärer publiceras inte som statiska filer. +- **Lagring:** + - Allt sparas i `data/rc_timing.sqlite`; webbläsaren håller en lokal kopia och synkar. + - Menyn visar sparstatus (sparat, väntar, misslyckades, med **Försök igen**). + - Domarkorrigeringar skickas direkt till servern. +- **Backup:** + - automatisk före varje sessionsstart, plus manuella; + - de senaste 30 listas under Inställningar; + - återställ med `npm run backup:restore` (se [Installation](#återställ-en-serverbackup)). +- **Export/import** (Inställningar → Lagring): + - full JSON, eller bara registret (klasser, förare, bilar); + - CSV för förare och bilar (Excel/LibreOffice; komma, semikolon eller tab). CSV-importen slår ihop: den matchar på id, sedan transponder, sedan namn + klass. + - ett enskilt racepaket från Race Setup; + - klubbförval. +- **Rensning:** förare, bilar, klasser, race eller träningsstatistik kan rensas var för sig, var och en med egen bekräftelse. Exportera först. -Regressionstesterna använder Node:s inbyggda testverktyg och kräver inget extra testramverk. Sviten täcker träningsprofiler, racegenerering och tidtagning, domarkorrigeringar, frontend/backend-synk samt ett isolerat SQLite API-test med en temporär datamapp: - -```bash -npm test -``` - -Integrationstestet startar en egen backend på en temporär localhost-port och läser eller skriver aldrig den vanliga databasen `data/rc_timing.sqlite`. - - -## Create Race Wizard -- `Race Setup` startar nu med en fyrstegs wizard för nya race: - - `Grunddata` - - `Deltagare` - - `Sessionsplan` - - `Bekräfta` -- Wizarden är till för att snabbt skapa första grundstrukturen: - - välj klass och preset - - välj vilka förare som faktiskt ska vara giltiga i racet - - skapa practice, kval och/eller team race automatiskt -- Finaler skapas fortfarande senare från `Race actions` när practice eller kval är färdiga. - -## Serie / cup - -Menyn **Serier / cup** samlar flera race i en serie: -- **Klasser:** välj fritt; varje klass får en egen tabell. -- **Deltävlingar:** valfritt antal. Skapa dem från en datumlista (ett race per datum och klass) med antal kvalomgångar, finaler och max bilar per heat, eller lägg till ett befintligt race. -- **Säsongen sköts från seriesidan (steg 3)**, en rad per deltävling: - - **Förare:** klicka på antalet och bocka i vilka som kör. Alla förare i klassen är förbockade från början. **Kopiera från förra** tar startfältet från förra deltävlingen i samma klass, och **Ny förare** lägger in en efteranmäld förare i klassen (och seriens klubb) och bockar i hen. - - **Format per deltävling:** kvalomgångar, finaler och max bilar per heat. Varje deltävling och klass kan skilja sig; formatet låses när kvalet har skapats. - - **Skapa kval:** antalet heat följer antalet förare och fördelas jämnt (9 förare, max 8 per heat → 5 + 4, aldrig 8 + 1). - - **Skapa finaler** när kvalet är klart. **Status** visar ej startad, kval skapat/pågår/klart, finaler, klar. **Öppna** går till racet i Race Setup. -- **Poängtabell:** ÖRC (100, 90, 82, 75, 69 ... sedan -4 per plats, lägst 10), 100-80-70 ..., F1, eller en egen lista med minskning och lägsta värde efter den. -- **Räknade resultat:** bästa N (t.ex. 9 av 12), eller alla körda utom X sämsta. Då minskar antalet automatiskt om en deltävling ställs in. Frånvaro räknas som 0 och kan strykas. -- **Vem får seriepoäng** väljs per serie: - - **Alla förare (öppen serie)**, standard. Förare från alla klubbar kör och får poäng. - - **Endast klubbmedlemmar.** Välj klubb; klubben hämtas från varje förare i förarregistret. Förare från andra klubbar kör och syns i dagens resultat men får inga seriepoäng, och medlemmarna rangordnas om utan dem (bästa medlem får vinnarpoängen). -- **Dagens resultat:** varje deltävling rankas efter slutresultatet (A före B), sedan förare utan final i kvalordning, eller enbart efter kvalet om inga finaler körts. Den som saknar registrerat varv får 0. -- **Lika poäng:** flest segrar bland räknade resultat, sedan andraplatser osv., sedan senaste gemensamma deltävling. -- **Ställning:** visas per klass med strukna resultat inom parentes. Den kan skrivas ut eller exporteras som PDF; breda tabeller blir liggande A4. - -## Hantera-flödet -- Efter att racet skapats är `Hantera` uppdelat i fyra tydliga steg: - - `Setup` - - `Format` - - `Generering` - - `Live / resultat` -- `Setup` används för racedeltagare och lag. Stegkorten högst upp fungerar också som snabbnavigering mellan de fyra blocken. -- `Format` används för practice/kval, finaler, validering, presets och avancerade val. I Grundläge döljer endurance de flesta kval-/finalfält tills du öppnar Avancerat. -- `Generering` ligger separat så knappar för kval, reseeding, finaler och bump-up inte blandas ihop med raceformatet. -- `Live / resultat` är där grid, standings, print, PDF och finalmatris används när upplägget väl är klart. - -## Export / Import -- `Inställningar -> Lagring` stöder nu: - - full JSON-export/import för hela tävlingsdatabasen - - register-JSON för bara klasser, förare och bilar - - CSV-export och sammanslagande CSV-import för förare och bilar; komma, semikolon och tabb stöds - - separat rensning av förare, bilar, klasser, race/sessioner eller träningsstatistik - - `Rensa all tävlingsdata` behåller decoder-, tema-, branding- och serverinställningar -- `Race Setup -> Hantera -> Race actions` stöder nu enskilda racepaket: - - exportera ett race med dess sessioner, resultat och refererade klasser/förare/bilar - - importera paketet på en annan installation som ett nytt race -- JSON-exporter innehåller nu även exportmetadata och ett schema-/versionsfält för säkrare import framåt. -- CSV-import från systemets egen export bevarar ID:n. Externa listor utan ID matchas först på transponder och därefter på namn + klass. Tomma fält skriver inte över befintlig information, och nya klassnamn skapas automatiskt. -- Förarimport kräver bara kolumnen `name` eller `namn`. Rekommenderat minimum är `name;transponder;class`. Valfria kolumner som `brand`, `spoken_name`, `club`, `country` och `profile_id` får saknas; okända kolumner ignoreras och rader utan namn hoppas över. +Exempel på förar-CSV (bara `name` krävs): ```csv name;transponder;class;brand;club;country @@ -396,252 +284,60 @@ Anna Andersson;123456;2WD;;JMK;SE Erik Eriksson;654321;4WD;Associated;; ``` -- En tom CSV-mall kan laddas ner direkt vid förarimporten under `Inställningar -> Lagring`. -- Ta en JSON-backup före rensning. Varje rensningsknapp kräver en separat bekräftelse och åtgärden kan inte ångras. -- Webbrensningen tömmer kanonisk appdata men behåller den separata råa `passings`-tabellen i SQLite som revisionslogg. En fysisk fabriksrensning av databasen ska göras lokalt på servern när processen är stoppad, inte via en oautentiserad LAN-route. +### Säkerhet -## Nya racefunktioner +RaceCore är tänkt för ett betrott racenätverk: +- **Admin-PIN** (Inställningar → System & backup, av som standard) skyddar alla ändringar via API:t. Inloggningen gäller i 30 dagar och är skyddad mot gissning. +- **`RC_ADMIN_ALLOWED_CIDRS`** begränsar adminändringar till vissa adresser eller nät, till exempel `192.168.1.0/24`. +- **`RC_ALLOWED_ORIGINS`** används för ett gränssnitt som medvetet körs från en annan adress. +- **Exponera inte port 8081 mot internet.** Läsningar skyddas inte av PIN. Publicera bara sökvägarna för publik overlay och mobilprofil via reverse proxy eller VPN. -### Follow-up time -- Ställs i `Race Setup -> Hantera -> Raceformat` -- Kan också sättas per session när du skapar eller redigerar en session -- När ordinarie tid går ut går sessionen först in i `Follow-up aktiv` -- När follow-up-tiden är slut stängs sessionen automatiskt -- Genererade kval/finaler ärver follow-up från raceformatet +Se [docs/security-performance-audit.md](docs/security-performance-audit.md). -### Min / Max varvtid -- Ställs i `Race Setup -> Hantera -> Raceformat` -- `Min varvtid`: - - varv snabbare än gränsen ignoreras som shortcut eller felträff -- `Max varvtid`: - - en långsammare passering startar en ny statistikstint - - övergångsvarvet räknas fortfarande i raceresultatet men utesluts ur pace- och femminuterssnitt +## Videoguider -Praktiskt exempel: -- bana runt `16 sek/varv` -- `Min varvtid = 11 sek` -- `Max varvtid = 120 sek` för att börja en ny stint efter två minuters avbrott +Korta inspelningar med berättarröst (`.mkv`, H.264/AAC), även länkade från Guiden i appen: -### Ogiltiga passeringar -- `Tidtagning -> Senaste passeringar` visar nu både giltiga och ogiltiga passeringar -- status som visas: - - `För kort varv` för en ogiltig shortcut/felträff - - `Långt varv · räknat · ny stint` när maxgränsen passeras -- ogiltiga passeringar markeras visuellt; räknade långa varv ligger kvar i raceresultatet +- **Kom igång:** [Anslut en decoder](docs/videos/connect-decoder.mkv) · [Lägg till förare och bilar](docs/videos/add-drivers-cars.mkv) · [Skapa ett race](docs/videos/create-race.mkv) · [Kör en session](docs/videos/run-a-session.mkv) +- **Rundtur i gränssnittet:** [Inställningsflikar](docs/videos/settings-tabs.mkv) · [Event Managers flikar](docs/videos/event-manager-tabs.mkv) · [Dagens schema](docs/videos/event-schedule.mkv) -### Manuella korrigeringar -- öppna `Tidtagning` -- klicka `Detaljer` på en förare / ett lag -- där finns: - - `+1 varv` - - `-1 varv` - - `+1 sek` - - `+5 sek` - - `-1 sek` - - `Nollställ korrigering` -- korrigeringarna uppdaterar leaderboard och resultat direkt - -### Best laps / average / consecutive -- Ställs per session med `Seedmetod` när `Seed bästa varv` är större än `0` -- tillgängliga lägen: - - `Bästa N varv, summa` - - `Bästa N varv, snitt` - - `Bästa N konsekutiva varv` -- leaderboard och ranking visar rätt format beroende på läge: - - summa: `3/00:48.321` - - snitt: `3 avg 16.107` - - konsekutiva: `3 con 00:49.005` - -### Poängtabeller och tie-break -- Ställs i `Race Setup -> Hantera -> Raceformat` -- poängtabeller för kval: - - `Placeringstal (1,2,3...)` - - `Fallande efter fältstorlek` - - `10-9-8-7-6-5-4-3-2-1` -- tie-break för kvalranking: - - `Jämför räknade rundor` - - `Bästa enskilda varv` - - `Bästa runda / heatresultat` -- kvalrankingen visar även en underrad med aktiv tie-break-information i tabellen - -### Raceformat presets -- `Race Setup -> Hantera -> Raceformat` -- välj ett preset och klicka `Applicera preset` -- tillgängliga presets: - - `Kort teknisk bana 16s` - - `Klubbrace kval + final` - - `IFMAR-stil kval/final` - - `Endurance / lagrace` -- efter applicering kan alla fält fortfarande justeras manuellt och sparas som vanligt -- `Spara klubb-preset` lagrar egna lokala presets i appens state så de kan återanvändas på samma installation -- `Ta bort klubb-preset` tar bort ett lokalt preset igen -- `Inställningar -> Klubb-presetar` kan exportera/importera presetbiblioteket som JSON mellan installationer - -### Schemaavvikelse på Översikt -- `Översikt` visar nu om dagen ligger före eller efter schema -- planerad tid räknar: - - sessionens varaktighet - - plus follow-up tid -- faktisk tid räknar: - - verklig tid från start till stopp - - eller pågående körtid om sessionen fortfarande kör - -### Invalid-lap markering i leaderboard -- om senaste mottagna passing för en förare/ett lag var ogiltig markeras raden även i leaderboard och overlay -- det gör det lättare att se felträffar utan att behöva stå i `Senaste passeringar` - -### Manuell invalidate last lap -- `Tidtagning -> Detaljer` -- knappen `Ogiltigförklara senaste varv` markerar senaste räknade varv som manuellt ogiltigt -- leaderboard, overlay och passings-historik uppdateras direkt -- `Återställ senaste manuellt ogiltiga varv` lägger tillbaka senaste manuellt ogiltiga varvet om du ångrar dig - -### Domarvy -- ny meny `Domare` -- visar aktiv session, leaderboard, lap history och domarlogg i samma vy -- samma korrigeringar som i `Tidtagning -> Detaljer` finns där som snabbknappar -- filter för: - - `Alla` - - `Ogiltiga` - - `Korrigerade` - - `Team race` -- domarloggen kan exporteras per session som JSON -- både `Ångra senaste` och undo-knapp per loggrad finns för flera manuella åtgärder - -## Framtida förbättringar -- Valfri neural text-till-tal för naturligare uppläsning av start, mål och förarnamn. -- Rekommenderad lösning: generera tal via backend, cacha korta ljudfiler under `data/tts/` och spela cachat ljud utan nätverksfördröjning under racet. -- Leverantörens API-nyckel ska endast finnas i backend och aldrig exponeras i webbläsaren eller publik overlay. -- Nuvarande systemröst och passing-blipp behålls som offline-fallback. -- Uppladdade eller förinspelade WAV/MP3-filer kan användas för fasta start- och målmeddelanden. +Spelas in med `node scripts/record-video-guides.mjs`, mot en isolerad testserver. ## Installation -RC RaceCore körs på 64-bitars Windows 11 och Linux. Använd Node.js 22 eller 24 LTS och npm 10 eller senare. Repot innehåller `package-lock.json`, så använd `npm ci` i stället för `npm install` för en reproducerbar installation. +RaceCore körs på 64-bitars Windows 11 och Linux med Node.js 22 eller 24 LTS och npm 10+. Använd `npm ci` (repot har en `package-lock.json`). -### Windows 11 - ny dator +### Windows 11 -#### 1. Installera Git +1. **Git:** kör `git --version`. Saknas det, kör `winget install --id Git.Git --exact --source winget` och öppna PowerShell igen, eller använd [Git for Windows](https://git-scm.com/download/win). Utan Git: ladda ner zip-filen från [repot](https://git.dio.nu/Public/Live_RC) och packa upp allt. +2. **Ladda ner:** + ```powershell + Set-Location $HOME + git clone https://git.dio.nu/Public/Live_RC.git Live_RC + Set-Location .\Live_RC + ``` +3. **Installera:** kör `.\windows\install.bat` (eller dubbelklicka). Den gör följande: + - installerar Node.js LTS vid behov, plus Visual C++-runtime som AMMC behöver; + - kör `npm.cmd ci`; + - verifierar Express, SQLite och AMMC; + - skapar `data\` och `logs\`; + - startar RaceCore i bakgrunden. +4. **Kontrollera:** + ```powershell + npm.cmd run status + Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" + ``` + Öppna sedan `http://localhost:8081`, eller `http://:8081` från en annan dator. -Öppna PowerShell och kontrollera om Git finns: +Använd `npm.cmd` i PowerShell; då slipper du felet "running scripts is disabled". Manuell installation utan skriptet: `npm.cmd ci`, `npm.cmd run verify`, `npm.cmd start`. Använd inte `--ignore-scripts`, eftersom SQLite behöver sitt installationsskript. -```powershell -git --version -``` - -Om Windows svarar att `git` inte känns igen installerar du Git med Windows Package Manager: - -```powershell -winget install --id Git.Git --exact --source winget -``` - -Stäng och öppna PowerShell efter installationen och kör sedan `git --version` igen. Om `winget` saknas kan Git för Windows installeras från [git-scm.com](https://git-scm.com/download/win). - -#### 2. Hämta RC RaceCore - -Klona det publika repot från ett vanligt PowerShell-fönster: - -```powershell -Set-Location $HOME -git clone https://git.dio.nu/Public/Live_RC.git Live_RC -Set-Location .\Live_RC -``` - -Skriv den rena URL:en exakt som ovan. Klistra inte in Markdown-format som `[https://...](https://...)` i PowerShell. - -Om du inte vill installera Git öppnar du [det publika repot](https://git.dio.nu/Public/Live_RC), laddar ner ZIP-arkivet och packar upp hela arkivet. Kontrollera att `package.json`, `server.js`, `src\` och `windows\` ligger i samma projektmapp. - -#### 3. Kör Windows-installationen - -Från projektmappen: - -```powershell -.\windows\install.bat -``` - -Du kan även dubbelklicka på `windows\install.bat` i Utforskaren. Installationen: - -- installerar Node.js LTS via `winget` om Node saknas eller har fel version -- installerar/kontrollerar Microsoft Visual C++ Runtime som AMMC använder -- kör `npm.cmd ci` med låsta dependency-versioner -- verifierar Express, SQLite och bundlade AMMC-filer -- skapar `data\` och `logs\` -- kör `npm.cmd restart` och lämnar RC RaceCore igång i bakgrunden - -Om installationen inte kan installera Node automatiskt installerar du Node.js 22 eller 24 LTS från [nodejs.org](https://nodejs.org/en/download), öppnar PowerShell igen och kör installationen på nytt. - -#### 4. Verifiera och öppna sidan - -```powershell -npm.cmd run status -Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health" -``` - -Öppna: - -```text -http://localhost:8081 -``` - -För att öppna RC RaceCore från en annan dator på race-nätverket kör du `ipconfig` på servern och använder: - -```text -http://:8081 -``` - -Använd `npm.cmd` i PowerShell. Det undviker det vanliga felet `npm.ps1 cannot be loaded because running scripts is disabled`. Vanliga `npm` fungerar normalt i Kommandotolken. - -#### Manuell Windows-installation - -Om du inte använder `install.bat`: - -```powershell -node --version -npm.cmd --version -npm.cmd ci -npm.cmd run verify -npm.cmd start -``` - -Använd inte `npm.cmd ci --ignore-scripts`. Den inbyggda SQLite-modulen behöver sitt installationsskript. - -### Linux - Ubuntu/Debian - -#### 1. Installera Git och grundverktyg - -```bash -sudo apt update -sudo apt install -y git curl build-essential -git --version -``` - -#### 2. Installera Node.js 22 LTS vid behov - -Kontrollera installerad version: - -```bash -node --version -npm --version -``` - -Om Node saknas eller är äldre än version 22 installerar du Node.js 22 via NodeSource: +### Linux (Ubuntu/Debian) ```bash +sudo apt update && sudo apt install -y git curl build-essential +# Node.js 22 om "node --version" saknas eller är äldre: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs -node --version -npm --version -``` - -Node.js 22 eller 24 LTS rekommenderas. Node.js 18 och 20 stöds inte av nuvarande native SQLite-dependency. - -De bundlade Linux-verktygen för x86-64 i `AMMC/linux_x86-64` kräver **GLIBC 2.39 eller senare**. Det gäller både decoder-konverterarna och `ammc-sim`. Kontrollera servern före racedagen med `ldd --version` och `npm run verify`. Äldre distributioner kan fortfarande köra RC RaceCore, men måste använda AMMC-binärer byggda för deras GLIBC-version eller köra AMMC på en annan kompatibel dator. - -#### 3. Klona, installera och starta - -```bash -mkdir -p ~/git -cd ~/git git clone https://git.dio.nu/Public/Live_RC.git Live_RC cd Live_RC npm ci @@ -649,104 +345,33 @@ npm run verify chmod +x AMMC/linux_x86-64/ammc-* npm start npm run status -curl http://127.0.0.1:8081/api/health ``` -`npm start` kör RC RaceCore i bakgrunden. Öppna `http://localhost:8081`, eller hitta Linux-serverns adress med `hostname -I` och öppna `http://:8081` från en annan dator. - -Om den bundlade AMMC-binären rapporterar `version 'GLIBC_2.39' not found` är hostens Linux för gammalt för just den binären. Använd en kompatibel AMMC-build eller en distribution med GLIBC 2.39+. Byt inte operativsystemets GLIBC manuellt eftersom hela systemet kan sluta fungera. - -`AMMC/linux_x86-64/ammc-sim` och `AMMC/windows64/ammc-sim.exe` kan simulera en AMB-decoder med valda transpondrar. Det passar för träning, overlaytest och belastningstest utan fysisk decoder. Ett komplett exempel finns i `docs/decoder-setup.sv.md`. +Öppna `http://localhost:8081` eller `http://:8081`. Den medföljande Linux-AMMC kräver **GLIBC 2.39+** (`ldd --version`). På äldre system: använd en AMMC-version byggd för ditt system eller kör AMMC på en annan dator. Byt aldrig systemets GLIBC. ### Driftkommandon -Windows PowerShell: +| Kommando (Windows: `npm.cmd ...`) | Gör | +|---|---| +| `npm start` | Startar i bakgrunden | +| `npm run status` | Körs den? (PID i `data/server.pid`) | +| `npm restart` | Startar om efter en uppdatering | +| `npm stop` | Stoppar | +| `npm run start:fg` | Kör i terminalen och visar fel direkt | +| `npm run tts:install` | Installerar Piper och standardrösterna | -```powershell -npm.cmd start -npm.cmd run status -npm.cmd restart -npm.cmd stop -npm.cmd run start:fg -``` +Loggar hamnar i `logs/server.out.log` och `logs/server.err.log`; data ligger i `data/`. -Linux: +Hjälpskript i `windows\`: +- `install.bat`: installerar, verifierar och startar om. +- `start_backend.bat` och `restart_backend.bat`: startar eller startar om servern. +- `start_ammc.bat`: startar AMMC. +- `start_all.bat`: startar AMMC och servern och öppnar webbläsaren. +- `stop_all.bat`: stoppar servern och AMMC. -```bash -npm start -npm run status -npm restart -npm stop -npm run start:fg -``` +### Uppdatera utan att tappa data -- `start` kör backend i bakgrunden -- `status` visar om PID-filen i `data/server.pid` motsvarar en aktiv process -- `restart` laddar om ändringar i backend -- `stop` stoppar den hanterade processen -- `start:fg` kör i terminalen och visar startfel direkt -- stdout skrivs till `logs/server.out.log` -- stderr skrivs till `logs/server.err.log` -- SQLite-data lagras i `data/rc_timing.sqlite` - -### Windows hjälpskript - -- `windows\install.bat`: installerar dependencies, verifierar och startar om -- `windows\start_backend.bat`: startar backend i bakgrunden -- `windows\restart_backend.bat`: startar om efter kopierad eller hämtad uppdatering -- `windows\start_ammc.bat`: startar bundlad AMMC manuellt -- `windows\start_all.bat`: startar AMMC och backend samt öppnar webbläsaren -- `windows\stop_all.bat`: stoppar backend och `ammc-amb.exe` - -### Återställ en serverbackup - -Backuper lagras i `data/backups/`. Återställning är avsiktligt ett lokalt serverkommando och exponeras inte via det oautentiserade webb-API:t. - -1. Stoppa RC RaceCore. -2. Kopiera backupfilens namn från `Inställningar -> Lagring` eller lista filerna i `data/backups/`. -3. Kör restore-kommandot med den uttryckliga bekräftelseflaggan. -4. Starta RC RaceCore igen. - -Windows PowerShell: - -```powershell -npm.cmd stop -$backup = Get-ChildItem .\data\backups\*.sqlite | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -$backup.Name -npm.cmd run backup:restore -- $backup.Name --confirm -npm.cmd start -``` - -Linux: - -```bash -npm stop -backup=$(find data/backups -maxdepth 1 -name '*.sqlite' -printf '%T@ %f -' | sort -nr | head -n 1 | cut -d' ' -f2-) -printf 'Återställer %s -' "$backup" -npm run backup:restore -- "$backup" --confirm -npm start -``` - -Restore-kommandot validerar vald SQLite-fil och skapar en `pre_restore`-backup av nuvarande databas innan den ersätts. - -### Uppdatera utan att förlora data - -SQLite-databasen och lokal konfiguration ligger i `data/`. Radera eller ersätt aldrig den katalogen vid en uppdatering. - -Windows: - -```powershell -npm.cmd stop -git pull --ff-only -npm.cmd ci -npm.cmd run verify -npm.cmd restart -npm.cmd run status -``` - -Linux: +Radera aldrig `data/`. Så här uppdaterar du: ```bash npm stop @@ -754,149 +379,55 @@ git pull --ff-only npm ci npm run verify npm restart -npm run status ``` -Om installationen kommer från ett ZIP-arkiv i stället för Git säkerhetskopierar du `data/`, packar upp de nya programfilerna, återställer/behåller befintlig `data/`, kör `npm ci` och startar om. Kopiera aldrig `node_modules/` mellan Windows och Linux. +På Windows används samma kommandon med `npm.cmd`. Menyn visar när en uppdatering finns, och uppdateringen kan också köras från Inställningar → System & backup. Vid zip-installation: behåll `data/`, och kopiera aldrig `node_modules/` mellan Windows och Linux. -## Koppla mot AMMC -Det finns nu två sätt: +### Återställ en serverbackup -Komplett nätverksdiagram, färdiga exempel för 1/2/3/4 decoders, brandvägg och felsökning finns i [`docs/decoder-setup.sv.md`](docs/decoder-setup.sv.md). Engelsk version: [`docs/decoder-setup.md`](docs/decoder-setup.md). +Backuper ligger i `data/backups/`. Återställning görs med ett lokalt kommando, med avsikt: -### A. Hanterad AMMC i webbgränssnittet -Viktigt: -- AMMC körs på samma Windows-host där backend startades med `npm.cmd start`. -- Om du öppnar sidan från en annan laptop startas ingen AMMC där. -- Fältet `AMMC binär` i `Settings` är en sökväg på backend-hosten, inte på klienten som surfar in. - -#### Koppling av decoders - -| Roll | Fysisk placering | Exempel decoder-IP | AMMC WS-port | Funktion | -|---|---|---:|---:|---| -| Main start/mål | Start-/målloop | `192.168.1.10` | `9000` | Räknar varv och bestämmer varvtid | -| Mellantid | Mellantidsloop | `192.168.1.11` | `9001` | Tid från senaste main-passering; räknar aldrig varv | -| Depå in | Infart till depå | `192.168.1.12` | `9002` | Öppnar ett depåstopp | -| Depå ut | Utfart från depå | `192.168.1.13` | `9003` | Stänger och tidtar depåstoppet | - -Decoder-IP och WebSocket-adress är två olika saker. Decoder-IP är den fysiska hårdvarans adress som AMMC ansluter till. Webbläsaren ansluter till AMMC på backend-hosten, till exempel `ws://192.168.1.100:9001`. Varje decoder måste ha unik nätverksadress och varje AMMC-process måste ha unik WebSocket-port. - -Aktivera bara de kanaler som finns fysiskt på banan. En decoder på `9000` är fortsatt standard och kräver inga extrainställningar. Mellantid kräver en extra decoder. Depåtid kräver två extra decoders eftersom in- och utpassering är separata händelser. Komplett installation använder därför fyra decoders. - -Mellantids- och depådata visas på flera ställen: -- `Tidtagning` visar aktivt heats sammanställning och fullständig depåstoppslogg live. -- `Race Setup -> Hantera -> Live / resultat` visar sammanställning och depålogg för varje heat, inklusive långa 45-minuters endurance-heat. -- vanliga resultat- och lagrapporter inkluderar split-/depåsammanställning och fullständig in-/utlogg i PDF. -- `Träning -> Mer statistik` summerar mellantider och depåstopp för vald personlig förarprofil och klass; olika klasser blandas aldrig. -- den personliga mobilprofilen visar endast sanerade antal och aggregerade tider för vald klass. Den exponerar aldrig transpondrar, andra förare eller den råa depåstoppsloggen. - -Om ett lag byter förare eller bil mellan depå in och depå ut kopplas det färdiga stoppet till föraren, bilen och transpondern som registrerades vid depåinfarten. Transpondern vid utfarten sparas separat för felsökning. - -1. Lägg AMMC-binärerna i projektmappen `AMMC/` (redan gjort i denna repo). -2. Öppna `Settings`. -3. Aktivera `Hanterad AMMC / Managed AMMC`. -4. Sätt Main `Decoder IP / host`, kontrollera port `9000` och aktivera vid behov Mellantid och Depå enligt tabellen ovan. -5. Klicka `Starta AMMC / Start AMMC`. -6. Klicka `Använd serverns WS-url / Use server WS URL` så sätts klienten till t.ex. `ws://:9000`. - -Standardbinärer: -- Linux-host: `AMMC/linux_x86-64/ammc-amb` -- Windows-host: `AMMC/windows64/ammc-amb.exe` -- macOS-host: `AMMC/apple_m/ammc-amb` - -### B. Manuell start -Starta AMMC med WebSocket (exempel): -```powershell -ammc-amb.exe -w 9000 192.168.1.10 -``` - -Komplett exempel med fyra decoders, i fyra separata terminaler/processer: -```powershell -ammc-amb.exe -w 9000 192.168.1.10 -ammc-amb.exe -w 9001 192.168.1.11 -ammc-amb.exe -w 9002 192.168.1.12 -ammc-amb.exe -w 9003 192.168.1.13 -``` - -I appen: -1. `Settings` -2. Sätt `WebSocket URL` till t.ex. `ws://127.0.0.1:9000` -3. Sätt `Backend URL` till `http://127.0.0.1:8081` -4. Klicka `Test Backend` -5. Gå till `Timing` och klicka `Connect Decoder` - -Om du kör Linux-brandvägg (UFW), öppna porten: ```bash -sudo ufw allow 8081/tcp -sudo ufw allow 9000:9003/tcp +npm stop +npm run backup:restore -- .sqlite --confirm +npm start ``` -## Auto reload vid uppdatering -- Servern bevakar `index.html`, `src/app.js` och `src/styles.css`. -- När du uppdaterar filer i `Live_RC` och sparar, laddar klienten om sidan automatiskt. -- Om backendkoden ändras i Windows, kör `npm.cmd restart`. +På Windows hittar du senaste filen med `Get-ChildItem .\data\backups\*.sqlite | Sort-Object LastWriteTime -Descending | Select-Object -First 1`. Återställningen kontrollerar filen och tar först en `pre_restore`-backup av den nuvarande databasen. -## Verifiera att SQLite sparar -Hämta senaste passeringar via API: -- `http://localhost:8081/api/passings` +## Decoders och AMMC -Hämta sparad app-state: -- `http://localhost:8081/api/state` +Den fullständiga guiden, med nätverksskiss, exempel med 1-4 decoders, brandvägg och felsökning, finns i [docs/decoder-setup.sv.md](docs/decoder-setup.sv.md) (engelska: [docs/decoder-setup.md](docs/decoder-setup.md)). -## Viktig regel för sponsor-event -- I **samma pågående session** måste varje aktiv bil ha unikt transponder-ID. -- Samma transponder-ID kan återanvändas i **nästa session** (Heat 1 -> Heat 2 -> Heat 3 -> Final 1 ...). +| Roll | Placering | Exempel decoder-IP | AMMC WS-port | Effekt | +|---|---|---:|---:|---| +| Main | Start/mål-slinga | `192.168.1.10` | `9000` | Räknar varv | +| Split | Mellanslinga | `192.168.1.11` | `9001` | Mellantid, aldrig ett varv | +| Depå in | Depåinfart | `192.168.1.12` | `9002` | Öppnar ett depåstopp | +| Depå ut | Depåutfart | `192.168.1.13` | `9003` | Stänger och tar tid | -## Referens AMMC JSON -Officiell quick-start: -- https://www.ammconverter.eu/docs/intro/quick-start/ +**Hanterad AMMC** (Inställningar): +1. Slå på Hanterad AMMC. +2. Ange decoderns IP för varje kanal. +3. Klicka **Starta AMMC**, sedan **Använd serverns WS-url**. + +AMMC körs på serverdatorn, inte i webbläsaren. De medföljande programmen ligger i `AMMC/windows64`, `AMMC/linux_x86-64` och `AMMC/apple_m`. + +**Manuell start:** kör en `ammc-amb -w ` per decoder. Sätt WebSocket-URL i Inställningar (t.ex. `ws://:9000`) och tryck **Anslut decoder**. Webbläsaren ansluter till AMMC-datorn, inte till decodern. På Linux med UFW: `sudo ufw allow 8081/tcp` och `sudo ufw allow 9000:9003/tcp`. + +**Diagnostik:** Inställningar → Decoder / socket-diagnostik visar varje kanals anslutning, meddelanden och passeringar, senaste råmeddelandet och 50 händelser. **`ammc-sim`** emulerar en decoder med valda transpondrar, för träning och test utan hårdvara. + +AMMC skickar PASSING-meddelanden så här ([AMMC-dokumentation](https://www.ammconverter.eu/docs/intro/quick-start/)): -Exempelmeddelande: ```json -{ - "msg": "PASSING", - "passing_number": 1, - "transponder": 232323, - "rtc_time": "2022-10-11T22:57:36.099+02:00", - "strength": 0.0, - "resend": false, - "tran_code": "ID:232323", - "loop_id": "55" -} +{ "msg": "PASSING", "passing_number": 1, "transponder": 232323, "rtc_time": "2022-10-11T22:57:36.099+02:00", "strength": 0.0, "resend": false, "loop_id": "55" } ``` -## Raceljud och startljus +## Utveckling och tester -Repot innehåller `rc-race-sound-pack/`. `sound_manifest.json` är källan för kopplingen mellan event, WAV-filer och svenska/engelska utrop. Servern publicerar manifestet på `/race-sounds/sound_manifest.json` och WAV-filerna under `/race-sounds/sounds/effects/`. - -1. Öppna `Inställningar -> Raceljud och utrop`. -2. Välj `sv` eller `en`, välj en installerad Race-röst och ställ dess hastighet, tonhöjd samt master-, effekt-, röst- och passing-volym. Offline-standard för race-controller-stil är hastighet `1.08` och tonhöjd `0.90`; för verkligt mänsklig speakerkvalitet krävs fortfarande förinspelade eller neurala klipp. -3. Slå på/av effekt och röst separat för varje event och använd radens Testa-knapp. Ändringar sparas automatiskt och sektionen har även en egen Spara-knapp. WAV-effekter är förinspelade; röstutrop använder operativsystemets Web Speech-röster. -4. Välj 0/10/30/60 sekunders förstart, startljus och gränser för slumpad startfördröjning. För tidsstyrda race startar klockan i samma callback som starttonen initieras. Open/Free Practice startar direkt. -5. Använd Race Control-knapparna i `Tidtagning` för Stopp på banan, Banan fri, Röd flagg, Felaktig start och Banvaktsvarning. - -Effekter körs asynkront och väntas aldrig in av decoderflödet. Kritiska utrop avbryter lägre prioriterat tal; korta passing-ljud får överlappa. Saknade WAV-filer ignoreras säkert. En förare eller bil kan välja `pass_01.wav` till `pass_08.wav`; tills dessa valfria filer finns i `rc-race-sound-pack/sounds/effects/` används `transponder_pass.wav` som fallback. - -Automatiska hooks omfattar passering, person-/meetingbästa, snabbaste varv, historiskt klass-banrekord, ledar- och positionsbyte, depå in/ut, 60/30/10 sekunder kvar, sista varv/tiden slut, finish, vinnare och podium. Penalty-utrop återanvänder domarvyns befintliga korrigeringsåtgärd. - -## Driftsäkerhet och sparstatus - -Menyn visar serveranslutning, väntande ändringar, pågående sparning, bekräftad sparning och sparfel. Där visas även senaste lyckade hämtning/sparning. En synlig varning visar tappad eller inaktuell serveranslutning; en lyckad anslutningskontroll tar inte bort ett sparfel. Klicka **Försök igen** för att skicka lokala ändringar igen. Serveranslutning och decoderanslutning har separata indikatorer. Behåll fliken öppen medan ändringar är osparade. - -Nya webbläsarprofiler använder sidans adress inklusive port som standard för backend. En uttryckligen konfigurerad backend-adress går före standardvärdet. - -Kör `npm test` för logik- och API-tester. Kör `npm run test:browser` (Windows PowerShell: `npm.cmd run test:browser`) för riktiga skapa/redigera/ladda-om-tester av klasser, förare och bilar, bibehållna formulärutkast under bakgrundsuppdatering samt offline-sparning och nytt sparförsök. Chrome, Chromium eller Edge måste finnas installerat; sätt `CHROME_PATH` om programmet inte hittas automatiskt. Testet skapar en tillfällig serverdatabas och webbläsarprofil och tar bort dem efteråt. Dina ordinarie racedata används inte och ingen decoder startas. ROADMAP.md visar vilka flöden som ännu saknar täckning. - -Webbläsartesterna täcker även sponsor-event, endurance-raceguiden, skapa/redigera/radera lag och ändra medlemmar, byte från Open Practice till lagrace samt sparade varvgränser. Overlayns sorteringsrubriker ligger ovanför sina kolumner; på smala skärmar skrollas rubriker och förarrader tillsammans i sidled. - -### Decoder- och Socketdiagnostik - -Öppna **Inställningar > Decoder / socket-diagnostik** för Main, mellantid och depå in/ut. Varje kanal visar sparad WebSocket-url, faktisk socket-adress, anslutnings-/mottagningstid och räknare. Ansluten socket betyder inte att passeringar kommer in. - -Använd AMMC-datorns IP i WebSocket-url (exempel `ws://192.168.1.75:9000`), inte den fysiska decoderns IP. Varje AMMC-kanal behöver egen port; aktivera bara installerade kanaler. `127.0.0.1` avser datorn med webbläsaren. - -Frames räknar mottagna socketmeddelanden; PASSING är passeringsmeddelanden, inte godkända varv. Hanterade inkluderar mellantider, depåhändelser och startreferenser. Ignorerade, ogiltiga varv och JSON-fel visas separat. Välj kanal för senaste råmeddelandet och 50 händelser. Pausa stoppar bara visningen. Rensa nollställer kanalens diagnostikräknare/logg men behåller anslutningstider. Kopiera erbjuder manuell kopiering på HTTP. Diagnostiken gäller bara denna webbläsare, sparas endast i minnet och försvinner vid omladdning. Varje exempel begränsas till 512 tecken. Tidtagningen påverkas inte och inget nytt publikt API tillkommer. Loggen kan innehålla transpondernummer; granska innan delning. - -### Anslutningsstatus i Mobilprofilen - -Den personliga träningslänken visar när data senast hämtades. Efter 30 sekunder utan tillämpad uppdatering visas en varning om att statistiken kan vara inaktuell, även om uppdateringen väntar på att du skriver klart. Vid hämtningsfel ligger statistiken kvar och **Försök igen** visas. Avsluta aktiv inmatning före återförsök. Hämtningar avbryts efter 15 sekunder; automatisk hämtning fortsätter var tionde sekund när sidan är synlig, utan överlappande anrop. Statusen gäller profilhämtningen, inte decoderanslutningen eller att en biländringsmarkering har sparats. +- **Enhets-, logik- och API-tester:** `npm test`. SQLite-integrationstesterna startar en egen server mot en tillfällig databas och rör aldrig `data/`. +- **Webbläsartester:** `npm run test:browser`. De kräver Chrome, Chromium eller Edge (sätt `CHROME_PATH` om den inte hittas) och körs mot en isolerad server med fejkad decoder. +- **Skärmbilder och videoguider:** `node scripts/capture-screenshots.mjs [namn]` och `node scripts/record-video-guides.mjs`. +- **Dokumentation:** modulöversikten finns i [docs/javascript-architecture.md](docs/javascript-architecture.md), och planerat och klart arbete i [ROADMAP.md](ROADMAP.md). +- **Automatisk omladdning:** klienten laddas om när `index.html` eller frontendfiler ändras. Kör `npm restart` efter ändringar i backend. +- **Rådata:** `/api/passings` (senaste passeringar) och `/api/state` (appens data), bara i det lokala nätverket. diff --git a/ROADMAP.md b/ROADMAP.md index adc28ea..664abaa 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -931,6 +931,12 @@ Verified 2026-10-11: - [x] Consolidate older future-work notes so this file remains the primary roadmap. - [x] Update the in-app Guide page for this session's shipped features. Added three new "Träningsstatistik" steps (guided-exercise config, mobile self-service, the end-of-practice summary) and a new "Resultatarkiv" section (overview card + 5-step walkthrough); corrected `guide.sqlite_2`/`_6`, which claimed raw SQLite passings are always retained - no longer true now that deletion/clear-data purges them. Verified 2026-09-09 with a headless-browser check confirming the new content renders as real translated text (sv), not raw `guide.*` keys. +Restructured 2026-10-13, asked by the user, who felt features were missing and the structure was poor: +- [x] Both READMEs rewritten around how a club uses RaceCore: contents, highlights, quick start, then race day → creating races → series → practice → audio → overlays → sponsor events → data → security, then video guides, installation, decoders and development. +- [x] Facts were checked against the code (menu and tab names in both languages, `Race actions` living in the Format tab, the Schedule & print tab, file and doc links). +- [x] Outdated claims were removed (penalties on Timing, legacy passing sounds, Piper as future work). +- [x] A script checked that all 18 table-of-contents anchors resolve in each language. + Consolidated 2026-09-09: the raw "Träningsstat" brainstorm notes (Pyramiden, Konsistens-jakten) were folded into section 3's "Guided practice exercises" as a proper specification and removed from here. Closed out 2026-09-12, requested by the user alongside the screenshot refresh above: `docs/javascript-architecture.md` (~2850 lines) hadn't kept pace with this whole session's work. Used a research-only Explore pass first to get a concrete diff (doc location vs. actual code) rather than guessing what was stale, then applied it: diff --git a/package-lock.json b/package-lock.json index ea7fd09..281b2c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rc-racecore", - "version": "1.39.0", + "version": "1.39.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rc-racecore", - "version": "1.39.0", + "version": "1.39.1", "hasInstallScript": true, "dependencies": { "better-sqlite3": "^12.11.1", diff --git a/package.json b/package.json index 86857ab..c36cfce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-racecore", - "version": "1.39.0", + "version": "1.39.1", "private": true, "description": "RC RaceCore live timing and race control with AMMC ingest and SQLite persistence", "engines": {