• v1.2.0 1a3aaea933

    v1.2.0
    frontend / frontend (push) Successful in 1m19s
    pytest / test (push) Successful in 1m31s
    docker-image / build-and-push (push) Successful in 3m55s
    Stable

    tliu93 released this 2026-06-13 17:21:26 +02:00 | 1 commits to main since this release

    Replaces 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/write
      • POST /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.py output.
    • Multi-stage Dockerfile (node build → python runtime) + frontend CI workflow.
    • Explicit docker-compose.dev.yml dev stack (port 8001, -dev container
      names, prod-copy ./data DB).
    • 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 old auth.py /
      pages.py page routers.
    • docker-compose.override.yml (renamed to the explicit docker-compose.dev.yml).

    Fixed

    • Logout no longer floods GET /api/session with 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
  • v1.1.0 c1a5d7a425

    v1.1.0 — Single-database consolidation (M1)
    pytest / test (push) Successful in 50s
    docker-image / build-and-push (push) Successful in 3m52s
    Stable

    tliu93 released this 2026-06-12 20:53:09 +02:00 | 33 commits to main since this release

    Consolidates 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.

    1. Back up production app.db, locationRecorder.db, pooRecorder.db.
    2. Edit .env: remove LOCATION_DATABASE_URL / POO_DATABASE_URL (now ignored); keep APP_DATABASE_URL.
    3. Deploy the new image → the migration job (python -m scripts.run_migrations) upgrades app.db and creates the empty location / poo_records.
    4. 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

    1. Prefer a brief quiet/maintenance window (SQLite single-writer; avoids a new write colliding with a historical PK and tripping reconciliation).
    2. Verify: app.db location / poo_records row counts equal the legacy DB counts.
    3. 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.0

    Downloads
  • v1.0.3 636bb2b80b

    v1.0.3
    pytest / test (push) Successful in 53s
    docker-image / build-and-push (push) Successful in 3m59s
    Stable

    tliu93 released this 2026-04-29 13:18:03 +02:00 | 45 commits to main since this release

    This 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 changes

    Changed

    • 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 page

    Downloads
  • v1.0.2 8565534b73

    v1.0.2
    pytest / test (push) Successful in 45s
    docker-image / build-and-push (push) Successful in 3m40s
    Stable

    tliu93 released this 2026-04-22 13:35:57 +02:00 | 51 commits to main since this release

    Downloads
  • v1.0.1 c9af7530e5

    Release v1.0.1 changes compose behavior
    pytest / test (push) Failing after 44s
    docker-image / build-and-push (push) Successful in 3m40s
    Stable

    tliu93 released this 2026-04-22 13:28:51 +02:00 | 53 commits to main since this release

    Downloads
  • v1.0.0 35aee79d93

    1.0.0
    pytest / test (push) Successful in 43s
    docker-image / build-and-push (push) Successful in 3m38s
    Stable

    tliu93 released this 2026-04-20 23:34:44 +02:00 | 55 commits to main since this release

    Downloads
  • v0.9.1 94747c75dd

    release 0.9.1
    pytest / test (push) Successful in 43s
    docker-image / build-and-push (push) Successful in 3m37s
    Stable

    tliu93 released this 2026-04-20 23:07:05 +02:00 | 57 commits to main since this release

    Downloads
  • v0.9.0 7978a7e1e1

    Test release
    pytest / test (push) Successful in 42s
    docker-image / build-and-push (push) Successful in 3m42s
    Stable

    tliu93 released this 2026-04-20 22:20:16 +02:00 | 58 commits to main since this release

    With bug:
    home Assistant publish target/action unsupported: Unsupported Home Assistant target/action: poo_recorder/get_latest

    Downloads