4 Commits

Author SHA1 Message Date
mAi
288dfb31e8 feat(f/[slug]): render description as sanitized markdown
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.
2026-05-27 21:09:10 +02:00
mAi
a0765c9bf7 test: vitest + jsdom for Svelte component tests
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.
2026-05-07 20:04:10 +02:00
mAi
f5992ebc5b schemas + rate-limit + feedback helpers + tests
- src/lib/server/schemas.ts: feedback Zod schemas (Question discriminated union + FormDefinition + Instance create/update + Submission/Post/Hide + SignIn).
- src/lib/server/rate-limit.ts (+ test): in-memory token bucket — direct port from flexsiebels.
- src/lib/server/feedback.ts: generateSlug (32-char base62), getInstanceBySlug/ById via fdb(), RATE_LIMIT constants, clampUserAgent.
- src/lib/server/public-scope.test.ts: gate behaviour tests (allowlist coverage + 6 evaluatePolicy cases). Adapted for fdbck's allowlist (no /api/share, no /api/gotify-public).
- @types/bun added so svelte-check resolves bun:test imports — clean baseline (no 'Cannot find bun:test' tech debt that the flexsiebels project carries).

bun run check: 0 errors, 0 warnings.
bun run test: 20/20 pass.
2026-05-05 11:32:23 +02:00
mAi
ae2984088a skeleton: SvelteKit fullstack app (msbls.de pattern, fdbck variant)
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).
2026-05-05 11:27:59 +02:00