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).
51 lines
2.3 KiB
Cheetah
51 lines
2.3 KiB
Cheetah
{{define "documents-section"}}
|
||
<section id="documents-section" class="documents">
|
||
<h2>Documents</h2>
|
||
{{if .DocBanner}}<p class="banner warn" role="alert">{{.DocBanner}}</p>{{end}}
|
||
|
||
<form class="doc-add"
|
||
hx-post="/i/{{.Item.PrimaryPath}}/links/add"
|
||
hx-target="#documents-section"
|
||
hx-swap="outerHTML">
|
||
<select name="ref_type">
|
||
<option value="document">document</option>
|
||
<option value="note">note</option>
|
||
<option value="url">url</option>
|
||
</select>
|
||
<input type="date" name="event_date" value="{{if .HighlightDate}}{{.HighlightDate.Format "2006-01-02"}}{{end}}" required>
|
||
<input type="text" name="ref_id" placeholder="ref (path, URL, hash, …)" required>
|
||
<input type="text" name="note" placeholder="note (optional)">
|
||
<button type="submit">+ Add</button>
|
||
</form>
|
||
|
||
{{if .Documents}}
|
||
<ul class="docs">
|
||
{{range .Documents}}
|
||
<li class="doc-row {{if and $.HighlightDate (eq (.Link.EventDate.Format "2006-01-02") ($.HighlightDate.Format "2006-01-02"))}}highlight{{end}}"
|
||
id="per-{{.PER}}" data-link-id="{{.Link.ID}}">
|
||
<span class="per">{{.PER}}</span>
|
||
<span class="ref-type ref-type-{{.Link.RefType}}">{{.Link.RefType}}</span>
|
||
{{if eq .Link.RefType "url"}}
|
||
<a href="{{.Link.RefID}}" target="_blank" rel="noopener noreferrer">{{.Link.RefID}}</a>
|
||
{{else}}
|
||
<code class="ref-id">{{.Link.RefID}}</code>
|
||
{{end}}
|
||
{{if .Link.Note}}<span class="doc-note">{{deref .Link.Note}}</span>{{end}}
|
||
<small class="muted">added {{.Link.CreatedAt.Format "2006-01-02"}}</small>
|
||
<form class="doc-remove inline"
|
||
hx-post="/i/{{$.Item.PrimaryPath}}/links/remove"
|
||
hx-target="#documents-section"
|
||
hx-swap="outerHTML"
|
||
hx-confirm="Remove this document reference?">
|
||
<input type="hidden" name="link_id" value="{{.Link.ID}}">
|
||
<button type="submit" class="x" aria-label="Remove">×</button>
|
||
</form>
|
||
</li>
|
||
{{end}}
|
||
</ul>
|
||
{{else}}
|
||
<p class="muted">No dated artifacts yet. Add one above — it becomes a PER like <code>{{.Item.PrimaryPath}}.{{if .HighlightDate}}{{.HighlightDate.Format "060102"}}{{else}}YYMMDD{{end}}</code>.</p>
|
||
{{end}}
|
||
</section>
|
||
{{end}}
|