3.1 KiB
CLAUDE.md — HomeOS
Self-built smart-home control plane. Single household, self-hosted, LAN-first. Not Home Assistant / not a wrapper: own data model, own integrations, own UI.
Authoritative build spec: handoff.md. Non-negotiable conventions: rules.md.
Approved design direction: design-mockup.html (open in a browser).
Read all three before non-trivial work.
Locked decisions (see handoff §12)
- Framework: Laravel 13 · Livewire v3 class-based (NOT Volt) · Tailwind v4 (CSS-first
@theme, notailwind.config.js) · Vite - DB: PostgreSQL 17 + TimescaleDB (telemetry hypertables + compression/retention)
- Realtime: Laravel Reverb + Echo — every channel PRIVATE
- Queue/Cache: Redis (+ Horizon)
- MQTT: Eclipse Mosquitto 2 · client
php-mqtt/laravel-client· Python discovery sidecar - Git: local repo, no remote yet · feature branches, never commit to
main - Name: "HomeOS" is a working title
Everything runs in containers (R8 — host has only Docker)
The host has no PHP / Composer / Node for project work. Always exec into the stack:
docker compose up -d # start stack
docker compose exec app php artisan … # artisan
docker compose exec app composer … # composer
docker compose exec app npm … # node/vite (or: docker compose exec app npm run build)
docker compose logs -f app # tail
The app, horizon, scheduler, reverb (and later mqtt-listener) services share one image
(docker/app/Dockerfile). Ports are env-driven in .env (APP_PORT, VITE_PORT,
REVERB_HOST_PORT, DB_HOST_PORT). HOST_UID/HOST_GID come from id nexxo — never hardcode.
Architecture (handoff §3)
MQTT-first hybrid. Mosquitto is the bus. mqtt-listener (artisan daemon) parses + dispatches only
(H2) → Horizon jobs upsert device_states → Reverb private channels → Livewire (Echo).
UI action → DeviceCommandService → driver (ShellyMqttDriver first) → device, every command
audited in commands (H1). Vendor specifics only in app/Support/Mqtt + app/Support/Drivers (H3).
Design system (handoff §8)
"Enterprise Ops, dark OLED" — UniFi/Grafana-class console, not a consumer app. Tokens live in
resources/css/app.css @theme (ported verbatim from the mockup). Status via colored dot/pill +
text (never color alone, never emoji, R9). Every numeric value / MAC / IP / timestamp in
font-mono with tabular-nums. Hairline borders, no shadows. Accent (cyan) sparingly.
Non-negotiable rules
See rules.md (R1–R17 + H1–H5). Highlights: class-based Livewire pages (R1/R2), tokens-only
styling (R3/R10), wire-elements/modal for confirms (R5), UUID route keys (R11), browser-verify every
page (R12), English routes / German labels (R13), self-hosted fonts (R14), Codex review gate (R15),
full localization DE+EN (R16). On any conflict: STOP and ask.
Build order (handoff §13)
- Bootstrap → 2. Domain core → 3. MQTT ingest → 4. Discovery → 5. Presence → 6. Automations →
- Polish + PWA. Each phase ends browser-verified (R12) + Codex-clean (R15) + committed on a feature branch.