Categories¶
One tree, shared by three kinds of content. Filing something under a category is the single act that decides what it is about, who may edit it, and what it is read with.
The tree¶
question_categories is self-referential — each row has a parent_id. A row
also carries a system_id pointing at one of the 16 organ systems.
Three things are filed against it:
| Content | Column |
|---|---|
| A question | question_category_id (primary), plus any number of additional links |
| An article | category_id |
| A flashcard deck | category_id |
So one category filters all three, a grant over a branch reaches all three, and a deck generated from an article inherits the article's filing.
Primary and additional¶
A question has exactly one primary category and any number of additional ones, held as rows in a link table.
PATCH /questions/{id} takes additional_category_ids as the full
replacement set — send the list you want to end up with, not a delta.
Filtering by a set of categories expands each to all its descendants first, then matches a question by its primary category or an additional link. So the filter is OR within categories and the branch is inclusive downward.
Tag filtering, by contrast, is AND: a question must carry every tag asked for.
Reassigning¶
Both PATCH /questions/{id} and the bulk action check the destination
against assert_can_manage_category: it must be a category the caller holds.
- A moderator holds every category, so a moderator may move anything anywhere.
- A grant holder may move a question between their own branches, and is
refused —
403 You do not have an editorial grant for this category— the moment the destination falls outside them. Setting the category to "uncategorized" is refused for the same reason:Noneis not in anybody's scope.
So a grant holder cannot move a question out of their own reach, which is the thing the restriction exists for.
Curating the tree¶
/categories is the Taxonomy screen, moderator-only. Two axes: Topics
(the category tree) and Systems (the organ-system facet). Each row shows
the questions filed directly in it and the total including everything beneath.
| Act | Endpoint | Notes |
|---|---|---|
| Add | POST /question-categories/ |
Name and a parent |
| Rename, or move under a different parent | PATCH /question-categories/{id} |
A parent that would make a cycle is refused |
| Delete | DELETE /question-categories/{id}?move_to= |
See below |
Deleting asks two things first:
- Children must be moved first. "Move child categories before deleting this category."
- The questions have to go somewhere. If any question is filed there — by
primary category or by an additional link —
move_tois required. Without it: "N questions are filed here. Choose a topic to move them to before deleting this one." An empty topic goes without being asked.
Additional links follow the questions to the destination, minus any that would duplicate a pair the destination already has.
Deleting a category cascades¶
question_article_links, article_topic_claims and grants are all
ON DELETE CASCADE. Deleting a category takes the reading links, the topic
claims and anybody's grant over that branch with it. Check before you do it;
see What can be undone.
Where it is curated¶
/categories — moderator-only. It is the administrative screen for the tree
and the tag facets, not a reader-facing browse menu; the reader's category
browser is the column view inside /articles.