Database targets: a Download button that exports the SQLite contents as gzipped JSON #374

Open
opened 2026-10-01 21:14:28 +02:00 by clawbot · 1 comment
Collaborator

Owner's words (chat, 2026-10-01 ~19:14 UTC):

database targets should have a "download" button that dumps the sqlite file's contents as gzipped json.

PRIORITY: an owner's direct request of 1 October, in the tier of #367 to #373: after the production path, ahead of the older backlog.

Definition of done:

  • Each database target on the per-webhook page has a "Download" button. It returns that target's SQLite database contents as one gzipped JSON file (Content-Encoding not relied on: the file itself is .json.gz), named after the webhook, the target and the UTC time.
  • The JSON holds every table's rows the target stores, with event bodies included. The plan comment on this issue gives its shape, for example one top-level key per table, an array of row objects, and binary bodies base64-encoded with a marker.
  • It streams: the export never loads the whole database or the whole JSON into memory, so a large archive does not spike RAM. It reads a consistent snapshot while new events keep arriving.
  • It sits behind the admin login, like the rest of the UI. Its URL does not expose the inbound webhook UUID.
  • Tests check that the downloaded file decompresses, parses, and matches the stored rows, including a binary body and an empty database. Lands on next with an independent review, sequenced with 370, which reworks the targets section.

model: opus-5-5

Owner's words (chat, 2026-10-01 ~19:14 UTC): > database targets should have a "download" button that dumps the sqlite file's contents as gzipped json. PRIORITY: an owner's direct request of 1 October, in the tier of https://git.eeqj.de/sneak/webhooker/issues/367 to https://git.eeqj.de/sneak/webhooker/issues/373: after the production path, ahead of the older backlog. Definition of done: - Each database target on the per-webhook page has a "Download" button. It returns that target's SQLite database contents as one gzipped JSON file (`Content-Encoding` not relied on: the file itself is `.json.gz`), named after the webhook, the target and the UTC time. - The JSON holds every table's rows the target stores, with event bodies included. The plan comment on this issue gives its shape, for example one top-level key per table, an array of row objects, and binary bodies base64-encoded with a marker. - It streams: the export never loads the whole database or the whole JSON into memory, so a large archive does not spike RAM. It reads a consistent snapshot while new events keep arriving. - It sits behind the admin login, like the rest of the UI. Its URL does not expose the inbound webhook UUID. - Tests check that the downloaded file decompresses, parses, and matches the stored rows, including a binary body and an empty database. Lands on `next` with an independent review, sequenced with 370, which reworks the targets section. model: opus-5-5
clawbot self-assigned this 2026-10-01 21:14:28 +02:00
Author
Collaborator

Plan.

  • Route: GET /hook/ID/targets/TARGETID/download, behind the admin login with the other webhook pages; the URL holds the webhook and target IDs, never an entrypoint UUID. A Download button sits on each database target in the target list.
  • File: archive-WEBHOOKNAME-TARGETNAME-YYYYMMDDTHHMMSSZ.json.gz, with the names made safe by the same function as #376, sent as a download (application/gzip, attachment).
  • Shape: one JSON object with webhook (ID, name), target (ID, name), exported_at (UTC), and archived_events, an array holding one object per stored row with every column. A body that is valid UTF-8 is a string in body; any other body is base64 in body, marked with "body_encoding": "base64".
  • Streaming: rows are read with a cursor, and each one is encoded straight into the gzip writer on the response, so nothing holds the whole table or the whole JSON. The export reads in a single read transaction on its own connection, so it sees one consistent snapshot while events keep arriving, and it must not hold up the archive's writes. The PR says how the archive's journal mode makes both true.
  • An archive file that does not exist yet, or was moved away, downloads as an export with an empty archived_events; the export never creates the file.
  • Sequencing: after #367 (the paths) and 376 (one archive per target, and its file naming). The button goes into the targets section after #370.

Model: opus-5-5

Plan. - **Route:** `GET /hook/ID/targets/TARGETID/download`, behind the admin login with the other webhook pages; the URL holds the webhook and target IDs, never an entrypoint UUID. A Download button sits on each `database` target in the target list. - **File:** `archive-WEBHOOKNAME-TARGETNAME-YYYYMMDDTHHMMSSZ.json.gz`, with the names made safe by the same function as https://git.eeqj.de/sneak/webhooker/issues/376, sent as a download (`application/gzip`, attachment). - **Shape:** one JSON object with `webhook` (ID, name), `target` (ID, name), `exported_at` (UTC), and `archived_events`, an array holding one object per stored row with every column. A body that is valid UTF-8 is a string in `body`; any other body is base64 in `body`, marked with `"body_encoding": "base64"`. - **Streaming:** rows are read with a cursor, and each one is encoded straight into the gzip writer on the response, so nothing holds the whole table or the whole JSON. The export reads in a single read transaction on its own connection, so it sees one consistent snapshot while events keep arriving, and it must not hold up the archive's writes. The PR says how the archive's journal mode makes both true. - An archive file that does not exist yet, or was moved away, downloads as an export with an empty `archived_events`; the export never creates the file. - **Sequencing:** after https://git.eeqj.de/sneak/webhooker/issues/367 (the paths) and 376 (one archive per target, and its file naming). The button goes into the targets section after https://git.eeqj.de/sneak/webhooker/issues/370. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/webhooker#374