Overview cold start:
- InstanceResourceService persists every live fetch into status_snapshots
(category 'resources') and serves a snapshot younger than 2 minutes
before calling upstream, so the first fleet overview after a restart
costs zero device requests; instance deletion cleans up via FK cascade
Bounded retention for the four fastest-growing tables (15-minute sweep):
- connection_logs: one row per probe per beat had no automatic cleanup
- audit_events: new pruneBefore (90d)
- operation_preparations: every prepare/retry attempt inserted a row,
terminal rows now expire after 7 days
- notification_queue: terminal rows pruned after 30 days
SSE events now cover instance lifecycle:
- create/update emit instance envelopes from the routes; the two-phase
delete emits a job envelope on every terminal transition plus an
instance envelope when the node actually disappears, so fleet and
instance views invalidate in real time
Linux ops:
- 'install.sh unit' writes systemd user units for API and gateway with
Restart=on-failure, 0600 secret injection, and
MULTI_SIMADMIN_SYSTEMD_UNIT wired so console self-update restarts via
systemctl -- closing the self-update loop on Linux
Fleet overview N+1:
- InstanceResourceService gains a 30s TTL cache with single-flight
coalescing; the overview no longer fires six live upstream requests per
device on every render (plus the re-login storm), while the per-device
detail route probes live via force:true
Event journal becomes live:
- job terminal transitions (manual executions and the interrupted sweep)
now append to the journal, so /api/v1/events SSE feeds the frontend's
invalidation controller that was built but never received events
- journal pruning moves off the append hot path (was an unindexable
full-table json_extract scan per insert) onto the retention timer
Console auth hardening:
- scrypt upgraded from N=16384 to N=2^16 (OWASP interactive guidance);
a new password_kdf column records the derivation per row and legacy
hashes rehash transparently on the next successful login without
invalidating sessions (migration 18)
Legacy stack:
- instance URL validation blocks IPv4-compatible IPv6 after WHATWG
canonicalization (::a9fe:a9fe metadata, ::7f00:1 loopback slipped past)
- status polls cool down auto-login for 60s after a failed attempt so a
stale saved password cannot hammer the device into an account lockout
Build hygiene:
- web bundle splits app (410kB) from vendor (212kB) so framework code
stays cacheable across releases; stale root package-lock.json removed
(pnpm is the only lockfile)
- platform gate accepts Darwin and Linux; other platforms are refused
- default install root follows each platform's convention
(~/Library/Application Support vs ~/.local/share)
- LAN IP discovery uses ip -4/hostname -I on Linux, ipconfig on macOS
- port occupancy checks fall back from lsof to ss
- API process gets MULTI_SIMADMIN_SECRET_BACKEND pinned per platform
- README documents the per-platform secret storage
The runtime executables bind fixed ports, so the production command check now
skips instead of failing against a live deployment, and the canary check takes
a reserved free port. Raise the default test timeout for the SQLite and browser
suites that were only slow under full-suite parallelism.