Commit Graph
4 Commits
Author SHA1 Message Date
clawbot 4a89e4088e Bound the event log's rendered bodies in the query (closes #135)
check / check (push) Successful in 3m16s
templates/source_logs.html rendered {{.Body}} untruncated. Bodies come
from the unauthenticated receiver under a 1 MB ingest cap, and since
renderTemplate started buffering a page instead of streaming it, a
25-event page of maximal bodies is tens of megabytes of resident memory
per concurrent viewer — inflated further by HTML escaping.

The cut happens in SQL, not in the template: loadEventsWithDeliveries
now selects substr(cast(body as blob), 1, 8192) with
length(cast(body as blob)) beside it, so an oversized body never
becomes a Go string at all. Truncating template-side would still
materialise the whole value and miss the point. The casts to blob make
substr and length count bytes rather than characters, so the bound
holds for any encoding.

Events reach the page as EventLogView, alongside the existing
DeliveryView and TargetView projections, carrying BodyTruncated and
BodyBytes so the page shows a marker with the true stored size.

SQLite cuts at an arbitrary byte, so trimPartialRune drops a trailing
sequence the cut left incomplete. Bytes that are merely invalid UTF-8 —
binary payloads, which this service receives — are left exactly as
stored: utf8.FullRune reports a complete sequence for an invalid
encoding too, so only a valid prefix awaiting its continuation bytes is
removed, and a tail with no rune start in its last utf8.UTFMax bytes is
untouched. A body that was not cut is never repaired.

Also corrects the executeTemplate comment that claimed these pages are
small.
2026-08-17 20:44:32 +00:00
clawbot 4dd4dfa5eb chore: consolidate DBURL into DATA_DIR, codebase audit for 1.0.0
check / check (push) Successful in 56s
DBURL → DATA_DIR consolidation:
- Remove DBURL env var entirely; main DB now lives at {DATA_DIR}/webhooker.db
- database.go constructs DB path from config.DataDir, ensures dir exists
- Update DATA_DIR prod default from /data/events to /data
- Update all tests to use DataDir instead of DBURL
- Update Dockerfile: /data (not /data/events) for all SQLite databases
- Update README configuration table, Docker examples, architecture docs

Dead code removal:
- Remove unused IndexResponse struct (handlers/index.go)
- Remove unused TemplateData struct (handlers/handlers.go)

Stale comment cleanup:
- Remove TODO in server.go (DB cleanup handled by fx lifecycle)
- Fix nolint:golint → nolint:revive on ServerParams for consistency
- Clean up verbose middleware/routing comments in routes.go
- Fix TODO fan-out description (worker pool, not goroutine-per-target)

.gitignore fixes:
- Add data/ directory to gitignore
- Remove stale config.yaml entry (env-only config since rework)
2026-03-01 23:33:20 -08:00
clawbot 32bd40b313 refactor: self-contained delivery tasks — engine delivers without DB reads in happy path
check / check (push) Successful in 58s
The webhook handler now builds DeliveryTask structs carrying all target
config and event data inline (for bodies ≤16KB) and sends them through
the delivery channel. In the happy path, the engine delivers without
reading from any database — it only writes to record delivery results.

For large bodies (≥16KB), Body is nil and the engine fetches it from the
per-webhook database on demand. Retry timers also carry the full
DeliveryTask, so retries avoid unnecessary DB reads.

The database is used for crash recovery only: on startup the engine scans
for interrupted pending/retrying deliveries and re-queues them.

Implements owner feedback from issue #15:
> the message in the <=16KB case should have everything it needs to do
> its delivery. it shouldn't touch the db until it has a success or
> failure to record.
2026-03-01 22:09:41 -08:00
clawbot 43c22a9e9a feat: implement per-webhook event databases
check / check (push) Successful in 1m50s
Split data storage into main application DB (config only) and
per-webhook event databases (one SQLite file per webhook).

Architecture changes:
- New WebhookDBManager component manages per-webhook DB lifecycle
  (create, open, cache, delete) with lazy connection pooling via sync.Map
- Main DB (DBURL) stores only config: Users, Webhooks, Entrypoints,
  Targets, APIKeys
- Per-webhook DBs (DATA_DIR) store Events, Deliveries, DeliveryResults
  in files named events-{webhook_uuid}.db
- New DATA_DIR env var (default: ./data dev, /data/events prod)

Behavioral changes:
- Webhook creation creates per-webhook DB file
- Webhook deletion hard-deletes per-webhook DB file (config soft-deleted)
- Event ingestion writes to per-webhook DB, not main DB
- Delivery engine polls all per-webhook DBs for pending deliveries
- Database target type marks delivery as immediately successful (events
  are already in the dedicated per-webhook DB)
- Event log UI reads from per-webhook DBs with targets from main DB
- Existing webhooks without DB files get them created lazily

Removed:
- ArchivedEvent model (was a half-measure, replaced by per-webhook DBs)
- Event/Delivery/DeliveryResult removed from main DB migrations

Added:
- Comprehensive tests for WebhookDBManager (create, delete, lazy
  creation, delivery workflow, multiple webhooks, close all)
- Dockerfile creates /data/events directory

README updates:
- Per-webhook event databases documented as implemented (was Phase 2)
- DATA_DIR added to configuration table
- Docker instructions updated with data volume mount
- Data model diagram updated
- TODO updated (database separation moved to completed)

Closes #15
2026-03-01 17:06:43 -08:00