Go to file
HomeOS Bootstrap 60d5275819 feat(presence): who's-home overview, person edit/delete, avatars, faster away
Issue 1 — presence was half-built:
- Away detection: the debounce was 8 min (you disconnect, still "home"). Now
  3 min and configurable (homeos.presence.away_debounce_minutes /
  PRESENCE_AWAY_DEBOUNCE).
- Person management: ManagePerson modal handles BOTH add and edit (name, UniFi
  client, avatar). Delete from the person card (confirm). Replaces AddPerson.
- Avatar upload: image stored on the public disk (storage:link), shown on cards
  + the who's-home strip; initials fallback (green when home).
- Who's home: a summary strip ("N Zuhause · M abwesend" with avatars) + clear
  per-person home/away, so you can see at a glance who is in.

5 tests (debounce, create+avatar, edit, delete+avatar removal). Suite 78 green,
12/12 tabs clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 10:20:49 +02:00
app feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
bootstrap Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
config feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
database feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
docker feat(devices): auto-detect host IP, discovery dedup, delete + rescan 2026-07-18 09:34:07 +02:00
lang feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
public fix(pwa): await service-worker cache write (R15) 2026-07-18 01:27:41 +02:00
resources feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
routes feat(shelly): local HTTP/RPC transport — add by IP like Home Assistant 2026-07-18 09:48:35 +02:00
sidecar feat(devices): auto-detect host IP, discovery dedup, delete + rescan 2026-07-18 09:34:07 +02:00
storage Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
tests feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
.editorconfig Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
.env.example feat(presence): who's-home overview, person edit/delete, avatars, faster away 2026-07-18 10:20:49 +02:00
.gitattributes Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
.gitignore feat(addons): Ring backend bridge — ring-mqtt ingest, cloud devices, badge 2026-07-18 01:58:40 +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 docs: README — Ring add-on setup, PWA install, full services table 2026-07-18 02:10:47 +02:00
artisan Phase 1: bootstrap — Docker stack, Laravel 13, design system, auth 2026-07-17 21:06:20 +02:00
composer.json Phase 5: UniFi presence — poll, person↔client mapping 2026-07-18 00:31:32 +02:00
composer.lock Phase 5: UniFi presence — poll, person↔client mapping 2026-07-18 00:31:32 +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 feat(addons): Ring backend bridge — ring-mqtt ingest, cloud devices, badge 2026-07-18 01:58:40 +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 Tablet control panel: touch tiles, drag-reorder, light colour modal 2026-07-18 00:58:24 +02:00
package.json Tablet control panel: touch tiles, drag-reorder, light colour modal 2026-07-18 00:58:24 +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

Add-ons

On-demand integrations, managed under Add-ons in the sidebar.

Ring (cloud, opt-in)

Ring has no local API, so HomeOS bridges it via ring-mqtt, which runs as an opt-in container (it never starts on a Ring-less setup):

bash docker/mosquitto/gen-passwd.sh              # seeds the least-privileged `ring` broker account
docker compose --profile addons up -d ring-mqtt  # start the bridge

Then:

  1. Open http://:${RING_UI_PORT:-55123} (ring-mqtt's own web UI) and sign in with your Ring account (email + password + 2FA). It mints and stores the refresh token — HomeOS never handles Ring's OAuth itself.
  2. In HomeOS → Add-ons → Ring → Install, then Connect account.
  3. Ring devices (doorbell, cameras, sensors) appear automatically under Devices, tagged Cloud.

Install as an app (PWA)

HomeOS ships a web manifest + service worker, so it installs to a tablet/phone home screen ("Add to Home Screen") and runs full-screen. Use the Steuerung (/panel) tab as the tablet control surface. Install requires HTTPS in production (localhost is exempt for testing).

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 (presence, metrics, automations)
mqtt-listener subscribes the bus, dispatches ingest jobs
mosquitto MQTT broker (auth + per-client ACLs) ${MQTT_HOST_PORT:-1883}
discovery mDNS/SSDP sidecar (host network)
ring-mqtt Ring bridge — opt-in (--profile addons) ${RING_UI_PORT:-55123}
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.