What to build
An admin-only triage view for incoming user feedback. Lists rows from `product_feedback`, lets an admin filter by status, mark items `in-progress` / `done`, and paste a GitHub issue URL once a report has been exported to the engineering tracker.
End-to-end behavior: an admin signs in, navigates to `/admin/feedback`, sees newest `new` rows first, can change status inline and attach a `github_url`. A non-admin (editor / viewer / unauthenticated) hitting the route is rejected by `requireRole("admin")`.
Files
| File |
Change |
| `app/admin/feedback/page.tsx` (new) |
Server component. Calls `requireRole("admin")` from `lib/auth.ts`. Reads `listFeedback({ status })` from `lib/feedback-db.ts`. Renders a table grouped by status with Bug/Idea badges, route + browser context expandable, contact email shown if present. |
| `app/admin/feedback/actions.ts` (new) |
Server actions: `markFeedbackStatus(id, status)` and `attachFeedbackGithubUrl(id, url)`. Both re-check `requireRole("admin")` server-side (don't trust the page gate alone). |
| Inline UI |
Status select (`new` / `in-progress` / `done` / `wontfix`) + a small text input for GitHub URL. Native HTML + Tailwind, brand tokens, no component library. |
UX notes
- Default filter shows `new` rows; tabs/segmented control to switch to `in-progress` / `done` / `all`.
- Display the auto-captured context (route, environment, host, browser, viewport) in a collapsed `
Details
` block — not the primary read.
- `updated_at` updates automatically via the trigger / column default; the action only writes `status` or `github_url`.
Acceptance criteria
Blocked by
- #176 — needs `requireRole("admin")` from `lib/auth.ts`
- #177 — needs the `product_feedback` table and `lib/feedback-db.ts`
What to build
An admin-only triage view for incoming user feedback. Lists rows from `product_feedback`, lets an admin filter by status, mark items `in-progress` / `done`, and paste a GitHub issue URL once a report has been exported to the engineering tracker.
End-to-end behavior: an admin signs in, navigates to `/admin/feedback`, sees newest `new` rows first, can change status inline and attach a `github_url`. A non-admin (editor / viewer / unauthenticated) hitting the route is rejected by `requireRole("admin")`.
Files
UX notes
Details
` block — not the primary read.Acceptance criteria
Details
` block, not the primary readBlocked by