Commit Graph

8 Commits

Author SHA1 Message Date
mAi
b914294769 README + design doc copy
- README.md: stack, run-locally, test/check/build, structure tree, data
  model summary, anti-abuse layers, scope notes, issue origin pointer.
- docs/plans/feedback-feature.md: copied verbatim from flexsiebels for
  self-containment (single source of truth in this repo from now on).
2026-05-05 11:38:11 +02:00
mAi
699000c63d Dockerfile: oven/bun:latest, root-run (avoids alpine UID 1000 collision)
Mirrors msbls.de pattern, simplified (no mbrian-core submodule clone).

UID note: oven/bun:1-alpine has a built-in 'bun' user at UID/GID 1000 and
`addgroup -u 1000` on top of it breaks the build silently. mExDraw#14
(commit fc62b9c) lost ~4 weeks of Dokploy deploys to that. Comment in the
Dockerfile so the next person doesn't trip over the same.

Production build verified locally: vite build ✓ (4.08s).
2026-05-05 11:37:36 +02:00
mAi
f9140a414a admin pages (list + detail) + login page (Supabase email/password)
- /admin/feedback (page.server.ts + page.svelte): list with status/mode badges, counts, JSON-editor create form. flex()→fdb() rename done.
- /admin/feedback/[id] (page.server.ts + page.svelte): tabbed detail (Chat / Submissions / Edit), 5s admin polling, hide-toggle, close/reopen, CSV/JSON export, delete. flex()→fdb() rename done.
- /login: simple email + password form posting to /api/auth/sign-in. Pre-redirect if already authed (locals.userId in load). Honours ?redirect= query.

Pages otherwise byte-identical ports of the flexsiebels versions — schema
helper rename happens in /server/fdb.ts.

bun run check: 0 errors, 13 warnings (known false-positive 'data/inst captured
at init'; same pattern flexsiebels has).
2026-05-05 11:36:42 +02:00
mAi
4c68b48417 /f/[slug] participant page (no layout reset hack — whole app is naked)
Direct port from flexsiebels worktree. Imports getInstanceBySlug from
$lib/server/feedback (which uses fdb()) — schema rename happens at the
helper level, page code is identical.

Behaviour:
- LocalStorage: feedback:display_name (global) + feedback:session:<slug>
- 3s polling /posts?since=<latest_ts>; auto-scroll on new
- Hidden posts: '(Beitrag entfernt)' for others; own session sees body + note
- Honeypot 'company' input (CSS-hidden, aria-hidden)
- 423 → closed banner; 429 → rate-limit message; required-validation client+server
- noindex meta + no-referrer
- Question types: short_text, long_text, single_choice, multi_choice, scale, boolean

Root +layout.svelte already gives the naked shell (no sidebar/footer/bottom-nav)
so the +layout@.svelte reset trick is unnecessary here.

bun run check: 0 errors, 5 warnings (known false-positive 'data captured at
init' on $state — data from server load doesn't change client-side; same warning
pattern as flexsiebels).
2026-05-05 11:35:30 +02:00
mAi
946c755f17 feedback API endpoints (port from flexsiebels, fdb() schema rename)
Public (slug-gated, auto-allowlisted):
- GET  /api/public/feedback/[slug]              — instance config
- POST /api/public/feedback/[slug]/submit       — form submission (honeypot, rate-limit, required-validation, 423 if closed)
- GET  /api/public/feedback/[slug]/posts        — chat polling (?since=, hides body of moderated posts)
- POST /api/public/feedback/[slug]/posts        — new chat post (honeypot, rate-limit, 423 if closed)

Admin (requireAuth, owner-scoped):
- GET/POST   /api/admin/feedback                — list/create
- GET/PATCH/DELETE /api/admin/feedback/[id]    — detail/update/delete (PATCH closes/reopens, sets closed_at)
- POST       /api/admin/feedback/[id]/posts/[post_id]/hide — toggle hidden flag
- GET        /api/admin/feedback/[id]/export?format=csv|json — single-file dump

Auth:
- POST /api/auth/sign-in   — Supabase email+password, sets access+refresh cookies
- POST /api/auth/sign-out  — clears cookies

bun run check: 0 errors, 0 warnings.
2026-05-05 11:34:54 +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
fa1ad92517 auth + supabase + public-scope hook (mirrors flexsiebels gate, no API keys)
- src/lib/server/supabase.ts: getSupabaseAdmin/Anon (lazy singletons, env-driven URL)
- src/lib/server/fdb.ts: schema accessor for the fdbck Postgres schema
- src/lib/server/auth.ts: cookie-based JWT auth (access+refresh), Supabase getUser/refreshSession. NO API key path — fdbck has no api_keys table; if needed later, add a separate module.
- src/lib/server/request-context.ts + public-scope.ts: public-scope policy gate ported from flexsiebels#59. Allowlist /api/auth/* and /api/public/* by default.
- src/lib/server/response.ts + errors.ts: json/requireAuth + parseBody/handleApiError
- src/hooks.server.ts: validate cookies, set locals.userId, refresh tokens, run handler inside RequestState scope, evaluatePolicy after.
- src/routes/+layout.svelte: minimal naked shell (only loads feedback.css). NO sidebar/footer/bottom-nav per spec.
- src/routes/+page.svelte: brief landing page + admin-login link.
- src/lib/styles/feedback.css: copied verbatim from flexsiebels worktree.

bun run check: 0 errors, 0 warnings.
2026-05-05 11:30:13 +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