- Add github.com/jackc/pgx/v5 v5.9.1 dependency
- Add golang-migrate pgx/v5 driver
- Create migrations/postgres/0001_initial_schema.up.sql with SERIAL PRIMARY KEY
- Create migrations/postgres/0001_initial_schema.down.sql
- Rename RunMigrations to RunSQLiteMigrations in migrate.go
- Add RunPostgresMigrations with pgxmigrate driver and 'pgx5' name
- Update export_test.go to use RunSQLiteMigrations (go vet compliance)
- Remove TestMain (no longer needed; each test is isolated)
- Replace all diun.UpdatesReset() with diun.NewTestServer() per test
- Replace all diun.SetWebhookSecret/ResetWebhookSecret with NewTestServerWithSecret
- Replace all diun.WebhookHandler etc with srv.WebhookHandler (method calls)
- Replace diun.UpdateEvent with srv.TestUpsertEvent
- Replace diun.GetUpdatesMap with srv.TestGetUpdatesMap
- Update helper functions postTag/postTagAndGetID to accept *diun.Server parameter
- Change t.Fatalf to t.Errorf inside goroutine in TestConcurrentUpdateEvent
- Add error check on second TestUpsertEvent in TestDismissHandler_ReappearsAfterNewWebhook
- All 32 tests pass with zero failures
- RunMigrations applies versioned SQL files via golang-migrate + embed.FS (iofs)
- ErrNoChange handled correctly - not treated as failure
- Migration 0001 creates full current schema with CREATE TABLE IF NOT EXISTS
- All three tables (updates, tags, tag_assignments) with acknowledged_at and ON DELETE CASCADE
- Uses database/sqlite sub-package (modernc.org/sqlite, no CGO)
- go mod tidy applied after adding dependencies
- Store interface with 9 methods covering all persistence operations
- SQLiteStore implements all 9 methods with exact SQL from current handlers
- NewSQLiteStore sets MaxOpenConns(1) and PRAGMA foreign_keys = ON
- UpsertEvent uses ON CONFLICT DO UPDATE with acknowledged_at reset to NULL
- AssignTag uses INSERT OR REPLACE for tag_assignments table
- golang-migrate v4.19.1 dependency added to go.mod
- TestUpdateEventAndGetUpdates: UpdateEvent error now fails test
- TestUpdatesHandler: UpdateEvent error now fails test
- TestConcurrentUpdateEvent goroutine: UpdateEvent error now fails test
- TestDismissHandler_Success: UpdateEvent error now fails test
- TestDismissHandler_SlashInImageName: UpdateEvent error now fails test
- TestDismissHandler_ReappearsAfterNewWebhook: bare UpdateEvent call now checked
All 6 silent-return sites replaced; test failures are always visible to CI
- Add maxBodyBytes constant (1 << 20 = 1 MB)
- Add errors import to production file
- Apply http.MaxBytesReader + errors.As(err, *http.MaxBytesError) pattern in:
WebhookHandler, TagsHandler POST, TagAssignmentHandler PUT and DELETE
- Return HTTP 413 RequestEntityTooLarge when body exceeds limit
- Fix oversized body test strategy: use JSON prefix so decoder reads past limit
(Rule 1 deviation: all-x body fails at byte 1 before MaxBytesReader triggers)
- TestWebhookHandler_OversizedBody: POST /webhook with >1MB body expects 413
- TestTagsHandler_OversizedBody: POST /api/tags with >1MB body expects 413
- TestTagAssignmentHandler_OversizedBody: PUT /api/tag-assignments with >1MB body expects 413
- Verifies tag survives a second UpdateEvent() for the same image (DATA-01)
- Verifies acknowledged_at is reset to NULL by the new event
- Verifies event fields (Status) are updated by the new event
- Add PRAGMA foreign_keys = ON in InitDB() after SetMaxOpenConns(1)
- Replace INSERT OR REPLACE INTO updates with named-column INSERT ON CONFLICT UPSERT
- UPSERT preserves tag_assignments rows on re-insert (fixes DATA-01)
- FK enforcement makes ON DELETE CASCADE fire on tag deletion (fixes DATA-02)
- Protect `/webhook` endpoint using the `Authorization` header
- Update `README.md` with setup instructions and examples for authentication
- Warn when `WEBHOOK_SECRET` is not configured
- Add tests for valid, missing, and invalid token scenarios
- Update `docker-compose.yml` to support `WEBHOOK_SECRET` configuration
- **fix(sql):** wrap `rows.Close` in a `defer` function to safely handle potential close errors
- **fix(api):** handle JSON encoding errors in API responses to prevent unhandled edge cases
- **docs:** correct typos and improve phrasing in `.claude/CLAUDE.md`
- **test:** add error handling for `UpdateEvent` in test cases
- **feat(ui):** implement `AcknowledgeButton` component for acknowledging images
- **feat(stats):** add dashboard stats for total images, pending updates, and acknowledged status
- **chore(deps):** introduce `bun` dependency management and add required libraries
- **style(ui):** enhance UI with Tailwind-based components and modularity improvements
- **chore:** add drag-and-drop tag assignment using `@dnd-kit/core`