Cherry-pick of b49f2e0 from mai/iris/hotfix-render onto main. iris's
hotfix branched off 538419f (May 6) to avoid Phase 2, but prod was
actually already on c13d84d (Phase 2 deployed May 7-8), so deploying
her branch directly would have regressed Phase 2. Cherry-pick onto
current main resolves cleanly: package.json + +page.svelte
auto-merged; bun.lock regenerated via bun install.
Replaces the bare <p>{data.description}</p> on the participant page
with a marked + isomorphic-dompurify pipeline so admins can author
descriptions with categorized link lists. Scoped .fb-description
styles restore list bullets, give h1-h6 sensible scale below the page
title, and use the existing --color-primary / dark-mode tokens.
Both deps land in dependencies (not devDependencies) because the
render runs SSR-first.
Hotfix for the UPC Deadlines training (HL PA, 2026-05-28) — m wants a
curated Resources/Links block above the form.
Sets up the runtime split for §3.A's per-question-type modules: each type's
ParticipantInput / BuilderEditor / ResultsBlock will live in its own .svelte
file and want testable input handling. The pure logic (schema, isAnswerEmpty,
ingest, csvColumns, etc.) stays on `bun test`; the Svelte components run on
vitest.
Why two runners:
- Bun test doesn't apply the `browser` export condition when resolving ESM,
so it picks Svelte 5's `index-server.js` and @testing-library/svelte's
mount() throws lifecycle_function_unavailable.
- Vitest reuses the existing vite-plugin-svelte and applies the right
conditions natively. Run via `bun --bun vitest` so vitest itself executes
on bun (Node 18 is too old for vitest 4's node:util.styleText usage).
Files:
- New vitest.config.ts (jsdom env, svelte plugin, browser conditions, picks
up src/**/*.svelte.test.ts files only)
- New src/test-setup/vitest.ts — afterEach cleanup so consecutive render()
calls don't pollute each other's getByTestId lookups
- New src/lib/components/SmokeTest.svelte + .svelte.test.ts — sanity check
that the runner actually mounts a Svelte 5 component and reads props
- package.json scripts split: `test:server` (bun, 5 server files),
`test:components` (vitest), `test` runs both
- Pinned @sveltejs/vite-plugin-svelte to ^5.0.0 (v7 needs Node 22+ for
node:util.styleText; ours is on Node 18)
devDeps added (test-only): vitest, @testing-library/svelte,
@testing-library/jest-dom, jsdom.
54 server tests + 2 component tests pass. svelte-check + build clean.
Bootstrap from /home/m/dev/web/msbls.de template:
- SvelteKit 2.15 + Svelte 5 + adapter-node + bun + vite 6
- Deps trimmed: @supabase/supabase-js, postgres, zod (+ dev: kit, vite-plugin-svelte, svelte-check, typescript)
- No mbrian-core submodule (irrelevant for fdbck)
- src/app.html minimal (no fonts, no theme toggler)
- src/app.d.ts declares App.Locals { userId: string | null }
- robots.txt Disallow: / (whole app is naked, per-link or auth-only)
- .env.example: Supabase + PUBLIC_SITE_URL + optional COOKIE_DOMAIN
Initial mai init scaffolding (.claude, .m, .mcp.json, AGENTS.md) bundled in
this first commit since the repo was empty before bootstrap.
Spawned from m/flexsiebels.de#63 pivot — see docs/plans/feedback-feature.md
for the full spec (copied in next commit).