Move Proclamations From Sub-Categories To Groups
build-dev / nix-build (push) Successful in 32s

The portal's v2 API replaced nested categories (proclamation_categories.parent_id)
with flat categories plus tag-like groups: a proclamation now belongs to one
category and optionally one group. This lets the Proclamation Options page drop
its special-cased two-level tree.

Database:
- Add the proclamation_groups table (id, name, sort_order) and a
  proclamations.group_id column.
- Drop parent_id from the proclamation_categories DDL so fresh databases get a
  flat table.
- runMigrations() creates the new table/column, then runs a one-time
  transactional v1->v2 migration keyed on PRAGMA user_version: every legacy
  sub-category becomes a group (its id is preserved), proclamations that
  pointed at a sub-category are remapped to (parent category, new group), and
  the now-stale sub-category rows are deleted. selected flags are never
  touched, so user choices survive. No network is needed, so offline kiosks
  migrate at startup; re-running is a no-op.
- Add replaceGroups() and getAllGroups(); stop reading/writing parent_id.

API sync:
- Add PATH_GROUPS ("/groups") and parseGroupsJson().
- parseProclamationsJson() now also reads groupId.
- syncProclamationsFromApi() fetches /proclamations, /categories and /groups,
  leaves the database untouched if any request or parse fails, then replaces
  categories, replaces groups and upserts proclamations.

Proclamation Options page:
- FlatItem is now Category / Group / Proclamation.
- Each category lists only the groups that have at least one member in that
  category, so impossible pairings (e.g. Physical/Prayers) never render.
- Proclamations with no group, or with a group the portal has removed, sit
  directly under the category. Groups are collapsible and use a distinct color.

Tests:
- test_db: groups round-trip plus a legacy->v2 migration test asserting the
  group is created, proclamations are remapped, selection is preserved and a
  second initialize() is a no-op.
- test_proclamation_sync / test_api_client: parse groupId, parse groups, and
  the live smoke test now also fetches /groups.

Docs: README database table and AGENTS notes updated for groups.
This commit is contained in:
NeilClack
2026-09-10 19:49:47 -05:00
parent 2b1040d3db
commit 9fead922c4
12 changed files with 460 additions and 98 deletions
+8
View File
@@ -102,6 +102,14 @@ suite and need the `RWT_LIVE_*` secrets to pass.
- `ConfigManager` hot-reloads `config.yaml` from a watcher thread and fires
`onChanged` callbacks; `AudioManager` volume/device/`dynamic_audio` are read
from it.
- Proclamations carry a flat `category_id` plus a tag-like `group_id`
(`proclamation_groups`). The Options page lists every category and, under it,
only the groups that have at least one member in that category; ungrouped
proclamations sit directly under the category. `runMigrations()` performs a
one-time v1→v2 migration (`PRAGMA user_version`) that converts legacy
`proclamation_categories.parent_id` sub-categories into groups and remaps
their proclamations, preserving selections. No network is needed for it, so
offline kiosks migrate on startup.
---