Schema (migration 0005): dispatches gains a nullable pulse_id FK to pulses(id) ON DELETE SET NULL. Partial index on the populated rows. The pulses + votes tables themselves are unchanged — vote uniqueness, status derivation, and the existing tests still hold; only the entity relationship changes. db.ts: - Dispatch type gains pulse_id. New DispatchWithPoll = DispatchWithAuthor + a hydrated poll (pulse + counts + viewer's vote). - createDispatch accepts an optional poll input — if provided, creates the pulse first in the same transaction and stamps dispatches.pulse_id. - updateDispatch grows two new arguments: poll (input or null) and a pollExplicit flag. The flag distinguishes "leave the existing poll alone" (undefined) from "the admin actively chose to detach / replace it" (true). The detach path nulls pulse_id; the replace path mutates the existing pulse in place via updatePulse so vote history survives. - publishDispatch / archiveDispatch are now wrappers that also publishPulse / closePulse on the attached pulse. Dispatch state drives poll state. - getDispatchWithPoll(dispatchId, viewerId) — single call for the page renderers. Admin: - The Pulses tab is removed from the admin tab nav. The route + POST handlers stay in place so existing draft pulses aren't orphaned, but the entity is no longer a place admins go to think. - DispatchesTab form gains a poll fieldset: question + 4 option inputs (first two required if any are filled) + opens_at + closes_at. A hidden poll_explicit flag tells the server the form intentionally asserted the poll state (so leaving the fields blank during edit detaches rather than no-ops). On edit, fields prefill from the attached pulse if present. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| auth.ts | ||
| db.ts | ||
| format.ts | ||
| markdown.ts | ||
| notify.ts | ||
| routing.ts | ||