"Add Windows installer and driver training rewards"
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user