"Add Windows installer and driver training rewards"

This commit is contained in:
larssand
2026-08-24 14:48:49 +02:00
parent 4c0e94bc50
commit de7b4adfe0
21 changed files with 2068 additions and 210 deletions

View File

@@ -90,12 +90,21 @@ Dependencies:
- `express`
- `better-sqlite3`
Runtime contract:
- Node.js `>=22 <27`
- npm `>=10`
- dependency graph locked by `package-lock.json`
- `scripts/preinstall.js` rejects unsupported Node/Windows architecture before native install
- `scripts/verify-install.js` loads Express and executes an in-memory SQLite query after install
Scripts:
- `npm start` -> `node scripts/serverctl.js start`
- `npm run start:fg` -> `node server.js`
- `npm stop`
- `npm run status`
- `npm restart`
- `npm run verify`
- `npm run setup:windows`
### `server.js`
Role:
@@ -149,6 +158,40 @@ Uses:
- `logs/server.out.log`
- `logs/server.err.log`
### Windows bootstrap
Files:
- `windows/install.bat`
- `windows/setup.ps1`
- `windows/start_backend.bat`
- `windows/start_ammc.bat`
- `windows/start_all.bat`
- `windows/stop_all.bat`
Dependency flow:
```mermaid
flowchart LR
InstallBat[windows/install.bat] --> SetupPs[windows/setup.ps1]
SetupPs -->|missing/unsupported| Winget[winget OpenJS.NodeJS.LTS]
SetupPs --> VCRuntime[winget Microsoft.VCRedist.2015+.x64]
SetupPs --> NpmCi[npm ci]
NpmCi --> Preinstall[scripts/preinstall.js]
NpmCi --> Native[better-sqlite3 prebuilt N-API binary]
NpmCi --> Postinstall[scripts/verify-install.js]
Postinstall --> SQLite[SQLite in-memory query]
Postinstall --> AMMC[AMMC/windows64 runtime check]
SetupPs --> ServerCtl[scripts/serverctl.js]
```
Important constraints:
- the repository should be installed in a short ASCII path such as `C:\\Live_RC`
- AMMC Windows binaries and DLLs must remain together in `AMMC\\windows64`
- `npm start` is already a background start; batch wrappers must not create a second detached npm process
- server process identity is stored in `data\\server.pid`
- Windows stdout/stderr use `logs\\server.out.log` and `logs\\server.err.log`
- the optional `-OpenFirewall` setup flag opens inbound TCP `8081` and `9000` only when PowerShell is elevated
## 2.2 Frontend files
### `src/app.js`
@@ -347,6 +390,42 @@ Owns:
- branding/audio settings UI
- import/export settings UI
### `src/training_logic.js`
Type:
- pure training/statistics logic
Owns:
- training-state normalization
- valid driver-lap aggregation across `resultsBySession`
- lifetime/session/best-lap/consistency calculations
- rule-based practice recommendation selection
- milestone progress calculation
Rules:
- only passings with a matching `driverId` are included
- invalid laps and lap times at or below `500 ms` are excluded
- anonymous Open Practice transponders are excluded until registered as drivers
- consistency is the P10-to-P90 spread of the latest 30 valid laps divided by their mean
### `src/training_views.js`
Type:
- training page renderer/controller
Owns:
- driver selector
- training stat cards and recommendation display
- milestone/reward create, claim, and delete actions
- mobile-responsive training markup
Mutations:
- replaces or appends entries in `state.training.goals`
- always calls injected `saveState()` before rerender
Route behavior:
- `/?view=training` opens the training view directly
- `driver=<driverId>` selects a driver and supports mobile bookmarks
- this is currently the same trusted-LAN admin shell, not a separate public read-only profile route
## 3. Direct Import Dependencies
## 3.1 Static import graph
@@ -368,6 +447,8 @@ Owns:
- `src/timing_views.js`
- `src/race_render_helpers.js`
- `src/judging_logic.js`
- `src/training_logic.js`
- `src/training_views.js`
### `src/event_workspace_controller.js` imports
- `src/event_views.js`
@@ -543,6 +624,7 @@ Primary state buckets:
- `state.cars`
- `state.classes`
- `state.resultsBySession`
- `state.training`
- `state.settings`
- `state.passings`
@@ -739,6 +821,8 @@ sequenceDiagram
| `src/core_views.js` | view/render | none | `app.js` | yes | no | no |
| `src/misc_views.js` | view/render | none | `app.js` | yes | no | no |
| `src/settings.js` | view/render | none | `app.js` | yes | no | no |
| `src/training_logic.js` | logic | none | `app.js` | no | no | no, returns normalized/derived data |
| `src/training_views.js` | view/controller | none | `app.js` | yes | no | yes, through injected state access |
| `server.js` | backend runtime | node core + deps | npm/node | n/a | backend process state | yes |
| `scripts/serverctl.js` | process control | node core | npm scripts | n/a | no | pid/log files only |
@@ -1094,7 +1178,7 @@ If one of these breaks, inspect this controller first.
- `initSchema()`
- initializes SQLite schema
- `watchAppFiles()`
- bumps app version on file changes
- bumps app version when `index.html` or any top-level `src/*.js` / `src/*.css` file changes
- `loadAmmcConfig()` / `saveAmmcConfig()`
- AMMC config file persistence
- `normalizeAmmcConfig(...)`
@@ -1128,6 +1212,7 @@ This section describes the practical shape of the frontend state as persisted by
events: Event[],
sessions: Session[],
resultsBySession: Record<string, SessionResult>,
training: TrainingState,
activeSessionId: string,
settings: Settings
}
@@ -1343,7 +1428,44 @@ Practical shape:
This bucket is the most dynamic part of state and is mutated heavily during live timing and judging.
## 15.8 `Settings`
## 15.8 `TrainingState`
```js
{
goals: TrainingGoal[]
}
```
`TrainingGoal`:
```js
{
id: string,
driverId: string,
title: string,
reward: string,
targetLaps: number,
createdAt: string, // ISO timestamp
claimedAt: string // empty until reward is delivered
}
```
Normalized by:
- `normalizeTrainingState()` wrapper in `src/app.js`
- `normalizeTrainingState()` implementation in `src/training_logic.js`
Persisted through:
- `buildPersistableState()` in `src/app.js`
- `applyPersistedStateHelper()` in `src/runtime_services.js`
- existing full-state `POST /api/state` backend path
Derived statistics are intentionally not stored. They are recalculated from `resultsBySession` so corrections and invalidated laps are reflected immediately.
Known lifecycle constraint:
- deleting historical sessions removes their source passings and therefore lowers calculated lifetime totals
- a future immutable training ledger should be introduced before session archival/deletion is used routinely
## 15.9 `Settings`
Practical shape contains at least:
- theme