Go to file
HomeOS Bootstrap 66f0d7b067 Fix R15: reject out-of-order MQTT state updates (concurrency)
With multiple Horizon workers, ingest jobs for one entity can finish out of
order and overwrite newer state with older. The listener now stamps each message
with a µs receive time (observed_at); IngestShellyMessage applies state only when
the incoming message is newer (race-safe via a conditional update + unique guard),
and broadcasts only when applied. Added a feature test for the ordering guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 23:01:32 +02:00
app Fix R15: reject out-of-order MQTT state updates (concurrency) 2026-07-17 23:01:32 +02:00
bootstrap Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
config Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
database Fix R15: reject out-of-order MQTT state updates (concurrency) 2026-07-17 23:01:32 +02:00
docker Fix R15: pass MQTT passwords to the broker without shell interpolation 2026-07-17 22:54:03 +02:00
lang Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
public Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
resources Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
routes Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
storage Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
tests Fix R15: reject out-of-order MQTT state updates (concurrency) 2026-07-17 23:01:32 +02:00
.editorconfig Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
.env.example Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
.gitattributes Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
.gitignore Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
.npmrc Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
CLAUDE.md Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
README.md Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
artisan Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
composer.json Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
composer.lock Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
design-mockup.html Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
docker-compose.yml Phase 3: MQTT ingest — Mosquitto bus, Shelly driver, live device state 2026-07-17 22:51:14 +02:00
handoff.md Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
package-lock.json Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
package.json Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
phpunit.xml Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
rules.md Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
vite.config.js Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00

README.md

HomeOS

Self-built smart-home control plane — single household, self-hosted, LAN-first. Laravel 13 · Livewire v3 · Tailwind v4 · PostgreSQL 17 + TimescaleDB · Redis/Horizon · Reverb.

Everything runs in Docker; the host needs only Docker (no PHP/Composer/Node). Authoritative spec: handoff.md · conventions: rules.md · guide: CLAUDE.md.

First-run setup

cp .env.example .env                                        # dev defaults work as-is
docker compose build                                        # build the app image
docker compose run --rm app bash docker/app/bootstrap.sh    # deps + key + assets + migrate/seed
bash docker/mosquitto/gen-passwd.sh                         # broker credentials (fills empty MQTT_*_PASSWORD)
docker compose up -d                                        # start the full stack

docker compose up alone is not the first command — vendor/, node_modules, public/build and the Mosquitto passwd file are not committed, so the steps above must run first.

Then open http://localhost and sign in with the seeded dev admin:

Production

.env.example ships development defaults. For a real deployment you must:

  • set APP_ENV=production and APP_DEBUG=false (otherwise exceptions are exposed and the demo household is seeded into your real database);
  • set strong values for DB_PASSWORD, the REVERB_APP_* keys and HOMEOS_ADMIN_PASSWORD (seeding aborts if the admin password is unset outside local/testing), and run php artisan key:generate.

The demo seeder (DemoHomeSeeder) only runs in local/testing.

Everyday commands (in-container, R8)

docker compose exec app php artisan …    # artisan
docker compose exec app composer …       # composer
docker compose exec app npm run build    # rebuild assets (or `npm run dev` for HMR)
docker compose exec app php artisan test # test suite
docker compose logs -f app               # logs

Services & ports

Service Role Host port
app php-fpm + nginx + supervisor ${APP_PORT:-80}
reverb websockets (proxied same-origin via nginx /app) ${REVERB_HOST_PORT:-6001}
horizon · scheduler queue workers · cron
db PostgreSQL 17 + TimescaleDB 127.0.0.1:${DB_HOST_PORT:-5432}
redis cache / queue

All ports and HOST_UID/HOST_GID are env-driven in .env.