Announcements can use Piper, a free local neural TTS, instead of the browser's system
voice. No account, no paid service, and it keeps working with no internet at the track.
- npm run tts:install (or Settings -> Audio -> Install) downloads the standalone Piper
release for Linux/Windows/macOS plus Swedish and English voices into piper/ once
- server/tts.js generates each line once, one at a time, and caches it as WAV under
data/tts/; a new line takes ~0.3 s with the standalone build
- src/piper_speech.js plays it and falls back to the browser voice if Piper is missing,
errors, or takes over 2.5 s, so no announcement is lost and timing is never held up
- "Pre-generate phrases and driver names" renders every fixed phrase and name in both
languages before race day
Browser voice stays the default. Generation routes fall under the admin PIN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Off by default. Once a PIN is set in Settings -> System & backup, every non-GET /api/*
request (plus GET /api/ammc/config) needs a signed 30-day HttpOnly cookie, which also
closes the unauthenticated /api/update/run restart trigger. A 401 opens a PIN dialog
and the pending save is retried after login. Reads stay open because the public overlay
hydrates through GET /api/state. Optional RC_ADMIN_ALLOWED_CIDRS restricts the same
routes by client address.
The PIN hash and signing secret live in data/, outside the app_state blob, so they
never leak through GET /api/state, exports or backups.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes both open "Documentation maintenance" roadmap items. Used a research-only
Explore pass to get a concrete diff against the actual code before editing, rather
than guessing what was stale.
Documented: src/track_layouts_logic.js (previously unmentioned anywhere),
buildEventSchedule, the Settings/Event Manager tab layouts, new state fields
(raceConfig.scheduleStartAt/scheduleGapMin, Session.trackLayoutId, top-level
trackLayouts/audioEventLog), a real SQLite table contract section, a full
field-by-field Settings shape, several previously-undocumented backend routes,
and the complete list of files tests/browser_smoke.js actually invokes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>