If esp-web-tools throws a JS error during progress display (e.g. the
manifest offset bug), flash-success never fires and the wizard gets stuck
with no way to advance. After reaching 100% progress, wait 4s for the
event; if it doesn't come, show a 'Continue →' button instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
esp-web-tools reads the flash offset from the 'offset' field in the
manifest parts array. The field was named 'address', causing the offset
to be undefined, which produced 'Writing at 0xNaN' and the
'Cannot read properties of undefined (reading toString)' error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: use --flash_size 4MB and drop OTA data from merge_bin (OTA
data at 0xc10000 inflated binary to 12.6MB, exceeding 4MB chip flash)
- main.go: seedFirmwareDir now overwrites when source size differs, fixing
PVC staleness where old 1.6MB app-only binary was never replaced
- onboard.js: renderFlashFirmware() rewritten so all elements (button,
progress bar, status text, retry help, log panel) are inline in one
container — no separate floating modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix portal crossing direction bug in collectCrossings: direction was
determined by currSide (where blob is now), but should be determined
by prevSide (where blob came from). A→B means blob was on A side before.
- Add Enabled: true to portal test fixtures so they participate in
crossing detection (portals default to disabled).
- Refactor health.Checker: add injectable checkDB field defaulting to
defaultCheckDB() for cleaner unit test overriding.
- Fix TestHealthCheckSheddingLevelJSON: use getShedLevel override instead
of trying to poke shedder internals; fixes type mismatch in closure.
- Fix TestHealthCheckUptimeIncrement: backdate startTime to guarantee
the second check crosses a 1-second boundary.
Captures console.log/warn/error and esp-web-tools state-changed events
into a scrollable monospace log panel (collapsed by default, auto-opens
on flash-start and flash-error). Includes timestamps and error detail
from the flash-error event for diagnosing failures like the toString crash.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guru Meditation/IllegalInstruction after flashing was caused by the
merged binary using default flash parameters instead of the project's
settings. esptool merge_bin flags use underscores and go after the
subcommand: --flash_mode dio --flash_freq 80m --flash_size 16MB.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On flash-error, show BOOT+RST instructions with board diagram and a
"Try Again" button instead of a dead-end error message. Escalates to
USB cable/hub advice after 2 failures. Adds a proactive collapsible
tips section before flashing starts for users who read ahead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
esptool merge_bin combines bootloader (0x0), partition table (0x8000),
application (0x10000), and OTA data (0xc10000) into a single binary
flashable at offset 0x0 — matching the manifest address and enabling
correct initial flashing via the onboarding wizard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/dist/install-button.js has bare 'tslib' imports that browsers reject.
/dist/web/install-button.js is the fully bundled build with only
relative imports — works without an import map.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch to unpkg.com/esp-web-tools@10.2.1 which resolves correctly.
The old espressif.github.io/esp-web-tools path no longer exists,
causing the firmware flashing component to silently fail to load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collect zone crossing/transition events under lock, then fire callbacks
after releasing the lock to prevent re-entrant deadlock when callbacks
themselves call zone manager methods.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mdns was moved out of the built-in ESP-IDF tree in v5.x and must be
declared via idf_component.yml for the component manager to resolve it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
led.c was missing from the build, causing undefined reference errors
for led_init, led_stop_blink, and led_blink_identify at link time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ESP-IDF 5.x requires explicit set-target even when CONFIG_IDF_TARGET
is present in sdkconfig.defaults.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
espressif/idf entrypoint is not invoked in multi-stage builds, so
idf.py is not in PATH. Sourcing export.sh activates the toolchain.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add espressif/idf:v5.2 as a multi-stage build step so the firmware
binary is baked into the image at /firmware/spaxel-firmware.bin.
On startup the mothership copies it into /data/firmware/ (PVC) if not
already present, making it immediately available for the onboarding
wizard without a manual upload.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The onboard wizard requires the esp-web-install-button custom element
from esp-web-tools. It was loaded in index.html but missing from
simple.html, causing "Firmware flashing component failed to load."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add "+ Add Node" button to bottom nav and load onboard.js with wizard
CSS. Also fix broken init that still referenced removed SpaxelAuth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bare `BLEPanel` in an inline onclick throws ReferenceError if the script
hasn't loaded yet. Using `window.BLEPanel` returns undefined instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Traefik forward-auth with Google OAuth already gates all non-device
routes. The in-app PIN system was redundant. Removes auth middleware,
/api/auth/* endpoints, auth.js from all HTML pages, and SpaxelAuth
references from JS. The auth package remains for install_secret/node
token derivation used by provisioning.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- StorageSubscriber: refactor to two-phase shutdown (forwarders drain
EventBus channels into queue, then worker drains queue to SQLite)
ensuring no in-flight events are lost on Stop()
- Fix bus_test: increase channel capacity to avoid non-blocking drops
in TestEventBusConcurrentPublish
- Fix events_test: set MaxOpenConns(1) for in-memory SQLite to prevent
concurrent-connection data visibility issues
- Fix storage_test: remove manual ctx/cancel initialization after
StorageSubscriber struct was refactored to separate workerCtx/forwarderCtx
- Fix api/events.go: zone_id and person_id always take precedence;
until timestamp uses < (cutoffMs+1000) to include full RFC3339 second
- Fix api/events_test: default mode is expert, simple mode requires
explicit ?mode=simple parameter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>