feat(checklists): t-paliad-225 Slice C backend — template versioning + catalog Version

m/paliad#61 Slice C backend.

Schema (mig 116, idempotent):
- ALTER paliad.checklists ADD COLUMN version int NOT NULL DEFAULT 1.
  Pre-Slice-C rows default to 1 (the column was added with DEFAULT
  so the UPDATE clause is a no-op safety net).
- ALTER paliad.checklist_instances ADD COLUMN template_version int.
  NULL on existing rows — instance detail page leaves the "outdated"
  badge off when the snapshot version is unknown.

Services:
- ChecklistTemplateService.Update — version bumps on title/body
  changes (the meaningful edits that warrant notifying instance
  owners). Pure metadata tweaks (description/court/reference/deadline)
  update updated_at without bumping. Emits the new 'checklist.versioned'
  audit event with prior_version + new_version metadata.
- ChecklistInstanceService.Create — captures snapshot_version
  alongside the body snapshot.
- ChecklistCatalogService — CatalogEntry grew a Version field
  (1 for static; live column for authored). ListVisible / Find
  populate it.
- Models — Checklist.Version int; ChecklistInstance.TemplateVersion *int.
- /api/checklists/{slug} response now includes version so the
  instance detail page can compare against the snapshot.

Migration verified live via BEGIN..ROLLBACK against paliad.checklists
and paliad.checklist_instances.

Build hygiene: go build/vet/test ./internal/... + TestBootSmoke
./cmd/server/ all green.
This commit is contained in:
mAi
2026-05-20 15:50:21 +02:00
parent b850eb755c
commit fffddcc71a
7 changed files with 115 additions and 10 deletions

View File

@@ -443,6 +443,10 @@ type ChecklistInstance struct {
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
TemplateSnapshot NullableJSON `db:"template_snapshot" json:"template_snapshot,omitempty"`
// TemplateVersion is the checklists.version at instance create time.
// NULL on pre-Slice-C rows where versioning wasn't captured; the
// "outdated" badge stays off in that case.
TemplateVersion *int `db:"template_version" json:"template_version,omitempty"`
}
// ChecklistInstanceWithProject enriches an instance with its parent Project
@@ -471,6 +475,7 @@ type Checklist struct {
Visibility string `db:"visibility" json:"visibility"`
PromotedAt *time.Time `db:"promoted_at" json:"promoted_at,omitempty"`
PromotedBy *uuid.UUID `db:"promoted_by" json:"promoted_by,omitempty"`
Version int `db:"version" json:"version"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}