Ideas (Admin)
The Ideas section of the admin panel provides moderation tools for the Ideas Hub. Admins can review all submitted ideas, change their status, edit content, moderate comments, and manage the categories and tags that users see when submitting ideas.
Where to Find It
Admin sidebar → Hub → Ideas, which is a sub-group with three entries:
| Entry | Route | Sidebar gate |
|---|---|---|
| Ideas | /hub/ideas | ideas:moderate_read |
| Categories | /hub/ideas/categories | ideas:moderate_edit |
| Tags | /hub/ideas/tags | ideas:moderate_edit |
Idea detail pages live at /hub/ideas/\{id\}. Categories and tags are their own routes, not toolbar buttons on the Ideas list.
Ideas List
The list view at /hub/ideas shows all ideas across every status.
Columns
| Column | Description |
|---|---|
| (checkbox) | Row selection, plus a select-all checkbox in the header |
| Title | Idea title, with a coloured category chip underneath when the idea has a category. Clicking it opens the detail page. |
| Author | User's display name, or — |
| Status | Inline status dropdown for admins with ideas:moderate_edit; a coloured badge otherwise |
| Votes | Up-vote and down-vote counts side by side |
| Comments | Total comment count |
| Created | Creation date |
| Actions | View, plus a delete (trash) button for admins with ideas:moderate_edit |
Category is not its own column — it appears as a chip under the title.
Statuses
Ideas move through six statuses: open, planned, in_progress, testing, completed, closed. The server validates against exactly that allowlist.
Filtering
The toolbar exposes:
- Search — a search box matching on title and description; typing resets to page 1.
- Status — a pill bar with
Allplus each of the six statuses.
There is no category filter. Filter state lives in React state and is not reflected in the URL.
Bulk Actions
Selecting rows reveals a bulk-action bar. Both bulk operations sit behind a single ideas:moderate_edit gate in the UI:
| Action | UI gate | Server gate |
|---|---|---|
| Change status | ideas:moderate_edit | ideas:moderate_status |
| Delete selected | ideas:moderate_edit | ideas:moderate_delete |
Bulk status change is a target-status dropdown plus Apply; it fans out one status PATCH per selected idea. There is no accompanying-message field. Bulk delete raises a confirmation dialog naming the number of selected ideas.
Idea Detail
The detail page at /hub/ideas/\{id\} provides a full view of a single idea and all associated data.
Sections
Idea Content
Displays the title, description, category, tags, vote totals, and comment count. Admins with ideas:moderate_edit get an Edit button that swaps the card for a single form covering title, description, category, status, and tags at once — there is no separate status modal, and no field for a status-change message. A Delete button sits next to Edit, behind a confirmation dialog.
Status changes issue PATCH /v1/ideas/\{id\}/status, which requires ideas:moderate_status server-side even though the button is gated on ideas:moderate_edit in the UI.
Timeline
A chronological list of timeline entries for the idea — status transitions, title/description/category/tag changes. It shows the five most recent entries with a Load more control for the rest. Timeline entries are read-only and cannot be removed.
Comments
The comment list for the idea. Each comment shows the author, the body, and a timestamp, with a delete action gated on ideas:moderate_edit in the UI and ideas:moderate_comment (or ideas:comment_delete for one's own comment) server-side. Deletion goes through DELETE /v1/ideas/comments/\{id\}.
Vote counts are derived from the idea_votes table; there is no manual override.
Category Management
A dedicated page at /hub/ideas/categories, reached from the sidebar (Hub → Ideas → Categories). The sidebar entry and the page are gated on ideas:moderate_edit; the API enforces ideas:edit for create/update and ideas:delete for delete.
Category List
A table with Color, Label, Name (slug), Sort Order, and Actions. Rows are edited in place.
Creating a Category
Click Add Category to open an inline row form:
| Field | Description |
|---|---|
| Label | Display label shown to users (placeholder: "e.g. Feature Request") |
| Name | Machine-readable slug (placeholder: "e.g. feature_request") |
| Color | Colour used for the category chip in the UI |
| Sort Order | Integer; lower sorts first |
There is no description field.
Editing a Category
Click the edit action on a row; the label, name, colour, and sort order become editable in place.
Deleting a Category
Deleting raises a confirmation dialog carrying the warning "Categories with existing ideas cannot be deleted. Reassign the ideas first." The database enforces this with ON DELETE RESTRICT on the category_id FK, and a failed delete surfaces the error "Failed to delete. The category may still have ideas assigned."
Tag Management
A dedicated page at /hub/ideas/tags (Hub → Ideas → Tags), gated on ideas:moderate_edit in the sidebar and page. The API enforces ideas:create for creating a tag and ideas:delete for removing one.
Tag List
A search box, a "Tag name…" input with an Add Tag button, and a paginated list of tags. Each row shows the tag name and a delete (trash) button. Usage counts are not shown.
Creating a Tag
Type a name into the input next to the search box and click Add Tag. Tags are also created by users inline when submitting an idea.
Deleting a Tag
Click the trash button on any tag row. A confirmation dialog ("Are you sure you want to delete the tag …?") is shown first. Deleting removes the tag and its idea_tag_assignments join rows; the ideas themselves are not affected.
There is no rename flow — delete and recreate.
Permissions
All Ideas admin actions require admin:access (the dashboard-entry gate). In addition:
| Action | UI gate | Server gate |
|---|---|---|
| Open the ideas list and detail pages | ideas:moderate_read | — (the list and detail queries are open to any authenticated user) |
| Change idea status | ideas:moderate_edit | ideas:moderate_status |
| Edit any idea's content | ideas:moderate_edit | ideas:moderate_edit (or ideas:edit for one's own idea) |
| Delete any idea | ideas:moderate_edit | ideas:moderate_delete (or ideas:delete for one's own idea) |
| Delete any comment | ideas:moderate_edit | ideas:moderate_comment (or ideas:comment_delete for one's own comment) |
| Open the categories / tags pages | ideas:moderate_edit | — |
| Create / update a category, create a tag | ideas:moderate_edit | ideas:edit (categories), ideas:create (tags) |
| Delete a category or tag | ideas:moderate_edit | ideas:delete |
ideas:moderate_read is a UI-only gate: it controls the sidebar entry and the admin pages, not the underlying read queries.
Category and tag mutations are guarded by the admin-scope ideas:edit / ideas:create / ideas:delete permissions, not by ideas:moderate_* — grant both to a moderator who should manage taxonomy.
System admins (is_system = true) implicitly have all permissions.
API
| UI Action | GraphQL | REST |
|---|---|---|
| List ideas | ideas(filter, sort, limit, offset) | GET /v1/ideas |
| Get idea detail | idea(id: UUID!) | GET /v1/ideas/\{id\} |
| Edit idea content | updateIdea(id, input) | PATCH /v1/ideas/\{id\} |
| Change status | updateIdeaStatus(id, status) | PATCH /v1/ideas/\{id\}/status |
| Delete idea | deleteIdea(id: UUID!) | DELETE /v1/ideas/\{id\} |
| List comments | ideaComments(ideaId) | GET /v1/ideas/\{id\}/comments |
| Delete comment | deleteIdeaComment(id: UUID!) | DELETE /v1/ideas/comments/\{id\} |
| Timeline | ideaTimeline(ideaId) | — |
| List categories | ideaCategories | GET /v1/ideas/categories |
| Create category | createIdeaCategory(input: CreateIdeaCategoryInput!) | POST /v1/ideas/categories |
| Update category | updateIdeaCategory(id: UUID!, input: UpdateIdeaCategoryInput!) | PATCH /v1/ideas/categories/\{id\} |
| Delete category | deleteIdeaCategory(id: UUID!) | DELETE /v1/ideas/categories/\{id\} |
| List tags | ideaTags | GET /v1/ideas/tags |
| Create tag | createIdeaTag(name) | POST /v1/ideas/tags |
| Delete tag | deleteIdeaTag(id: UUID!) | DELETE /v1/ideas/tags/\{id\} |
There is no /v1/ideas/admin/* route prefix — admin and end-user operations share the same paths and are separated by permission checks. The admin app reaches them through its own /api/ideas/* proxy routes.
There is no pin feature: no pin control in the admin UI, no pinIdea mutation, and no pin endpoint.
Related
- Feature Flags — the
system:ideas_hubandsystem:ideas_hub_publickill-switches, which every ideas endpoint checks before doing anything - Ideas Hub feature doc — architecture, data model, WebSocket channels
- Ideas Hub user guide — user-facing functionality