During beta and early access, direct user feedback is critical for prioritisation. This feature provides a lightweight, always-accessible feedback drawer that lets users report bugs, request features, or ask questions without leaving the app. It requires no account and adds zero friction.
width: 380px) containing a free-text textarea and a submit button.message, the current url (window.location.href), and the userAgent (truncated to 200 chars server-side).API: POST /api/feedback
{ message, category, url, userAgent }.bug, feature, question, other. Category is required and validated server-side (note: the drawer currently sends without a category — this is a mismatch to resolve).429 with Retry-After header when exceeded.feedback.log in the app root (fire-and-forget, non-fatal if the write fails).console.log('[feedback]', ...) for server-side visibility in logs.{ ok: true } with X-RateLimit-Remaining header on success.--color-jesus-words) + success text.Component: apps/web/src/lib/components/layout/FeedbackDrawer.svelte
open: boolean, onclose: () => voidDrawer component with variant="right".feedback.title, feedback.message_placeholder, feedback.submit, feedback.success, feedback.error.API Route: apps/web/src/routes/api/feedback/+server.ts
$lib/server/rate-limit.js — in-memory rate limiter.join(process.cwd(), 'feedback.log') — flat newline-delimited JSON file.category field is validated against ['bug', 'feature', 'question', 'other'] but the drawer currently does not send one. This will cause a 400 error until the drawer is updated to include a category selector or the server-side requirement is relaxed.Implemented, but there is a known mismatch: the drawer POSTs without a category field, while the API requires it. Either add a category selector to the drawer or make the field optional server-side before this feature is fully functional end-to-end.