# DECISIONS.md — Project Bifrost Decisions made during autonomous build. Each entry: what was chosen, why, and where it applies. --- ## D-01 · Content collections in `src/content/` not root `content/` **Chose:** `src/content/updates/` and `src/content/meetings/` for Astro content collections. **Why:** Astro 4 requires content collections to live inside `src/content/`. The root `content/` folder cannot be used for typed collections with Zod schemas. **Applies to:** updates, meetings. **Note:** `content/roadmap.md` stays at root and is read via `fs.readFileSync` since it's a single file, not a collection. --- ## D-02 · `marked` added as a runtime dependency **Chose:** Added `marked ^12.0.0` for rendering user-contributed markdown. **Why:** SPEC requires markdown-lite rendering (bold, italic, links, lists, code blocks) in contributions and replies. A homegrown parser risks XSS and correctness bugs. `marked` is tiny, well-maintained, and ships its own TypeScript types. **Note:** HTML output is not sanitized (no DOMPurify). Acceptable for a private hub with 14 trusted users. Flag for v1.1 if scope expands. --- ## D-03 · Sessions: 7-day, random 32-byte hex ID **Chose:** Sessions stored in SQLite. Cookie `bifrost_session` holds a 32-byte random hex string. Expiry 7 days. HttpOnly, SameSite=Lax. **Why:** Simple, auditable. No JWTs — session validity is always checkable server-side. SPEC mandates HttpOnly + SameSite=Lax. --- ## D-04 · Invite tokens: HMAC-signed, hash stored in DB **Chose:** Token format `${randomBase64url}.${hmac16chars}`. SHA-256 hash of the full token stored in `invites.token_hash`. HMAC key = `BIFROST_SECRET`. **Why:** SPEC says "HMAC-signed, not JWTs". Storing the hash means a compromised DB doesn't reveal usable tokens. --- ## D-05 · `BIFROST_SECRET` env var with dev fallback **Chose:** `process.env.BIFROST_SECRET ?? 'dev-secret-do-not-use-in-production'` **Why:** Zero-config for local dev. Production must set the env var. A `.env.example` documents it. --- ## D-06 · Calendar navigation via URL params, no JS **Chose:** `/calendar?y=2026&m=4` — month grid built server-side per request. **Why:** Works without JavaScript. Simpler to reason about. JS keyboard nav is a v1.1 enhancement. --- ## D-07 · Reactions use form POST (full reload) **Chose:** +1 reaction is a plain `