diff --git a/server/src/__tests__/database-backup-catalog-guidance.test.ts b/server/src/__tests__/database-backup-catalog-guidance.test.ts new file mode 100644 index 00000000000..21b28c9aa45 --- /dev/null +++ b/server/src/__tests__/database-backup-catalog-guidance.test.ts @@ -0,0 +1,15 @@ +import { expect, it } from "vitest"; +import { searchRunnerApi } from "../services/native-runtime/runner-api-catalog.js"; + +// An agent asked to back up and verify a restore cannot do either. Its API search must give it the real operator +// paths, so it does not invent a backup page: the retention setting, the CLI, and restore into a separate database. +it.each(["backup instance restore snapshot", "database backups list restore"])("search %j describes the real backup and restore paths", query => { + const operation = searchRunnerApi({ query, limit: 10 }).results.find(row => row.operationId === "POST /api/instance/database-backups"); + expect(operation, query).toBeDefined(); + const description = operation!.description; + expect(description).toContain("agent credentials receive 403"); + expect(description).toContain("The web UI has no control that creates or restores a backup"); + expect(description).toContain("Backup retention section of the company-prefixed /company/settings page"); + expect(description).toContain("paperclipai db:backup"); + expect(description).toContain("separate, empty PostgreSQL database, never over the live one"); +}); diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index 08bea0a8c19..e4c2f54bb37 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -9885,6 +9885,7 @@ registry.registerPath({ path: "/api/instance/database-backups", tags: ["instance"], summary: "Trigger a database backup", + description: "Instance admins only: agent credentials receive 403, and cloud-managed instances run backups for you. Automatic gzip-compressed backups run about hourly by default; instance admins set how long they are kept in the Backup retention section of the company-prefixed /company/settings page. The web UI has no control that creates or restores a backup. For a backup now, an instance admin calls this endpoint, or an operator with shell access to the server runs `paperclipai db:backup` (add --json for metadata). The result names a gzip-compressed SQL file (backupFile) on the server host and its size. Paperclip has no restore endpoint or command: to check a backup, an operator restores the file with psql into a separate, empty PostgreSQL database, never over the live one, and then checks the restored data.", responses: { 200: r.ok(), 401: r.unauthorized, 403: r.forbidden }, });