105 lines
4.6 KiB
Markdown
105 lines
4.6 KiB
Markdown
# 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 `<form method="post">`. Full page reload.
|
|
**Why:** No JS required. Works in all contexts. AJAX reactions are a UX polish item for v1.1.
|
|
**Trade-off:** Page reload loses scroll position. Acceptable for prototype.
|
|
|
|
---
|
|
|
|
## D-08 · Roadmap parsed from `content/roadmap.md` with simple section splitter
|
|
|
|
**Chose:** Read `content/roadmap.md` with `fs.readFileSync`, split on `## ` headings, render each section's items with `marked`.
|
|
**Why:** It's a single file, not a collection. No need to add Astro content collection overhead for one file.
|
|
|
|
---
|
|
|
|
## D-09 · `better-sqlite3` excluded from Vite optimisation
|
|
|
|
**Chose:** Added `vite.ssr.external: ['better-sqlite3']` and `vite.optimizeDeps.exclude`.
|
|
**Why:** Prevents Vite from attempting to bundle the native Node module, which would fail. Standard pattern for native modules in Vite/Astro.
|
|
|
|
---
|
|
|
|
## D-10 · Ghost border on form field bottom edges
|
|
|
|
**Chose:** Input fields use `border-bottom: 1px solid rgba(186,186,176,0.30)` (ghost border pattern from design system).
|
|
**Why:** This is explicitly permitted by the design system README for form fields ("bottom-only Ghost Border"). Not a structural layout border.
|
|
|
|
---
|
|
|
|
## D-11 · AppLayout for authenticated pages, BaseLayout for auth pages
|
|
|
|
**Chose:** Two layouts. `AppLayout.astro` has the glass nav, user info, and nav links. `BaseLayout.astro` (existing) is used for login and invite redemption pages.
|
|
**Why:** Auth pages should not show the nav — they are entry points before identity is established.
|
|
|
|
---
|
|
|
|
## D-12 · Attendance RSVP shown only to Fenja role
|
|
|
|
**Chose:** The attendance tally on meeting pages is visible to all (yes/no counts). Individual RSVP selections are visible only to fenja-role users.
|
|
**Why:** SPEC §5.4: "A simple tally, not a hard RSVP. Shown only to Fenja."
|
|
|
|
---
|
|
|
|
## D-13 · Contribution edit window: 10 min enforced server-side
|
|
|
|
**Chose:** Edit button visible client-side based on `data-created` timestamp. Server validates the 10-minute window on POST.
|
|
**Why:** Both checks needed: client for UX, server for security. The client check is just convenience.
|
|
|
|
---
|
|
|
|
## D-14 · Password reset via new invite link (no email flow)
|
|
|
|
**Chose:** No forgot-password page built. Admin issues a new invite link from /admin.
|
|
**Why:** SPEC §3 explicitly says: "No forgot-password flow for v1 — admin re-issues invite links."
|