Files
DiunDashboard/.planning/phases/01-data-integrity/01-01-SUMMARY.md
Jean-Luc Makiola fb16d0db61 docs(01-01): complete UPSERT + FK enforcement plan
- Create 01-01-SUMMARY.md documenting both bug fixes and test addition
- Advance plan counter to 2/2 in STATE.md
- Record decisions and metrics in STATE.md
- Update ROADMAP.md plan progress (1/2 summaries)
- Mark requirements DATA-01 and DATA-02 complete
2026-03-23 21:16:49 +01:00

4.0 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
01-data-integrity 01 backend/storage
sqlite
bug-fix
data-integrity
upsert
foreign-keys
requires provides affects
DATA-01
DATA-02
pkg/diunwebhook/diunwebhook.go
added patterns
SQLite UPSERT (ON CONFLICT DO UPDATE)
PRAGMA foreign_keys = ON
created modified
pkg/diunwebhook/diunwebhook.go
pkg/diunwebhook/diunwebhook_test.go
Use named-column INSERT with ON CONFLICT(image) DO UPDATE SET (UPSERT) instead of INSERT OR REPLACE to preserve tag_assignments child rows
Enable PRAGMA foreign_keys = ON immediately after SetMaxOpenConns(1) so all connections (single-connection pool) enforce FK constraints
duration completed_date tasks_completed files_modified
2 minutes 2026-03-23 2 2

Phase 01 Plan 01: Fix SQLite Data-Destruction Bugs (UPSERT + FK Enforcement) Summary

One-liner: SQLite UPSERT replaces INSERT OR REPLACE to preserve tag_assignments on re-insert, and PRAGMA foreign_keys = ON enables ON DELETE CASCADE for tag deletion.

What Was Built

Fixed two silent data-destruction bugs in the SQLite persistence layer:

Bug DATA-01 (INSERT OR REPLACE destroying tags): SQLite's INSERT OR REPLACE is implemented as DELETE + INSERT. The DELETE fired ON DELETE CASCADE on tag_assignments.image, silently removing the tag assignment every time a new DIUN event arrived for an already-tagged image. Fixed by replacing the statement with a proper UPSERT (INSERT INTO ... ON CONFLICT(image) DO UPDATE SET) that only updates the non-key columns, leaving tag_assignments untouched.

Bug DATA-02 (FK enforcement disabled): SQLite disables foreign key enforcement by default. PRAGMA foreign_keys = ON was never executed, so ON DELETE CASCADE on tag_assignments.tag_id did not fire when a tag was deleted. Fixed by executing the pragma immediately after db.SetMaxOpenConns(1) in InitDB(), before any DDL statements.

Tasks Completed

Task Name Commit Files
1 Replace INSERT OR REPLACE with UPSERT + add PRAGMA FK enforcement 7edbaad pkg/diunwebhook/diunwebhook.go
2 Add regression test TestUpdateEvent_PreservesTagOnUpsert e2d388c pkg/diunwebhook/diunwebhook_test.go

Decisions Made

  1. Named-column UPSERT over positional INSERT OR REPLACE: The UPSERT explicitly lists 15 columns and their excluded.* counterparts in the DO UPDATE SET clause, making column mapping unambiguous and safe for future schema additions.

  2. acknowledged_at hardcoded NULL in UPSERT: The UPSERT sets acknowledged_at = NULL unconditionally in both the INSERT and the ON CONFLICT update clause. This ensures a new event always resets the acknowledged state, matching the pre-existing behavior and test expectations.

  3. PRAGMA placement before DDL: The FK pragma is placed before all CREATE TABLE statements to ensure the enforcement is active when foreign key relationships are first defined, not just at query time.

Deviations from Plan

None — plan executed exactly as written.

Verification Results

  • grep -c "INSERT OR REPLACE INTO updates" pkg/diunwebhook/diunwebhook.go0 (confirmed)
  • grep -c "PRAGMA foreign_keys = ON" pkg/diunwebhook/diunwebhook.go1 (confirmed)
  • grep -c "ON CONFLICT(image) DO UPDATE SET" pkg/diunwebhook/diunwebhook.go1 (confirmed)
  • Full test suite: 29 tests pass, 0 failures, coverage 63.6%
  • TestDismissHandler_ReappearsAfterNewWebhook — PASS
  • TestDeleteTagHandler_CascadesAssignment — PASS
  • TestUpdateEvent_PreservesTagOnUpsert — PASS (new regression test)

Known Stubs

None.

Self-Check: PASSED

Files exist:

  • FOUND: pkg/diunwebhook/diunwebhook.go (modified)
  • FOUND: pkg/diunwebhook/diunwebhook_test.go (modified, contains TestUpdateEvent_PreservesTagOnUpsert)

Commits exist:

  • FOUND: 7edbaad — fix(01-01): replace INSERT OR REPLACE with UPSERT and enable FK enforcement
  • FOUND: e2d388c — test(01-01): add TestUpdateEvent_PreservesTagOnUpsert regression test