feat(phase 3c per-events): event_date on item_links, Documents UI, PER URL resolver, MCP date-aware add_link

migration 0011_item_links_event_date.sql: ADD event_date date + partial
index (idempotent). Day granularity by design per the PER spec; the
column lands NULL on every existing row, no backfill.

store:
- ItemLink gains an EventDate *time.Time (every read path scans it).
- AddLinkDated(ctx, item, refType, refID, rel, note, date, metadata)
  upserts with COALESCE(new, old) for note + event_date so partial
  callers don't clobber prior state.
- DatedLinks(item) returns event_date IS NOT NULL ordered DESC.

web:
- per.go: parsePER strips a trailing .YYMMDD (rejects invalid dates like
  Feb 30); collisionTag yields a/b/.../z/aa/ab/...; computePERs walks
  DatedLinks output and assigns render-time collision tags inside each
  date group. Tags are never stored.
- handleDetail: 404 retry with PER stripped — /i/mfin.house1.260515
  resolves to the house1 item with HighlightDate=2026-05-15.
- documents_section.tmpl: add-form (ref_type/date/ref_id/note),
  date-sorted rows with computed PER, ref-type badge, remove × with
  anti-forgery item-id check, highlight row when HighlightDate matches.
- POST /i/{path}/links/add and /links/remove handlers; HTMX swap on the
  fragment, redirect for non-HTMX callers.

mcp:
- add_link accepts event_date: "YYYY-MM-DD" (parsed strict, hands back
  fmt.Errorf on bad form). linkView.event_date surfaces it on responses.
- Existing add_link callers without event_date keep working unchanged.

docs:
- docs/standards/per.md gains an Implementation section pointing at
  item_links.event_date + ref_types + render-time collision policy.
- docs/design.md adds a Documents/dated artifacts section with the
  schema delta, conflict policy, and URL routing rules.

tests:
- per_test.go: parsePER (valid/invalid dates, non-numeric, wrong
  length); collisionTag (1..53); computePERs (bare-then-.a, skips
  undated, multi-date grouping).
This commit is contained in:
mAi
2026-05-15 18:35:21 +02:00
parent 836054be63
commit e055e4607e
12 changed files with 627 additions and 25 deletions

View File

@@ -0,0 +1,17 @@
-- 0011_item_links_event_date.sql
--
-- Phase 3c: add an optional event_date to projax.item_links so dated artifacts
-- (PER-cited letters, invoices, meeting notes, …) actually resolve. The PER
-- standard at docs/standards/per.md uses YYMMDD day granularity, so `date` is
-- correct here — time-of-day is intentionally not part of the standard.
--
-- The partial index makes "list every dated artifact for an item, newest
-- first" cheap without bloating the main index for the (vast) majority of
-- existing links that carry no date.
ALTER TABLE projax.item_links
ADD COLUMN IF NOT EXISTS event_date date;
CREATE INDEX IF NOT EXISTS item_links_event_date_idx
ON projax.item_links (event_date)
WHERE event_date IS NOT NULL;