chore(canary-phase1): database & repositories complete

Phase 1 deliverables (audited PASS by superpowers:code-reviewer + general-purpose):

Implementation (1 commit):
- b2558e2e  Postgres schema + token & event repositories + testcontainers helper

Schema:
- 3 goose migrations under internal/core/migrations/ (tokens, events, indexes)
- All spec §7.1 columns + types + CHECK constraints present
- All 8 spec indexes present, including 2 partial indexes
- FK ON DELETE CASCADE on events.token_id (verified by TestRepository_FKCascade)
- chk_token_type enforces the 7-token locked enum exactly

Repositories:
- token: Insert / GetByID / GetByManageID / DeleteByManageID / IncrementTriggerCount /
         SetEnabled / ListAll / CountAll
- event: Insert / GetByID / ListByToken (cursor pagination, LIMIT N+1 trick) /
         CountByToken / AttachFingerprint (jsonb || merge into most-recent within
         configurable window) / UpdateNotifyStatus / PruneToLimit (window function)
- Both: ErrNotFound on sql.ErrNoRows; all errors wrapped with %w; Repository struct
        + NewRepository(*sqlx.DB) constructor pattern matches template

Tests:
- 11 token integration tests + 9 event integration tests, all PASS
- testcontainers/postgres:18-alpine spins per test (~5-7s each)
- Tagged //go:build integration so plain `go test ./...` stays cheap
- Coverage: insert, get, not-found, delete with cascade, atomic increment,
  enable toggle, list pagination across 3 pages, fingerprint merge preserving
  existing extras, prune-keeps-newest, prune-rejects-zero, type CHECK rejection

Wired into main.go: core.RunMigrations(db.DB.DB) on startup; tokenRepo +
eventRepo blank-assigned (services consume them in Phase 9/10).

Audit findings (informational, non-blocking, deferred):
- Spec text says CHECK names 'chk_type'/'chk_channel'; implementation uses
  'chk_token_type'/'chk_alert_channel' (audit prompt's expected names — both
  agents endorse). Functionally identical; spec literal could be amended.
- main.go uses 'db.DB.DB' triple-chain to pass *sql.DB to goose. Visually
  awkward; a Database.SQLDB() accessor would clean it up. Cleanup pass later.
- Default list limits (50, 20) are inline literals; hoisting to package consts
  would satisfy MEMORY.md 'no magic numbers' rule. Minor.
- ptr[T any] helper duplicated across token + event test files. Could move to
  testutil. Trivial.
- spec §12.4 ENVIRONMENT vs APP_ENVIRONMENT mismatch (logged in Phase 0
  rollup) carries forward; not Phase 1's concern.

Verification at phase boundary:
- go build ./...                                clean
- go vet ./...                                  clean
- go test -tags=integration ./internal/token/...   11/11 PASS
- go test -tags=integration ./internal/event/...    9/9 PASS

Phase 1 complete. Next: Phase 2 (generator interface + webbug + 1×1 GIF).
This commit is contained in:
CarterPerez-dev 2026-05-10 05:54:03 -04:00
parent b2558e2e41
commit 7a98ef8d72

Diff Content Not Available