-
v1.2.0
Stablereleased this
2026-06-13 17:21:26 +02:00 | 1 commits to main since this releaseReplaces the server-side Jinja pages with a same-origin React single-page app,
backed by a new JSON API. Same container, same origin (no CORS); auth still
rides the existing Argon2 + server-side session cookie.Added
- React SPA (Vite + TypeScript + Mantine + TanStack Query + React Router),
served same-origin from FastAPI as static build output. - JSON API for the SPA:
GET/PUT /api/config— config read/writePOST /api/config/smtp/test— SMTP test action- read-only data query endpoints (location / poo)
- single-record CRUD (
PATCH/DELETE) - session/auth endpoints (
/api/session, login, logout, forced password change)
- Data visualization: Leaflet heatmap home page (viewport-normalized
intensity, dark basemap) + records-management UI (paginated lists, edit/delete
modals) — takes over what Grafana used to do. - Typed OpenAPI client generated from
scripts/export_openapi.pyoutput. - Multi-stage Dockerfile (node build → python runtime) + frontend CI workflow.
- Explicit
docker-compose.dev.ymldev stack (port 8001,-devcontainer
names, prod-copy./dataDB). - Dark-mode toggle, Feather-icon nav, Grafana-style quick time-range presets.
Changed
- Browser endpoints reuse the existing session-cookie auth with presence-only
CSRF (X-CSRF-Token). - README + architecture-overview updated for the SPA reality; retire the
"no frontend/backend split" and "Grafana as visualization" constraints.
Removed
- Jinja templates (
base/config/home/login.html) and the oldauth.py/
pages.pypage routers. docker-compose.override.yml(renamed to the explicitdocker-compose.dev.yml).
Fixed
- Logout no longer floods
GET /api/sessionwith 401s — the session probe and
the login endpoint own their 401s, breaking the redirect→refetch loop. - Heat-layer white-screen crash on first load after login.
Notes
- The device ingestion endpoint stays on bare API until M3 (token auth).
- TOTP 2FA for the now public-facing dashboard is recorded under
Future Ideas — not scheduled.
Downloads
- React SPA (Vite + TypeScript + Mantine + TanStack Query + React Router),
-
released this
2026-06-12 20:53:09 +02:00 | 33 commits to main since this releaseConsolidates the project's three separate SQLite databases (app / location / poo) into a single app.db: one SQLAlchemy Base, one engine, one Alembic chain. Cleans up the data-access code that had accumulated across the codebase and removes Grafana. No historical data is lost — the location/poo rows are moved by a one-time, idempotent, reconciled migration script.
▎ First step of the post-v1.0.3 roadmap (M1 → M2 frontend → M3 mobile): lay a clean foundation first. This is a structural change with a breaking configuration change and a mandatory one-time data migration after deploy — read the Upgrade Guide before rolling out.
✨ Highlights
- Single database. location and poo_records are merged into app.db. The data layer is unified onto one Base + a cached engine bound to app_database_url with SQLite WAL, behind a single get_db. app/auth_db.py, app/poo_db.py, app/models/base.py removed.
- One Alembic chain. A new alembic_app revision creates location / poo_records (column types match the legacy schema exactly — REAL/TEXT, nullability, PK order). The alembic_location / alembic_poo chains and adoption scripts are deleted.
- One-time migration script scripts/migrate_legacy_data.py: ATTACH + INSERT OR IGNORE (idempotent), explicit columns, full-row NULL-safe reconciliation that aborts non-zero on any missing/differing row. Never deletes or overwrites files; not in the Alembic chain or startup path.
- Config cleanup (⚠️ breaking). Settings drops location_database_url / poo_database_url and their *_sqlite_path; only APP_DATABASE_URL remains. Config page and .env.example updated.
- Grafana removed. Service, the homeautomation_grafana_storage volume declaration, and the grafana/ directory deleted. Visualization moves to the M2 React frontend (intentional interim gap).
- Docs & OpenAPI. README / architecture-overview / roadmap updated to single-DB; openapi/ re-exported (also catching up /config/smtp/test, /public-ip/check, PublicIPCheckResponse).
⚠️ Upgrade guide (required after deploy, in order)
The new code only opens app.db at runtime; deploying does not move historical data by itself — it only creates the empty tables.
- Back up production app.db, locationRecorder.db, pooRecorder.db.
- Edit .env: remove LOCATION_DATABASE_URL / POO_DATABASE_URL (now ignored); keep APP_DATABASE_URL.
- Deploy the new image → the migration job (python -m scripts.run_migrations) upgrades app.db and creates the empty location / poo_records.
- Run the one-time data migration (otherwise historical location/poo data is absent):
python -m scripts.migrate_legacy_data
--app-db sqlite:///./data/app.db
--location-db sqlite:///./data/locationRecorder.db
--poo-db sqlite:///./data/pooRecorder.db
exit code must be 0; add --dry-run first to preview
- Prefer a brief quiet/maintenance window (SQLite single-writer; avoids a new write colliding with a historical PK and tripping reconciliation).
- Verify: app.db location / poo_records row counts equal the legacy DB counts.
- Retire the old DBs (manual, after verification, keep an archive): archive the legacy files (don't delete blindly); decommission the Grafana container and the homeautomation_grafana_storage volume.
▎ No automated path ever deletes the old files — retiring them is always a manual, reversible step.
🔒 Data safety
The migration reads the legacy DBs read-only (no os.remove/unlink/shutil/truncate/DROP/DELETE); idempotency comes from INSERT OR IGNORE. Verified end-to-end against copies of the real production databases: dry-run wrote nothing, the real run migrated every row with matching per-row checksums, a second run was idempotent, a constraint-violating row aborted reconciliation non-zero, and the legacy files were md5-identical throughout.
🧹 Internal cleanup
Startup converged (lifespan validates only the app DB, still fail-closed; run_migrations returns {"app": ...}); routes/deps/models on the single data layer; test suite converged (legacy adoption tests removed, migration-script tests added); pytest green (97 passed); openapi/ re-exported.
Changelog
PR #7 (feature/m1-db-consolidation → main, merge
1e0b235): T01 table revision · T02 migration script · T03 unified data layer (WAL) · T04 startup convergence · T05 config cleanup · T06 remove Grafana · T07 docs + OpenAPI · review rework (full-row reconciliation). Full diff: v1.0.3...v1.1.0Downloads
-
v1.0.3
Stablereleased this
2026-04-29 13:18:03 +02:00 | 45 commits to main since this releaseThis release adds Grafana provisioning, public IPv4 monitoring, SMTP support, and automatic email notifications for public IP changes.
Added
• Grafana provisioning
• Public IPv4 detection and persistence
• Public IP state/history storage in the app DB
• Manual endpoint to trigger a public IP check
• Scheduled public IP checks
• SMTP configuration and test email support
• Automatic email notifications when the public IP changesChanged
• Refined sender display for notification emails
Notes
• Public IP change notification emails are sent in English
• Notifications are only sent when an actual IP change is detected
• SMTP settings can be configured and persisted from the config pageDownloads
-
v1.0.2
Stablereleased this
2026-04-22 13:35:57 +02:00 | 51 commits to main since this releaseDownloads
-
released this
2026-04-22 13:28:51 +02:00 | 53 commits to main since this releaseDownloads
-
1.0.0
Stablereleased this
2026-04-20 23:34:44 +02:00 | 55 commits to main since this releaseDownloads
-
release 0.9.1
Stablereleased this
2026-04-20 23:07:05 +02:00 | 57 commits to main since this releaseDownloads
-
Test release
Stablereleased this
2026-04-20 22:20:16 +02:00 | 58 commits to main since this releaseWith bug:
home Assistant publish target/action unsupported: Unsupported Home Assistant target/action: poo_recorder/get_latestDownloads