1. Markdown preview in the admin edit panel now re-renders from the
textarea's current value on every toggle (dynamic-imports marked on
the client). Previously the panel showed the server-rendered seed
value forever, so new dispatches always previewed empty.
2. Pulse sub-form drops the opens_at field (opens on dispatch publish
automatically) and changes closes_at to a date input — the chosen
day is treated as end-of-day in the DB.
3. /dispatches/[slug] reading width widened 50% (720 → 1080px).
4. Roadmap display_order cascades on insert / update / delete:
inserting at N bumps N..end up by 1, deleting N pulls N+1..end
down by 1, moving from A to B shifts the intermediate range by 1
in the appropriate direction. Order stays dense — no gaps, no
collisions. All three transitions run in a transaction.
5. /roadmap always anchors at scrollLeft=0 on mount so the first
milestone aligns with the content-column left edge. Previously
the page jumped to the last-shipping milestone, which felt random
once items past the viewport landed.
6. Events admin list shows the actual date (fmtDateTime) instead of
"in 3 days" — easier to scan when planning across months.
7. duration_label is auto-computed from starts_at + ends_at on save
(minutes < 90, hours < 4, "Half day", "Full day", "N days").
The manual field is gone from the admin form; the column on the
member-facing event pages keeps reading the stored value as before.
8. Pulse hero still skips office hours per the existing logic — no
change. Confirmed via the test note's clarification.
9. Pulse "also coming up" strip relabeled to Previous + Upcoming.
Previous = most recent past non-office-hours event. Upcoming =
next non-office-hours event after the hero. Each card now carries
a small terracotta eyebrow with the label.
Typecheck clean, build clean, 147/147 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Backstage rebuild's first three resource configs. /admin/dispatches,
/admin/roadmap, and /admin/events now resolve through the dynamic route
with full list views, edit panels, and the publish/archive actions.
- src/admin/resources/dispatches.ts — kind/status/author/excerpt/body
fields, embedded pulse sub-form (pulse_question + multi-text options +
opens/closes datetimes), publish/archive actions, notifyCount on
drafts so the sidebar lights up terracotta until they ship.
- src/admin/resources/roadmap.ts — title/description/status/target/
display_order/metadata_text plus a multi-select-async for attributed
members. ops.update writes via setRoadmapAttributions() after the
basic save so the pivot table stays in sync.
- src/admin/resources/events.ts — full event fields; ops.create
auto-generates a unique slug from the title when blank.
- src/admin/embeds/PulseSubForm.astro — reads the dispatch's current
pulse via getPulseById(), renders question + options + opens/closes.
Pulses follow their parent dispatch's lifecycle (draft → open on
publish, → closed on archive); no status field of their own.
- src/admin/components/ResourceEditPanel.astro — dispatches on
embed.component, renders PulseSubForm for 'pulse-sub-form'.
- src/admin/resource-types.ts — renamed column .valueOf to .value
(collision with Object.prototype.valueOf was breaking TS structural
matching); OpContext now optionally carries the raw FormData so
resources with sub-forms can read embed fields.
- src/pages/admin/[resource].astro — passes formData into opCtx.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>