From b560317da07e6171d51c4b4ce027287d2c829cc6 Mon Sep 17 00:00:00 2001 From: claude-hdb Date: Thu, 16 Jul 2026 14:56:14 +0000 Subject: [PATCH] docs(draft): correct the stale "backup schedules are not exposed by the API" claim (#72) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `draft.ts` still told the operator that a database's backup schedule "is not exposed by Coolify's API" and is "create-time-only in cast" — in the `backup` uncaptured flag, its comment, and the NO_API_COVERAGE table. #51 disproved both: `GET /databases/{uuid}/backups` answers, and `diff` and `apply` now read and write it. The audit (#72) flags this as the #51 failure mode repeating — a defect filed as a limitation does not get fixed. semantics.md was already corrected when #51 landed; this brings draft.ts's three copies of the old claim in line with it. What is still true, and now said accurately: the DRAFT path (`inventory --emit-draft`) does not yet read that route, so no `backup:` block is captured and a rebuild from a draft still has no backups until the operator declares one — not because the API cannot express it. Text-only; no behavior change. `npm run check` clean, tests pass. Co-Authored-By: Claude Opus 4.8 --- src/draft.ts | 14 ++++++++------ test/draft-cli.test.ts | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/draft.ts b/src/draft.ts index c01b3b0..942ee80 100644 --- a/src/draft.ts +++ b/src/draft.ts @@ -585,13 +585,15 @@ function databaseSpec( `image "${image}" — no version could be read from its tag, so none was written and \`apply\` would create this database on Coolify's default image.`, ); } - // Coolify exposes no backup schedule on a database's GET, so a `backup:` block - // cannot be recovered. It is create-time-only in cast (see README's known - // limitations), so a rebuild from this draft would come up with NO BACKUPS — - // the quietest possible loss, and the one you discover at the worst moment. + // Coolify DOES expose a database's backup schedule — GET /databases/{uuid}/backups + // answers, and `diff`/`apply` read and write it (#51). What the DRAFT path cannot + // yet do is CAPTURE it: `inventory --emit-draft` does not read that route, so a + // `backup:` block is not recovered here. Until it is taught to, a rebuild from + // this draft still comes up with NO BACKUPS — the quietest possible loss, and the + // one you discover at the worst moment — unless the block is declared by hand. flag( "backup", - "backup schedules are not exposed by Coolify's API and are NOT in this draft. If this database is backed up, a rebuild from here would not be. Check the Coolify UI (Backups tab) and declare `backup: { frequency, retention }` yourself.", + "backup schedules are NOT in this draft — `inventory --emit-draft` does not yet read `GET /databases/{uuid}/backups` (which `diff` and `apply` do, #51). If this database is backed up, a rebuild from here would not be until you declare it. Read the schedule from a `cast diff` or the Coolify UI (Backups tab) and set `backup: { frequency, retention }` yourself.", ); return { type, ...(version ? { version } : {}) }; } @@ -798,7 +800,7 @@ const NO_API_COVERAGE: Array<[string, string]> = [ ], [ "backup schedules", - "a database's backup config is not exposed on its GET. A rebuild from this draft has NO backups until you declare them.", + "the API exposes them (`GET /databases/{uuid}/backups`, which `diff`/`apply` use — #51), but `inventory --emit-draft` does not yet read that route, so no `backup:` block is captured. A rebuild from this draft has NO backups until you declare them.", ], [ "database kinds cast does not model", diff --git a/test/draft-cli.test.ts b/test/draft-cli.test.ts index 986f7d1..89c1add 100644 --- a/test/draft-cli.test.ts +++ b/test/draft-cli.test.ts @@ -352,7 +352,7 @@ describe("cast inventory --emit-draft (#27)", () => { expect(md).toContain("destination_id 3"); expect(md).toContain("legacy-analytics"); // a MySQL cast cannot model expect(md).toContain("custom_labels"); // Basic Auth / Traefik labels - expect(md).toContain("backup"); // not exposed by the API + expect(md).toContain("backup"); // API exposes it, draft doesn't capture it yet (#51) expect(md).toContain("legacy.flag"); // not a name a template can hold // And the standing sections, emitted on every run whatever was found: