The database target type leverages this architecture: since events are already stored in the per-webhook database by design, the database target simply marks the delivery as immediately successful. The per-webhook DB IS the dedicated event database — that's the whole point of the database target type.
no. the database target type should have a configurable expiry (default: never) and should log events to a separate per-webhook archive sqlite file for long term storage. the file should be created if it does not exist and should be closed and reopened after each write (unless the last reopen was less than one second ago) and should support auto-recreate for the case where the archive sqlite db file is moved away for archiving.
> The database target type leverages this architecture: since events are already stored in the per-webhook database by design, the database target simply marks the delivery as immediately successful. The per-webhook DB IS the dedicated event database — that's the whole point of the database target type.
no. the database target type should have a configurable expiry (default: never) and should log events to a separate per-webhook archive sqlite file for long term storage. the file should be created if it does not exist and should be closed and reopened after each write (unless the last reopen was less than one second ago) and should support auto-recreate for the case where the archive sqlite db file is moved away for archiving.
clawbot
was assigned by sneak2026-03-25 02:17:08 +01:00
clawbot
removed their assignment 2026-07-25 12:10:14 +02:00
clawbot
added this to the 1.0.0 milestone 2026-08-07 13:11:41 +02:00
The Target interface (#77) is now merged, so implement this as the databaseTarget implementation.
Authoritative spec (from @sneak on this issue): the database target should have a configurable expiry (default: never) and should log events to a SEPARATE per-webhook archive sqlite file for long-term storage. The file is created if it does not exist; it is closed and reopened after each write (unless the last reopen was less than one second ago); and it supports auto-recreate for the case where the archive sqlite file is moved away for archiving.
Scope: internal/delivery/target_database.go plus a new archive-writer file it needs (keep it in the delivery or database package). Touch internal/config/config.go only if a genuinely global setting is required — prefer per-target config. Do NOT change the Target interface or other targets.
Behaviour:
databaseTarget.Deliver writes the full event (body, headers, method, content type, webhook id, entrypoint id, timestamp) as a row into a per-webhook archive sqlite file that is DISTINCT from the per-webhook event DB — e.g. archive-{webhookID}.db under the data dir. Create the file and its schema if missing.
After each write, close and reopen the archive handle, UNLESS the last reopen was less than 1 second ago (debounce). This lets an operator move the archive file away for offline archiving.
Auto-recreate: if the archive file was moved/removed since the last open, the next write recreates it (create-if-missing on open covers this).
Expiry: read an optional expiry from the target's config JSON (Target.Config), default "never" (keep forever). When an expiry is set, prune archived rows older than it — implementer's choice of mechanism (on open, or reuse the retention-sweep pattern), documented in the code. Default "never" means no pruning.
It stays fire-and-forget: record one successful attempt and mark delivered (as the current stub does), but now it actually archives.
Definition of done:
delivering to a database target writes the full event into a separate per-webhook archive sqlite file, created if absent
the handle is closed and reopened after each write with a 1-second debounce; moving the file away and delivering again recreates it
an optional per-target expiry (default never) prunes older archived rows when set
tests cover: a row is archived; the file is recreated after removal; the debounce; and expiry pruning when configured
Gates and process:
make fmt; validate with docker build . (must exit 0)
branch from main named issue-43-database-archiving; commit subject ends with (closes #43)
open a PR (base main) and comment on it with the diff summary and the docker build . result; no AI/tooling references
Note: main was just updated with the delivery refactor, the retention reaper, and NoCache. If docker build fails on something unrelated to your change, check whether an unmodified origin/main builds, and if it does not, STOP and report that main itself is broken rather than trying to fix it.
## Implementation instructions
The `Target` interface (#77) is now merged, so implement this as the `databaseTarget` implementation.
Authoritative spec (from @sneak on this issue): the database target should have a configurable expiry (default: never) and should log events to a SEPARATE per-webhook archive sqlite file for long-term storage. The file is created if it does not exist; it is closed and reopened after each write (unless the last reopen was less than one second ago); and it supports auto-recreate for the case where the archive sqlite file is moved away for archiving.
Scope: `internal/delivery/target_database.go` plus a new archive-writer file it needs (keep it in the `delivery` or `database` package). Touch `internal/config/config.go` only if a genuinely global setting is required — prefer per-target config. Do NOT change the `Target` interface or other targets.
Behaviour:
- `databaseTarget.Deliver` writes the full event (body, headers, method, content type, webhook id, entrypoint id, timestamp) as a row into a per-webhook archive sqlite file that is DISTINCT from the per-webhook event DB — e.g. `archive-{webhookID}.db` under the data dir. Create the file and its schema if missing.
- After each write, close and reopen the archive handle, UNLESS the last reopen was less than 1 second ago (debounce). This lets an operator move the archive file away for offline archiving.
- Auto-recreate: if the archive file was moved/removed since the last open, the next write recreates it (create-if-missing on open covers this).
- Expiry: read an optional expiry from the target's config JSON (`Target.Config`), default "never" (keep forever). When an expiry is set, prune archived rows older than it — implementer's choice of mechanism (on open, or reuse the retention-sweep pattern), documented in the code. Default "never" means no pruning.
- It stays fire-and-forget: record one successful attempt and mark delivered (as the current stub does), but now it actually archives.
Definition of done:
- delivering to a `database` target writes the full event into a separate per-webhook archive sqlite file, created if absent
- the handle is closed and reopened after each write with a 1-second debounce; moving the file away and delivering again recreates it
- an optional per-target expiry (default never) prunes older archived rows when set
- tests cover: a row is archived; the file is recreated after removal; the debounce; and expiry pruning when configured
Gates and process:
- `make fmt`; validate with `docker build .` (must exit 0)
- branch from `main` named `issue-43-database-archiving`; commit subject ends with ` (closes #43)`
- open a PR (base `main`) and comment on it with the diff summary and the `docker build .` result; no AI/tooling references
- Note: `main` was just updated with the delivery refactor, the retention reaper, and NoCache. If `docker build` fails on something unrelated to your change, check whether an unmodified `origin/main` builds, and if it does not, STOP and report that `main` itself is broken rather than trying to fix it.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
no. the database target type should have a configurable expiry (default: never) and should log events to a separate per-webhook archive sqlite file for long term storage. the file should be created if it does not exist and should be closed and reopened after each write (unless the last reopen was less than one second ago) and should support auto-recreate for the case where the archive sqlite db file is moved away for archiving.
Implementation instructions
The
Targetinterface (#77) is now merged, so implement this as thedatabaseTargetimplementation.Authoritative spec (from @sneak on this issue): the database target should have a configurable expiry (default: never) and should log events to a SEPARATE per-webhook archive sqlite file for long-term storage. The file is created if it does not exist; it is closed and reopened after each write (unless the last reopen was less than one second ago); and it supports auto-recreate for the case where the archive sqlite file is moved away for archiving.
Scope:
internal/delivery/target_database.goplus a new archive-writer file it needs (keep it in thedeliveryordatabasepackage). Touchinternal/config/config.goonly if a genuinely global setting is required — prefer per-target config. Do NOT change theTargetinterface or other targets.Behaviour:
databaseTarget.Deliverwrites the full event (body, headers, method, content type, webhook id, entrypoint id, timestamp) as a row into a per-webhook archive sqlite file that is DISTINCT from the per-webhook event DB — e.g.archive-{webhookID}.dbunder the data dir. Create the file and its schema if missing.Target.Config), default "never" (keep forever). When an expiry is set, prune archived rows older than it — implementer's choice of mechanism (on open, or reuse the retention-sweep pattern), documented in the code. Default "never" means no pruning.Definition of done:
databasetarget writes the full event into a separate per-webhook archive sqlite file, created if absentGates and process:
make fmt; validate withdocker build .(must exit 0)mainnamedissue-43-database-archiving; commit subject ends with(closes #43)main) and comment on it with the diff summary and thedocker build .result; no AI/tooling referencesmainwas just updated with the delivery refactor, the retention reaper, and NoCache. Ifdocker buildfails on something unrelated to your change, check whether an unmodifiedorigin/mainbuilds, and if it does not, STOP and report thatmainitself is broken rather than trying to fix it.