Merge pull request 'Reconcile dev from main (release 0.6.0 commits)' (#186) from main into dev
This commit was merged in pull request #186.
This commit is contained in:
+129
-21
@@ -1,27 +1,135 @@
|
|||||||
# NestQuest Release Notes
|
# NestQuest Release Notes
|
||||||
|
|
||||||
## Unreleased
|
## Version 0.6.0 — 2026-09-23
|
||||||
|
|
||||||
- **Storage layer extraction (task d0b691d8):** the SQLite storage layer
|
### Scope
|
||||||
(schema, migrations, db, store, const, recurrence, DAOs) is bundled
|
|
||||||
under `custom_components/nestquest/core/`, with the integration's
|
Sixth release of NestQuest, promoting the re-imagined architecture
|
||||||
original module names preserved as re-export shims.
|
(Features 15, 16, 18 and 20) and the foreground development-orchestration
|
||||||
- **Logger namespace change (breaking for logging configuration):** the
|
tooling from `dev` onto 0.5.0. This is a major architectural change: the
|
||||||
migrations runner now logs under
|
Home Assistant integration becomes a thin client of a standalone NestQuest
|
||||||
`custom_components.nestquest.core.migrations` instead of
|
API service that owns the database.
|
||||||
`custom_components.nestquest.migrations`. Users who tuned the old
|
|
||||||
logger name (e.g. in `logger.yaml` or `configuration.yaml`) must
|
- **Feature 15 — Domain Core Extraction:** all domain code (schema,
|
||||||
update the entry to keep that level, as the old name no longer
|
migrations, database access, the DAOs, the pure recurrence/presence
|
||||||
receives migration log output.
|
engines, materialization, completion, the SSE-free event payload
|
||||||
- **Additional logger namespace moves:** the children registry and the
|
builders, the panel snapshot builder, the children/definitions/allowlist
|
||||||
admin allowlist business layers now log under
|
business layers, and an explicit settings object) now lives in a
|
||||||
`custom_components.nestquest.core.children` and
|
Home-Assistant-free package bundled inside the integration at
|
||||||
`custom_components.nestquest.core.admin_allowlist` respectively
|
`custom_components/nestquest/core/`. The SQLite schema and migration
|
||||||
(moved with the engines/business-layer extraction, task 510c1f78).
|
versions are unchanged, so an existing `nestquest.db` opens without
|
||||||
The parent `custom_components.nestquest` logger still catches both,
|
migration. Covered by a no-Home-Assistant end-to-end smoke test.
|
||||||
so users who tune the parent rather than the leaf names are
|
(Tasks d0b691d8, 510c1f78, 4dd8f870, 628473ad.)
|
||||||
unaffected; only users who pinned a leaf logger name by its old
|
- **Feature 16 — NestQuest API Service:** a standalone FastAPI service
|
||||||
spelling need to update.
|
(`api/`) that imports `core/` and is the only writer of the database.
|
||||||
|
Panel plane (`/api/v1/panel/*`) is authenticated by a static service
|
||||||
|
token: household snapshot and an idempotent complete route. Admin plane
|
||||||
|
(`/api/v1/admin/*`): children, quest definitions, presence
|
||||||
|
schedule/override, uncomplete, regenerate, history query + CSV export,
|
||||||
|
and settings — authenticated by an Authentik OIDC JWT (issuer, audience,
|
||||||
|
JWKS signature and expiry) plus membership in `nestquest-admins`, with
|
||||||
|
the panel service token rejected outright. A server-sent-events stream
|
||||||
|
publishes the quest-completed, quest-uncompleted, quest-missed and
|
||||||
|
child-day-complete transitions; the missed sweep runs in the API with a
|
||||||
|
cross-process-safe watermark. `/health` and the OpenAPI document are
|
||||||
|
served. (Tasks 042dfc5c, ae7e90ae, 1860ef76, 4d7bae00, 44c93cfd,
|
||||||
|
e70e6bfb, 0f2afb29, e4845baa, b586a2f1, e4a9d31b, da0226b3, 2d2dda53,
|
||||||
|
2b3de7e5, 9047a97b, 9a118da9, 058c7b69, a232c4f5.)
|
||||||
|
- **Feature 18 — HA Integration as API Client:** the integration no longer
|
||||||
|
owns a database. It polls `GET /api/v1/panel/snapshot` and builds the
|
||||||
|
existing sensors (entity ids and per-child instance payload shape
|
||||||
|
unchanged), subscribes to the SSE stream and re-fires the four HA bus
|
||||||
|
events, proxies `nestquest.complete_quest` to the panel complete route,
|
||||||
|
and caches the last-good snapshot so a brief API outage does not blank
|
||||||
|
the panel. The HA admin services and the service permission gate are
|
||||||
|
removed; only the panel completion path remains. (Tasks 37d5e806,
|
||||||
|
6e70d166, b1ed9c45, 47c7c90e, d25b875f, d04f5bf3, ad67fc44.)
|
||||||
|
- **Feature 20 — Zero-Config Panel Dashboard:** the panel installs with no
|
||||||
|
hand-written card YAML and no manual dashboard creation. The cards
|
||||||
|
auto-discover children from a household entity attribute (ordered by the
|
||||||
|
API's `sort_order`), a Lovelace dashboard strategy generates the
|
||||||
|
party-board view and one quest-log view per child at render time with
|
||||||
|
computed navigation paths, and the integration registers the dashboard
|
||||||
|
on first setup. Navigation and the panel transitions match the design
|
||||||
|
mockups. (Tasks 1b6d91d2, c859af23, c2d4dd8e, 107b8fbe, 50067c1f,
|
||||||
|
fc69c940, 67775be9.)
|
||||||
|
- **Development orchestration tooling:** durable OpenCode controller and
|
||||||
|
role launchers, the foreground terminal orchestrator, the independent
|
||||||
|
review/approval gates, and the automatic release-preparation policy.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Minimum Home Assistant version: **2024.6.0**.
|
||||||
|
- A running NestQuest API service, reachable at the base URL and panel
|
||||||
|
service token configured in the integration options. The API service
|
||||||
|
source ships in `api/`; there is no container image, compose file or
|
||||||
|
deployment runbook in this release, and Feature 17 — the deployment
|
||||||
|
(TLS reverse proxy, Authentik, network separation, backups) — is **not**
|
||||||
|
part of this release and must be completed before the integration is
|
||||||
|
functional. See `docs/ARCHITECTURE.md` for the target design.
|
||||||
|
|
||||||
|
### Breaking changes
|
||||||
|
|
||||||
|
- **The HA integration no longer owns a database.** It reads exclusively
|
||||||
|
from the NestQuest API. The local `nestquest.db` is no longer opened,
|
||||||
|
migrated or written by the integration (the file is left untouched on
|
||||||
|
disk). Without a reachable API the entities become unavailable after the
|
||||||
|
configured staleness threshold; the panel serves the last-good snapshot
|
||||||
|
in the meantime.
|
||||||
|
- **HA admin services are removed** (`uncomplete`, quest-definition
|
||||||
|
create/update/set-active, presence pattern/override, CSV export,
|
||||||
|
`manage_child`, `regenerate`) and the HA-side permission gate is gone.
|
||||||
|
Admin operations move to the API, and — once Feature 19 lands — the
|
||||||
|
admin PWA. Any automation that called an admin service must be
|
||||||
|
repointed at the API.
|
||||||
|
- **Logger namespaces moved** under `custom_components.nestquest.core.*`:
|
||||||
|
the migrations runner now logs under
|
||||||
|
`custom_components.nestquest.core.migrations` (previously
|
||||||
|
`custom_components.nestquest.migrations`), and the children registry and
|
||||||
|
admin allowlist log under `custom_components.nestquest.core.children` and
|
||||||
|
`custom_components.nestquest.core.admin_allowlist`. The parent
|
||||||
|
`custom_components.nestquest` logger still catches all three; only users
|
||||||
|
who pinned a leaf logger name by its old spelling must update.
|
||||||
|
- **The panel installs with no configuration.** `child_order`,
|
||||||
|
`quest_log_path` and `board_path` are no longer required (an explicit
|
||||||
|
value still wins). The integration registers a `custom:nestquest-party`
|
||||||
|
dashboard on setup; point TouchHub at it.
|
||||||
|
- **Schema is unchanged at version 7** — no migration runs on upgrade.
|
||||||
|
|
||||||
|
### Known Limitations
|
||||||
|
|
||||||
|
- **Feature 17 (API deployment and identity) is not in this release.** The
|
||||||
|
API service source ships in `api/`, but no container image, compose
|
||||||
|
file, TLS reverse proxy, Authentik application/provider/`nestquest-admins`
|
||||||
|
group, proven network separation of the panel routes, or backup/restore
|
||||||
|
is included. Feature 17's containerization groundwork was completed on
|
||||||
|
its own feature branch, which is **not** merged into `dev` and therefore
|
||||||
|
is not part of this release. Until that deployment is completed the
|
||||||
|
integration has nothing to talk to.
|
||||||
|
- **Feature 19 (admin PWA) is not in this release.** There is no admin UI
|
||||||
|
in 0.6.0; admin operations are reachable only through the API directly.
|
||||||
|
- Moving the household database from Home Assistant to the API box is a
|
||||||
|
manual file copy (the schema is unchanged).
|
||||||
|
- Single household; single API service.
|
||||||
|
|
||||||
|
### Rollback
|
||||||
|
|
||||||
|
Schema version is unchanged (7), so no migration is involved in either
|
||||||
|
direction. Nevertheless **back up `nestquest.db` (plus `-wal`/`-shm`)
|
||||||
|
before upgrading**: 0.6.0 never touches it, and a downgrade to 0.5.0
|
||||||
|
resumes using exactly that file.
|
||||||
|
|
||||||
|
**HACS installs:**
|
||||||
|
|
||||||
|
1. Downgrade via HACS (HACS > Integrations > NestQuest > Redownload > 0.5.0).
|
||||||
|
2. Restart Home Assistant.
|
||||||
|
|
||||||
|
**Manual installs:**
|
||||||
|
|
||||||
|
1. Replace `custom_components/nestquest/` with the 0.5.0 tree.
|
||||||
|
2. Restart Home Assistant.
|
||||||
|
|
||||||
|
**Repository operators:** git-revert the 0.6.0 release merge on `main`.
|
||||||
|
|
||||||
## Version 0.5.0 — 2026-09-18
|
## Version 0.5.0 — 2026-09-18
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,5 @@
|
|||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"issue_tracker": "https://github.com/Maniacs-Mansion/NestQuest/issues",
|
"issue_tracker": "https://github.com/Maniacs-Mansion/NestQuest/issues",
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"version": "0.5.0"
|
"version": "0.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# NestQuest Architecture
|
||||||
|
|
||||||
|
Status: approved direction (2026-09-21). This document supersedes the
|
||||||
|
single-process design implied by Features 01–14, in which the Home Assistant
|
||||||
|
integration owned the database and the parent admin surface was planned as a
|
||||||
|
Lovelace card inside Home Assistant.
|
||||||
|
|
||||||
|
## 1. Why this changed
|
||||||
|
|
||||||
|
The original design put everything inside the Home Assistant integration: the
|
||||||
|
SQLite database, the business logic, the kid panel cards, and (planned) the
|
||||||
|
parent admin card. Three problems surfaced:
|
||||||
|
|
||||||
|
1. **The panel needed hand configuration.** Standing up the kid panel required
|
||||||
|
hand-writing card YAML (`child_order`, `quest_log_path`, `board_path`) and
|
||||||
|
hand-creating a Lovelace dashboard. A fresh install rendered nothing.
|
||||||
|
2. **The admin surface fought Home Assistant.** The admin design
|
||||||
|
(`design/ADMIN-SPEC.md`) is drawn at 390×844 — it is a phone app. Trapping it
|
||||||
|
inside a Lovelace card meant fighting HA's UI constraints for a mobile-first
|
||||||
|
experience.
|
||||||
|
3. **Data was locked to one process.** A standalone admin web app cannot reach a
|
||||||
|
SQLite file inside Home Assistant's config directory.
|
||||||
|
|
||||||
|
The re-imagined design keeps the panel in Home Assistant (TouchHub loads an HA
|
||||||
|
dashboard), moves data ownership to a standalone API service, and promotes the
|
||||||
|
admin surface to a standalone mobile-first PWA.
|
||||||
|
|
||||||
|
## 2. Target architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
DAKboard TouchHub
|
||||||
|
│ (loads an HA dashboard URL)
|
||||||
|
▼
|
||||||
|
HA box API box
|
||||||
|
┌───────────────────────────────┐ ┌───────────────────────────────────┐
|
||||||
|
│ Lovelace panel dashboard │ │ reverse proxy (TLS) │
|
||||||
|
│ ├ nestquest-party-board-card │ service │ ├ /api/v1/panel/* LAN-only │
|
||||||
|
│ └ nestquest-quest-log-card │ token │ └ /api/v1/admin/* public │
|
||||||
|
│ │ ─────────▶ │ FastAPI (imports core/) │
|
||||||
|
│ NestQuest integration │ │ └ SQLite (owned here) │
|
||||||
|
│ (thin client, no database) │ ◀───────── │ Authentik (OIDC) │
|
||||||
|
│ sensors + HA bus events │ SSE └───────────────────────────────────┘
|
||||||
|
└───────────────────────────────┘ ▲
|
||||||
|
PWA ───────────┘
|
||||||
|
https://nestquest.cubecraftlabs.com
|
||||||
|
```
|
||||||
|
|
||||||
|
One owner of the data (the API). Two clients (the HA integration, the PWA).
|
||||||
|
|
||||||
|
## 3. Data ownership
|
||||||
|
|
||||||
|
**The API service is the only writer.** The HA integration never opens the
|
||||||
|
database; it reads a snapshot and posts completions. This removes the
|
||||||
|
two-writer problem entirely.
|
||||||
|
|
||||||
|
- **Storage:** SQLite on the API box. Single household, trivial concurrency,
|
||||||
|
and the existing schema, migrations, and DAO tests are already SQLite. Postgres
|
||||||
|
buys nothing at this scale.
|
||||||
|
- **Schema:** unchanged. The cutover from the current HA-hosted database is a
|
||||||
|
file copy — same schema, same migration version.
|
||||||
|
- **Backups:** continuous replication (e.g. Litestream) plus a proven restore.
|
||||||
|
A configured-but-untested backup is not a backup.
|
||||||
|
|
||||||
|
## 4. Authentication: two planes
|
||||||
|
|
||||||
|
The kid panel and the admin PWA have opposite trust levels, so they use
|
||||||
|
separate credentials and separate network exposure.
|
||||||
|
|
||||||
|
### Panel plane (machine)
|
||||||
|
|
||||||
|
- **Credential:** a static service token.
|
||||||
|
- **Exposure:** `/api/v1/panel/*` is reachable **only from the LAN**.
|
||||||
|
- **Grants:** read the snapshot, and the single open write — complete a quest as
|
||||||
|
`actor: panel` with the tapped `actor_child_id`.
|
||||||
|
- **Refused:** admin routes reject the service token outright, not merely as a
|
||||||
|
non-admin. The internet cannot reach these routes at all.
|
||||||
|
|
||||||
|
This preserves the original fail-closed boundary: the kiosk can complete a
|
||||||
|
quest and nothing else.
|
||||||
|
|
||||||
|
### Admin plane (human)
|
||||||
|
|
||||||
|
- **Credential:** an Authentik OIDC JWT (authorization code + PKCE).
|
||||||
|
- **Exposure:** `/api/v1/admin/*` is internet-facing behind Authentik.
|
||||||
|
- **Grants:** everything a parent can do — definitions, assignment, presence,
|
||||||
|
children, un-complete, history, export, settings, regenerate.
|
||||||
|
- **Gate:** the API validates the JWT (issuer, audience, JWKS signature, expiry)
|
||||||
|
and requires membership in the `nestquest-admins` group. The Authentik group
|
||||||
|
is the single source of truth for "who is a parent", replacing the
|
||||||
|
integration-side admin allowlist.
|
||||||
|
|
||||||
|
## 5. Components
|
||||||
|
|
||||||
|
### `core/` — domain library
|
||||||
|
|
||||||
|
The extracted domain layer: schema, migrations, database access, DAOs, the pure
|
||||||
|
recurrence and presence engines, materialization, completion, event payload
|
||||||
|
construction, and the children/definitions/allowlist business layers. **No
|
||||||
|
Home Assistant imports.** Consumed by both the API and (during transition) the
|
||||||
|
integration. This is where the ~1500 existing tests live after extraction.
|
||||||
|
|
||||||
|
### `api/` — NestQuest API
|
||||||
|
|
||||||
|
A FastAPI service importing `core/`. Owns the database. Serves the panel and
|
||||||
|
admin planes, validates Authentik tokens, and publishes a transition event
|
||||||
|
stream (SSE) that the integration consumes. No business logic in route handlers.
|
||||||
|
|
||||||
|
### `custom_components/nestquest/` — HA integration (client)
|
||||||
|
|
||||||
|
A thin client. Polls the snapshot and builds the existing sensors; subscribes to
|
||||||
|
the SSE stream and re-fires the four HA bus events; proxies the panel completion.
|
||||||
|
Holds a last-good snapshot cache so a brief API outage does not blank the panel.
|
||||||
|
Owns no database and no business logic.
|
||||||
|
|
||||||
|
### `panel/` — Lovelace cards and dashboard strategy
|
||||||
|
|
||||||
|
The two kid-facing Lit cards plus a dashboard strategy that generates the panel
|
||||||
|
views at render time. Cards auto-discover children, so no `child_order` is
|
||||||
|
required; the strategy computes navigation paths, so `quest_log_path` and
|
||||||
|
`board_path` are not required.
|
||||||
|
|
||||||
|
### `admin/` — Admin PWA
|
||||||
|
|
||||||
|
A React progressive web app implementing `design/ADMIN-SPEC.md`, authenticated
|
||||||
|
via Authentik OIDC, installable on a phone. The only admin surface.
|
||||||
|
|
||||||
|
## 6. Zero-configuration panel
|
||||||
|
|
||||||
|
A fresh install should show the panel with no YAML:
|
||||||
|
|
||||||
|
1. **Auto-discovery.** The party-board card reads an ordered child list from a
|
||||||
|
household entity attribute instead of a configured `child_order`.
|
||||||
|
2. **Dashboard strategy.** A Lovelace strategy generates a party-board view and
|
||||||
|
one quest-log view per child, wiring navigation between them, so paths are
|
||||||
|
computed rather than configured. Explicit configuration still wins if a user
|
||||||
|
supplies it.
|
||||||
|
3. **Auto-registration.** The integration registers the dashboard on first
|
||||||
|
setup, so there is no manual dashboard step.
|
||||||
|
|
||||||
|
## 7. Home Assistant surface preserved
|
||||||
|
|
||||||
|
The re-imagining must not break what already works:
|
||||||
|
|
||||||
|
- **Sensors:** the per-child and household sensor entity_ids and the per-child
|
||||||
|
instance attribute payload shape are unchanged. The panel cards and the four
|
||||||
|
blueprints depend on them.
|
||||||
|
- **Events:** the four HA bus events (`nestquest_quest_completed`,
|
||||||
|
`nestquest_quest_uncompleted`, `nestquest_quest_missed`,
|
||||||
|
`nestquest_child_day_complete`) keep firing with their documented payloads.
|
||||||
|
They are now driven by the API's transition stream rather than by local
|
||||||
|
service handlers.
|
||||||
|
- **Blueprints:** the morning summary, afternoon reminder, end-of-day report, and
|
||||||
|
day-complete celebration continue to work with no change.
|
||||||
|
|
||||||
|
## 8. Events without an HA token on the API box
|
||||||
|
|
||||||
|
The API publishes transitions on an SSE stream; the integration subscribes and
|
||||||
|
re-fires the HA bus events locally. This deliberately avoids storing a Home
|
||||||
|
Assistant long-lived token on the API box, which would grant full HA access.
|
||||||
|
|
||||||
|
## 9. Migration phases
|
||||||
|
|
||||||
|
Mapped to the Maestro features:
|
||||||
|
|
||||||
|
| Phase | Feature | Outcome |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | 15 — Domain Core Extraction | `core/` runs with no HA imports; one implementation of the rules |
|
||||||
|
| 2 | 16 — NestQuest API Service | Panel and admin planes served with two-plane auth |
|
||||||
|
| 3 | 17 — API Deployment and Identity | TLS, Authentik, backups, network separation |
|
||||||
|
| 4 | 18 — HA Integration as API Client | Integration becomes a client; entity/event surface preserved |
|
||||||
|
| 5 | 19 — Admin PWA | Mobile-first React PWA replaces the admin card |
|
||||||
|
| 6 | 20 — Zero-Config Panel Dashboard | Panel installs itself; navigation and animations match the mockups |
|
||||||
|
|
||||||
|
Cutover: copy the existing SQLite file to the API box (same schema).
|
||||||
|
|
||||||
|
## 10. Locked decisions
|
||||||
|
|
||||||
|
- **API on its own box** — separate from Home Assistant.
|
||||||
|
- **Authentik** (`https://auth.cubecraftlabs.com`) for admin identity; a
|
||||||
|
`nestquest-admins` group is the admin source of truth.
|
||||||
|
- **Single household** — no tenant column, no multi-household auth.
|
||||||
|
- **React** for the admin PWA.
|
||||||
|
- **Drop the HA admin services** — the PWA is the only admin surface. The panel
|
||||||
|
completion path stays.
|
||||||
|
- **SQLite on the API box** initially; Postgres only if multi-household ever
|
||||||
|
becomes real.
|
||||||
|
|
||||||
|
## 11. Preserved vs. changed
|
||||||
|
|
||||||
|
**Preserved:** the tested Python domain layer, the panel card designs and
|
||||||
|
tokens, the sensor and event contract, the completion model, the append-only
|
||||||
|
event log, the panel's fail-closed "complete only" boundary.
|
||||||
|
|
||||||
|
**Changed:** data ownership moves to the API; the integration becomes a client;
|
||||||
|
the admin card becomes a PWA; panel cards become config-free with a
|
||||||
|
strategy-generated dashboard.
|
||||||
|
|
||||||
|
**New:** the API service, Authentik-gated admin auth, the PWA, and a
|
||||||
|
last-good-snapshot cache in the integration.
|
||||||
|
|
||||||
|
**Cost:** two new deployables (the API and the PWA) and one new box. Accepted
|
||||||
|
knowingly in exchange for a self-installing panel, an admin surface that is not
|
||||||
|
fighting HA's UI, and a data layer with real auth in front of it.
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "nestquest"
|
name = "nestquest"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
description = "NestQuest Home Assistant Integration"
|
description = "NestQuest Home Assistant Integration"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|||||||
Reference in New Issue
Block a user