# stapel-categories 0.5.3

Category tree with typed features: a hierarchical category tree (django-treenode) and a parallel feature tree whose typed config is validated by stapel-attributes, an ordered category<->feature M2M, feature inheritance, and a feature-editor lifecycle (keep/add/edit/inherit/remove/create/replace) with optimistic-concurrency apply over a category subtree.

Contract: axes 1 · extension points 4.
Generated from docs/capabilities.json by `stapel-llms-txt` — do not edit; drift-gated by `make contract-check`.

## Configuration axes — what a product switches on
Settings keys; `default` is what you get by saying nothing. Turning an axis off unmounts the operations it gates.
- DISPLAY_TRANSLATOR [enum, default "stapel_categories.translation.identity_translator"] — How category/feature names render as text
  Callable (key) -> str rendering a translation key for admin/__str__ display. The module stores translation keys, not resolved text; default is identity (conf.py, MODULE.md Extension points table).

## Extension points — what a product replaces, fork-free
- Admin config editor widgets [delegated_seam]
  The Feature.config admin widget resolves via stapel-attributes' get_config_editor_widget('config'); restyling/locales/extra assets are attributes' ADMIN_WIDGETS/ADMIN_EXTRA_CSS/ADMIN_EXTRA_JS/ADMIN_LOCALES seams (MODULE.md 'Admin UI', admin.py:16).
- DISPLAY_TRANSLATOR [dotted_path]
  REPLACE, single strategy: point it at a translation backend (e.g. a wrapper over the translate.resolve comm Function) to show resolved names instead of raw keys (conf.py, MODULE.md).
- feature_editor [function_seam]
  apply_feature_editor_changes(category, items, base_revision) is a pure function over FeatureEditorItems, separate from the HTTP layer — callable directly from a management command or host workflow (feature_editor.py, MODULE.md 'Feature-editor extension points').
- serializer_seams [class_override]
  CategoryViewSet / FeatureViewSet are DRF ModelViewSets; swap serializer_class / get_serializer_class by subclassing and remounting the router (views.py:77, views.py:482, MODULE.md 'Serializer seams').

## Fits with — fleet dependencies
- stapel-attributes (required) — the feature-type registry, config/DTO validation, polymorphic serializers and admin widgets are imported from stapel-attributes and never re-implemented (pyproject.toml dependency; admin.py:16, forms.py:14, serializers.py:11, views.py:23-24)
- stapel-core (required) — comm bus (mutate_and_emit/function), RevisionMixin, AppSettings, error registry (pyproject.toml dependency; models.py:28-29, conf.py:11, functions.py:22)
