# 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`, no `tailwind.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: ```bash 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) 1. Bootstrap → 2. Domain core → 3. MQTT ingest → 4. Discovery → 5. Presence → 6. Automations → 7. Polish + PWA. Each phase ends **browser-verified (R12) + Codex-clean (R15) + committed on a feature branch**.