project-bifrost-platform/migrations/0005_polls_on_dispatches.sql
Jonathan Hvid 867661ee3d feat(polls): polls attach to dispatches — standalone Pulses entity retired
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>
2026-05-12 10:14:50 +02:00

10 lines
542 B
SQL

-- Polls are no longer a standalone entity in the UX: every poll is attached
-- to a dispatch. We keep the pulses + votes tables (vote uniqueness, status
-- derivation, admin history) and add a nullable FK from dispatches.
--
-- ON DELETE SET NULL — if an attached pulse is hard-deleted, the dispatch
-- survives without a poll rather than vanishing with it.
ALTER TABLE dispatches ADD COLUMN pulse_id INTEGER REFERENCES pulses(id) ON DELETE SET NULL;
CREATE INDEX idx_dispatches_pulse ON dispatches(pulse_id) WHERE pulse_id IS NOT NULL;