Three test files covering the Phase 1 invariants:
- derivePulseStatus: draft/closed are sticky; open auto-closes by date.
- vote UNIQUE(pulse_id, user_id): castVote (OR IGNORE) keeps the first vote
silently, a raw second INSERT raises a constraint error, and uniqueness is
per-pulse (same user on a different pulse is fine).
- homeRouteForRole: cab/fenja → /pulse, pilot → null (render existing home).
tests/setup.ts opens BIFROST_DB_PATH=':memory:' and applies all migrations
before tests run, so the in-memory DB has the live schema. Each vitest fork
gets its own globalThis → its own fresh in-memory DB.
The homeRouteForRole helper extraction makes the / role-redirect testable
without booting Astro. Step 6 will use it from /index.astro.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parses the H2 sections (In progress / Next / Later) into roadmap_items rows.
Maps In-progress → beta (actively built, tested with pilots) and Next/Later
→ exploring with a target hint. Idempotent: skips entirely if the table is
already populated, so admin edits are never overwritten.
content/roadmap.md stays in the repo as the seed source. Once admin starts
editing via /admin, the DB is the source of truth.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds typed query functions for the council-portal entities. Pulse status is
stored AND derived: draft and closed are sticky, open auto-decays to closed
once now ≥ closes_at. Draft → open is an explicit admin Publish action, not
date-driven, so admins can stage a pulse without surprise auto-publishing.
Roadmap updateRoadmapItem stamps shipped_at the first time status transitions
to 'shipping' and never resets it; returns { shippedNow } so callers can fire
the roadmap_shipped activity row exactly once.
Event RSVPs reuse the existing attendance table with kind='event'; no
parallel Rsvp table. setEventRsvp upserts on UNIQUE(user_id, meeting_slug).
getLitQuarters drives the CouncilMark dot pattern from
roadmap_attributions × shipped_at — admin-curated, not derived from votes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- BIFROST_DB_PATH env var overrides the default bifrost.db path; lets
vitest open ':memory:' per suite without touching prod data.
- Extend User/UserPublic with title, cab_joined_date, slug.
- Update SELECT lists for getUserPublicById and getAllUsersPublic.
- Add getUserBySlug for /members/:slug routes.
- Add slugifyName + generateUniqueSlug; createUser now auto-slugs from name
and stamps cab_joined_date for cab-role users.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds title/cab_joined_date/slug to users, extends attendance with kind enum
and 'interested' status, and creates pulses, votes, roadmap_items,
roadmap_attributions, events, and activity tables.
Slug backfill covers the three seed users; new-user slug generation will
live in db.ts. roadmap_items has shipped_at to drive the council mark
(simpler than an audit table). roadmap_attributions is admin-curated only.
Also logs the pre-existing /api/contributions/[id]/edit 302-only bug in
KNOWN_ISSUES.md so it isn't lost; out of scope for this work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>