# Project Bifrost — Claude Code Memory

> This file is persistent context for every Claude Code session on this repo. Keep it under 200 lines. If something is only relevant to one feature, it does not belong here — put it in `SPEC.md` or a scoped file.

## Project

**Project Bifrost** is Fenja AI's invite-only pilot hub — a private website for pilot participants and Customer Advisory Board members during a ~3–4 month pilot of Fenja's sovereign AI platform. Full product specification lives in `SPEC.md`. Read it before doing anything substantial; it is the source of truth.

## Stack

- **Framework:** Astro 4+ (server output mode where needed, static elsewhere)
- **Language:** TypeScript, strict mode
- **Styling:** Vanilla CSS with design tokens derived from `design/colors_and_type.css` — *no Tailwind*, no CSS-in-JS, no component libraries with baked-in styling
- **Database:** SQLite via `better-sqlite3`
- **Auth:** Custom. Session cookies + bcrypt + signed invite tokens. No third-party auth providers.
- **Runtime:** Node 22 LTS
- **Package manager:** pnpm (never npm, never yarn)
- **Hosting:** Single Hetzner Cloud VPS (CAX11, Helsinki) behind Caddy

## Commands

```
pnpm install          # install dependencies
pnpm dev              # start dev server on :4321
pnpm build            # production build
pnpm preview          # preview production build locally
pnpm test             # run vitest
pnpm typecheck        # tsc --noEmit
pnpm lint             # eslint + prettier check
pnpm db:migrate       # apply migrations to dev SQLite
pnpm db:seed          # seed dev database with test users
```

Always run `pnpm typecheck` and `pnpm test` before claiming a task is done.

## File structure

```
/
├── SPEC.md                      # product spec (source of truth)
├── CLAUDE.md                    # this file
├── design/                      # design system — authoritative for all visual language
│   ├── SKILL.md                 # instructions for how to use this design system (read first)
│   ├── README.md                # human overview
│   ├── ICONOGRAPHY.md           # icon style & usage
│   ├── colors_and_type.css      # authoritative colour & type tokens
│   ├── assets/                  # logo and brand assets
│   ├── fonts/                   # font files
│   ├── preview/, screenshots/, ui_kits/, uploads/  # reference material
├── content/                     # markdown content
│   ├── updates/                 # YYYY-MM-DD-slug.md progress posts
│   ├── meetings/                # YYYY-MM-DD-slug.md meeting pages
│   └── roadmap.md               # single roadmap file
├── src/
│   ├── pages/                   # Astro routes
│   ├── components/              # Astro components
│   ├── layouts/                 # page layouts
│   ├── styles/
│   │   ├── tokens.css           # CSS custom properties — derived from design/colors_and_type.css
│   │   └── global.css           # base styles, resets, @font-face declarations
│   ├── lib/
│   │   ├── db.ts                # SQLite connection & typed queries
│   │   ├── auth.ts              # session + password + invite token helpers
│   │   └── content.ts           # markdown collection helpers
│   └── env.d.ts
├── migrations/                  # numbered .sql files
├── scripts/                     # ops scripts (backup, deploy, seed)
└── public/                      # static assets served as-is
    ├── logo.svg                 # copied from design/assets/ on first session
    └── fonts/                   # copied from design/fonts/ on first session
```

## Code standards

- **TypeScript strict.** No `any` without a comment explaining why. Prefer `unknown` and narrow.
- **No runtime dependencies unless asked.** Before adding a package, justify it. The current stack is chosen for minimalism — resist padding it.
- **SQL is written by hand.** No ORM. Queries live in `src/lib/db.ts` as typed functions (`getUserByEmail(email): User | null`, etc.).
- **Zod schemas** for all content collection frontmatter, all form inputs, and all env vars. Parse at boundaries; trust internally.
- **Server-only secrets** go through `astro:env` or a server-only `env.ts` module. Never import secrets into client code — verify this.
- **Errors** in route handlers return proper status codes with minimal JSON. Never leak stack traces to clients.
- **Dates** are always UTC in the database, rendered in Europe/Copenhagen on the page.
- **Accessibility is not optional.** Every interactive element keyboard-reachable; every image has `alt`; colour contrast meets WCAG AA against tokens from `design/colors_and_type.css`.

## Design principles (from SPEC §6)

The aesthetic is **authoritative quietude** — academic, editorial, Danish-minimal. The `design/` folder is the authoritative source; `design/SKILL.md` is the entry point for how to use it. Concrete rules that hold unless the design system overrides them:

- **No visible borders** on cards or sections. Separation = tonal background shift + whitespace.
- **No drop shadows.** If elevation is needed, use a tonal shift.
- **Editorial type scale** — headlines are large, body copy has room to breathe, line-height ≥ 1.6 for body.
- **Asymmetric layouts preferred** over centred ones. Use the 12-column grid deliberately.
- **Motion is minimal.** Transitions < 200ms, ease-out. No parallax, no auto-play.
- **Light mode only** for v1.
- **All colour, font, and spacing values come from `design/colors_and_type.css`** via `src/styles/tokens.css`. Never hardcode hex values, font names, or magic spacing numbers in components — reference tokens. If a token is missing, stop and add it to `tokens.css` (faithful to the design system) before continuing.

## First-session tasks (in order)

When Claude Code first opens this project:

1. Read `SPEC.md` end to end.
2. Read `design/SKILL.md` — follow its instructions. It is the primary guide for how to use the design system.
3. Read `design/README.md`, `design/ICONOGRAPHY.md`, and `design/colors_and_type.css`. Skim `design/preview/`, `design/screenshots/`, and `design/ui_kits/` for reference.
4. Scaffold the Astro project per the file structure above. Install only what the spec requires.
5. Copy logo assets from `design/assets/` into `public/` (prefer SVG; keep filenames stable, e.g. `public/logo.svg`).
6. Copy fonts from `design/fonts/` into `public/fonts/` and set up `@font-face` declarations in `src/styles/global.css`.
7. Create `src/styles/tokens.css` derived from `design/colors_and_type.css`. Either `@import` it directly, or re-express its values as CSS custom properties — whichever `design/SKILL.md` recommends.
8. Build a `/style-guide` internal route that renders: every colour token, every type scale step, spacing scale, buttons, form inputs, cards, iconography, and the logo in context. This is for human review before any real pages are built.
9. Stop and wait for review.

Do not skip step 9. The visual language needs human approval before pages get built on top of it.

## Behavioural preferences

- **Plan before coding.** For any task larger than a trivial fix, propose a plan first and wait for approval.
- **Small, reviewable commits.** One logical change per commit. Conventional commit messages (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `style:`).
- **Ask before:** adding a dependency, changing the database schema, changing anything in `design/`, changing this file or `SPEC.md`, deploying.
- **Never:** commit secrets, commit `.env*` files, run `git push --force`, modify files inside `design/` (that folder is read-only from the code's perspective — if the design needs to change, update `design/` directly via a separate deliberate commit).
- **When uncertain about product intent**, check `SPEC.md`. If the spec is ambiguous, ask — do not guess.
- **When uncertain about visual language**, re-read `design/SKILL.md` and `design/colors_and_type.css`. If it is still ambiguous, ask.
- **When blocked by a missing decision**, write the options as a short note in `DECISIONS.md` and ask for a ruling. Do not silently pick.
- **Write state to files for long tasks.** If a task spans many steps, keep notes in `progress.md` so a fresh session can pick up.

## Out of scope

Read `SPEC.md §8`. Do not build: email sending, file uploads, rich-text editors, dark mode, mobile app, search, analytics, i18n, 2FA, public pages. If the user asks for one of these, confirm it is a scope change and suggest updating `SPEC.md` first.

## Known gotchas

- **better-sqlite3 is native.** On Hetzner ARM it must be built for ARM. The deploy script rebuilds it on the server.
- **Astro server output mode** requires an adapter — use `@astrojs/node` in `standalone` mode.
- **Signed invite tokens** are HMAC-signed, not JWTs. Keep them short and opaque.
- **Sessions are HttpOnly, Secure, SameSite=Lax cookies.** Never expose session IDs to client JS.
- **Font licensing.** The fonts in `design/fonts/` may be licensed — check `design/README.md` and `design/SKILL.md` for any usage restrictions before serving them publicly.
