* feat(ADR-131): HOMECORE-UI operational dashboard + BFF gateway Complete two-tier Cognitum operator dashboard (ADR-131), served by homecore-server at /homecore, plus the single-origin BFF gateway that wires it to real backends. Front-end (zero-dep vanilla TS/JS + CSS, exact Cognitum design tokens): - All 10 panels (§4.1-4.10): dashboard, SEED fleet + detail, fleet map, entities (live WS subscribe_events, never polls), rooms, COGs, calibration wizard, events + automation builder, witness/audit, settings. - §6 UX invariants in code: first-class provenance, prominent stale/veto/ fragility, null(not-trained) vs withheld vs error, --mono everywhere, Hailo vs CPU COG distinction. - api.js calls the gateway routes in production; mock demoted to a dev-only ?demo=1 fixture (no mock in prod); typed error states. - Tests under plain node: import-graph, boot, render-smoke (22), interaction (3), prod-errors (13) — 5 files green; bundle ~137 KB (~37x smaller than HA), <2 ms/cold-render. BFF gateway (homecore-server/src/gateway.rs, compiled + tested on Rust 1.89): - /api/cal/* reverse-proxy to the calibration API (ADR-151). - GET /api/homecore/rooms with the RoomState adapter (breathing->breathing_bpm, heartbeat:null->heart_bpm:null, injected anomaly.threshold/room_id). - GET /api/homecore/cogs supervisor over /var/lib/cognitum/apps/. - GET /api/homecore/appliance from /proc + TCP service probes. - SEED-device/appliance routes return typed 503 upstream_unavailable. - cargo test -p homecore-server = 12/12; run live (curl-verified); fixed a real double-v1 proxy-URL bug found during live testing. Honest scope: W1/W2/W4/W6-appliance functional; W3/W5/W6-Hailo/federation return typed 503 (depend on services/hardware not in this repo). Co-Authored-By: claude-flow <ruv@ruv.net> * fix(homecore-ui): resolve code-review findings — SSRF guard, CORS/trace coverage, §6 honesty, crash guards Addresses the high-effort review of PR #1082: - SECURITY: cal_proxy rejects path-traversal/confused-deputy SSRF (`.`/`..` segments, backslash, %2e%2e/%2f, absolute) on raw+decoded forms → 400, before attaching the server-side calibration bearer. - CORRECTNESS: /api/homecore/* + /api/cal/* now covered by the shared CORS allowlist (build_cors_layer, exported from homecore-api) + TraceLayer — previously merged outside router()'s layers (no CORS, no tracing). - §6 HONESTY (no fabricated data): dashboard renders '—' for null metrics (not "null%"/"null°C"); cogs Hailo pill reflects the REAL appliance probe (not hardcoded "connected"); room anomaly threshold passed through / null, not a fabricated 0.5. - ROBUSTNESS: cogs asArray(hef) guards a non-array manifest field; calibration progress guards target<=0 (no NaN%/Infinity%); restart clears the poll timer. - CLEANUP: mock.js is now a cached DYNAMIC import (demo-only) — never bundled in production (§2.2). - New ui/tests/unit-fixes.mjs pins the above; ADR-131 + CHANGELOG updated. Co-Authored-By: claude-flow <ruv@ruv.net> --------- Co-authored-by: Nick Ruest <127058086+nicholas-ruest@users.noreply.github.com> |
||
|---|---|---|
| .. | ||
| src | ||
| ui | ||
| Cargo.toml | ||
| README.md | ||
README.md
homecore-server
Integrated HOMECORE server binary that wires state machine, API, recorder, plugins, automations, intent assistant, and HomeKit bridge into one process.
The production-ready HOMECORE binary — boots all 7 subsystems (core, API, recorder, plugins, automation, assist, HAP bridge) in a single process listening on :8123.
What this crate does
homecore-server is the integration point for the entire HOMECORE ecosystem. It orchestrates:
- HomeCore runtime — state machine, event bus, service registry
- REST + WebSocket API — Axum server on
:8123(HA-compatible) - SQLite Recorder — persists all state changes to disk
- Plugin Registry — loads and manages integrations (InProcessRuntime by default)
- Automation Engine — evaluates triggers, conditions, and actions
- Assist Pipeline — intent recognition and execution
- HAP Bridge — exposes accessories to HomeKit
All subsystems share the same HomeCore instance, so state changes flow through the event bus and trigger automations, record history, and notify WebSocket subscribers in lockstep.
Features
- Single unified process — no external microservices; run with
cargo run -p homecore-server - HA-compatible REST API — drop-in replacement for Home Assistant's
/api/on:8123 - SQLite state history — persistent recording of all state changes
- Automation engine — YAML-driven trigger→condition→action execution
- Intent assistant — regex-based (P1) intent recognition + service calling
- HomeKit bridge — exposes HOMECORE entities as HomeKit accessories
- Plugin system — load first-party Rust plugins; Wasmtime WASM plugins (P2,
--features wasmtime) - Configurable via CLI + env vars — no YAML required; sensible defaults
- Structured logging — tracing output with
RUST_LOGfiltering - Feature-gated subsystems — disable recorder (
--no-recorder), enable ruvector/wasmtime as needed
Subsystems
| Subsystem | Crate | Role | Notes |
|---|---|---|---|
| State Machine | homecore |
Core domain model | All other subsystems depend on this |
| REST API | homecore-api |
HTTP boundary | Listens on :8123; Axum framework |
| Recorder | homecore-recorder |
Persistence | SQLite; optional --no-recorder |
| Plugins | homecore-plugins |
Extension system | InProcessRuntime default; Wasmtime w/ feature |
| Automation | homecore-automation |
Trigger execution | Subscribes to event bus; YAML-driven |
| Assist | homecore-assist |
Intent pipeline | Regex recognizer (P1); semantic (P2) |
| HAP Bridge | homecore-hap |
HomeKit export | Accessories + characteristics; mDNS (P2) |
Usage
Basic startup (in-memory recorder):
cargo build -p homecore-server
./target/debug/homecore-server
# Listens on http://localhost:8123
With persistent SQLite:
./target/debug/homecore-server \
--bind 0.0.0.0:8123 \
--db sqlite:~/.homecore/home.db \
--location-name "My Home"
Full feature build (ruvector semantic search + Wasmtime plugins):
cargo build -p homecore-server --features ruvector,wasmtime --release
Via Docker (Dockerfile planned P2):
docker run -p 8123:8123 \
-e HOMECORE_DB=sqlite:///data/home.db \
-v ~/.homecore:/data \
homecore-server:latest
Test the API:
# List all entities
curl http://localhost:8123/api/states
# Set a light to "on"
curl -X POST \
-H "Content-Type: application/json" \
-d '{"state":"on","attributes":{"brightness":200}}' \
http://localhost:8123/api/states/light.kitchen
# WebSocket subscription (real-time state changes)
wscat -c ws://localhost:8123/api/websocket
Configuration via env:
export HOMECORE_BIND="0.0.0.0:8123"
export HOMECORE_DB="sqlite:~/.homecore/home.db"
export HOMECORE_LOCATION="Living Room"
export RUST_LOG="homecore=debug,homecore_api=info"
./target/debug/homecore-server
CLI Options
| Flag | Env Var | Default | Description |
|---|---|---|---|
--bind |
HOMECORE_BIND |
0.0.0.0:8123 |
REST API listen address |
--db |
HOMECORE_DB |
sqlite::memory: |
SQLite path (:memory: for ephemeral) |
--location-name |
HOMECORE_LOCATION |
Home |
Friendly name returned by /api/config |
--no-recorder |
— | off | Disable SQLite recorder (low-resource deployments) |
--ui-dir |
HOMECORE_UI_DIR |
<crate>/ui |
HOMECORE-UI asset dir served at /homecore (ADR-131); empty disables the mount |
HOMECORE-UI dashboard (ADR-131)
This binary also serves the HOMECORE-UI — the complete operational dashboard
for the two-tier Cognitum stack (v0 Appliance → SEEDs → ESP32 nodes) — at
/homecore, alongside the HA-compat /api surface. It is a zero-dependency,
no-build-step vanilla TS/JS + CSS frontend living in ui/:
cargo run -p homecore-server # then open http://localhost:8123/homecore/
It drives the live /api + /api/websocket (subscribe_events) endpoints; panels
backed by services not in this binary (SEED HTTPS API, calibration ADR-151,
federation ADR-105) render against a DEMO-flagged contract-conformant mock until
those endpoints land (ADR-131 §7.1). Frontend tests + benchmark run under plain
node (no npm install):
cd ui && npm test # import graph + render-smoke + interaction (24 checks)
cd ui && npm run bench # bundle budget (~137 KB, ~37× smaller than HA) + render timing
Comparison to Home Assistant
| Aspect | Home Assistant | homecore-server |
|---|---|---|
| Architecture | Python asyncio monolith | Rust async Tokio + component traits |
| API protocol | /api/ REST (HA wire format) |
Identical HA wire format |
| Persistence | SQLite + YAML files | SQLite (P1); Redis (P2) |
| Plugins | Python integrations in homeassistant/components/ |
Rust (P1) + WASM (P2) |
| Automation execution | Python asyncio event loop | Tokio async tasks + trait-based |
| HomeKit bridge | Via homekit integration |
Built-in homecore-hap subsystem |
| CLI | hass command with config YAML |
homecore-server with feature flags |
| Scalability | Single instance (HA Cloud for scale) | Can be load-balanced (future) |
| Binary size | ~200 MB (Python + deps) | ~50 MB (Rust, release build; 200 MB w/ wasmtime) |
Performance Targets (unreleased; TBD)
- Startup time — < 2s to listen on
:8123 - REST endpoint latency — p50 < 1 ms; p99 < 10 ms
- Event bus throughput — 10,000+ events/sec
- Automation evaluation — < 100 μs per trigger
- Concurrent WebSocket connections — 10,000+
- Memory footprint — ~100 MB (idle); ~500 MB with 1,000 recorded states
Development
Run tests:
cargo test -p homecore-server
Enable debug logging:
RUST_LOG=debug cargo run -p homecore-server -- --bind 127.0.0.1:8123
Build documentation:
cargo doc -p homecore-server --open
Relation to other HOMECORE crates
homecore-server (orchestration binary)
├── homecore (state machine)
├── homecore-api (REST + WS)
├── homecore-recorder (SQLite persistence)
├── homecore-plugins (extension system)
├── homecore-automation (trigger execution)
├── homecore-assist (intent pipeline)
└── homecore-hap (HomeKit bridge)