Skip to content

feat(backup): plural participations, per-database coverage (postiz 2.1.0) - #163

Merged
pofallon merged 1 commit into
mainfrom
feat/plural-backup-participations
Sep 20, 2026
Merged

pofallon merged 1 commit into
mainfrom
feat/plural-backup-participations

Conversation

@pofallon

Copy link
Copy Markdown
Contributor

Closes #152. Closes #153.

Why these are one PR

#153 (postiz's temporal-postgres has no hooks) was blocked on #152 (the schema forbids plural participations). The server has supported a list of participations since spec 004; the catalog could not express one, so no bundle could adopt it.

Schema

backup is now the singular object or a list of { id, preHook?, postHook? }. The singular form is untouched and normalises server-side to one participation named default — no existing bundle changes.

Validator

backupParticipations() mirrors the server's reader, and every hook check runs per participation with errors that name the entry (backup[1].preHook.service). Adds what JSON Schema can't: an id must be non-empty and unique — the server keys hook ordering and failure reporting on it, so a duplicate makes two databases indistinguishable in the one message you get when a dump fails.

The "runs a database, declares no hooks" warning is now per database service. An app-level check passes the moment one hook exists, which is exactly how postiz shipped with temporal-postgres never quiesced. The pre-hook is the quiesce, so that is what has to name each database.

The recogniser

Per-service warnings need to know which service is the database, so DATABASE_IMAGE (a substring regex over the whole image: line) becomes a service→image scan plus a port of the server's isDatabaseImage: same family list, same last-path-segment matching, same companion-role exclusions (postgres-exporter is not a database).

The docstring now says outright that this list and the server's DATABASE_IMAGE_FAMILIES are twins that must name the same families, and what goes wrong when they don't:

postiz 2.1.0

Adopts the plural form — app-db keeps the existing pg_dump, temporal-db adds pg_dumpall over Temporal's temporal and temporal_visibility databases. temporal-postgres gains the same ${HOLA_APP_DATA}/backups:/backups bind the primary database has; without it the dump lands outside the data root and never reaches a snapshot.

Verified

  • all 18 apps validate clean, no warnings
  • before the postiz change, the new per-database warning fired on exactly temporal-postgres and nothing else — no false positives across the catalog
  • negative cases caught: duplicate id, a hook naming a nonexistent service, a missing id (schema)
  • the server's own backupParticipations + judgeBackupCoverage read postiz's new block as quiesced, targeted 2 / recognised 2

Ordering

Best merged after try-hola/hola#470 ships — until the server recognises pgautoupgrade, postiz's dashboard coverage reads quiesced for the wrong reason (recognised: 0) either way. Nothing here depends on it to be correct.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Vck5KSX2CLxhohx14nb5Sh

The server has supported a list of backup@1 participations since spec 004; the
catalog's schema forbade it, so no bundle could adopt it and postiz's second
Postgres stayed unquiesced (#153, blocked on #152).

Schema: `backup` is now the singular object OR a list of `{ id, preHook?,
postHook? }`. The singular form is untouched and normalises server-side to one
participation named `default`, so no existing bundle changes.

Validator: `backupParticipations()` mirrors the server's reader and every hook
check runs per participation, with errors that name the entry
(`backup[1].preHook.service`). Adds what JSON Schema can't express — an id must
be non-empty and unique, because the server keys hook ordering and failure
reporting on it and a duplicate makes two databases indistinguishable in the one
message you get when a dump fails.

The "runs a database, declares no hooks" warning is now **per database service**.
An app-level check passes the moment one hook exists, which is exactly how postiz
shipped with temporal-postgres never quiesced. The pre-hook is the quiesce, so
that is what has to name each database.

That required knowing WHICH service is the database, so DATABASE_IMAGE (a
substring regex over the whole `image:` line) becomes a service->image scan plus
a port of the server's `isDatabaseImage` — same family list, same last-path-
segment matching, same companion-role exclusions (`postgres-exporter` is not a
database). The docstring now says outright that this list and
DATABASE_IMAGE_FAMILIES are twins that must name the same families, and what
goes wrong when they don't: a family only this side knows is a needless warning,
a family only that side knows is an app shipping with no hooks and no warning,
and a family NEITHER knew is how `pgautoupgrade` ended up rendering as fully
quiesced on four apps' dashboards (try-hola/hola#470).

postiz 2.1.0 adopts the plural form: `app-db` keeps the existing pg_dump,
`temporal-db` adds `pg_dumpall` over Temporal's `temporal` and
`temporal_visibility` databases. temporal-postgres gains the same
`${HOLA_APP_DATA}/backups:/backups` bind the primary database has — without it
the dump would land outside the data root and never reach a snapshot.

Verified: all 18 apps validate clean with no warnings; before the postiz change
the new per-database warning fired on exactly temporal-postgres and nothing
else. Negative cases caught: duplicate id, a hook naming a nonexistent service,
a missing id (schema). The server's own `backupParticipations` +
`judgeBackupCoverage` read postiz's new block as `quiesced 2/2`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vck5KSX2CLxhohx14nb5Sh
@pofallon
pofallon merged commit 4875143 into main Sep 20, 2026
5 checks passed
@pofallon
pofallon deleted the feat/plural-backup-participations branch September 20, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant