Self-hosted home information tracker for rooms, electrical panels/circuits, an interactive floorplan, and recurring or one-time maintenance. Clicking an outlet/fixture shows its breaker, clicking a breaker highlights its points on the floorplan, and completing recurring maintenance advances its next due date without losing the completed occurrence. Vendor/quote tracking is planned for a later phase.
Desktop floorplan with a selected point and its circuit details:
Circuit-walk capture at phone width:
See ARCHITECTURE.md for how it's put together and why.
The September 2026 UX review records findings, reproduction evidence, and the remediation plan.
backend/— FastAPI + SQLAlchemy + Alembic, SQLite storagefrontend/— React + Vite + TypeScript SPAscripts/import_drawio.py— one-off importer that turns room shapes drawn in an existing.drawiofloorplan into the JSON theroomsAPI expectsDockerfile/compose.yaml/compose.dev.yaml— single-container build (frontend built and served alongside the API)
Backend (needs uv):
cd backend
mkdir -p data
uv sync --locked --extra dev
uv run --locked alembic upgrade head
uv run --locked uvicorn hearth.main:app --reload --port 8000
Frontend, in another terminal:
cd frontend
npm ci
npm run dev
Open http://localhost:5173 — the Vite dev server proxies /api to the
backend on :8000.
Backend tests: cd backend && uv run --locked pytest. Frontend tests:
cd frontend && npm run test for unit tests or npm run test:e2e for the
Chromium browser regressions. Install the browser once with
npx playwright install chromium. The browser suite uses synthetic API
fixtures and does not need a Hearth database. Lint:
uv run --locked ruff check . (backend), npm run lint (frontend).
python3 scripts/import_drawio.py path/to/house.drawio --post-to http://localhost:8000
Each room shape (a labeled rectangle) becomes a room; each <diagram> page in
the file becomes a floor, named after the page's tab name unless --floor is
given. Drop --post-to to just print the JSON instead of creating rooms
directly.
docker compose -f compose.yaml -f compose.dev.yaml up --build
Builds the frontend, bakes it into the image alongside the API, runs Alembic
migrations on container start, and serves both from one port (default 8000).
compose.yaml alone (no -f compose.dev.yaml) pulls the published
ghcr.io/r055le/hearth:main image instead of building locally — that's what
the deploy host runs.
The container runs as the owned Wolfi runtime's nonroot user (uid/gid
65532) with a read-only rootfs, so before the first up, create and chown
the bind-mounted data directory to match:
mkdir -p data && sudo chown 65532:65532 data. Skipping this crash-loops the
container on "unable to open database file".
No auth in this phase — intended for tailnet/home-network access only, same
trust model as other self-hosted services here. See deploy/README.md for
the GHCR publish + host deploy pipeline.

