Taxonomy
A vocabulary is a list of terms; a term is a thing content can be filed under. Categories, tags, statuses, manufacturers, material grades — anything you would otherwise be tempted to hard-code as a dropdown.
No hard-coded lists, anywhere
This is a rule of the platform, not a style preference. Every list a user might reasonably want to change is a vocabulary, seeded with sensible defaults and yours to edit. If you find a list you cannot edit, that is a bug worth reporting.
Vocabularies are bundles
A vocabulary behaves like a content type: terms have fields, displays, revisions and translations. A manufacturer term can carry a logo, a country and a website; a category can carry a hero image and an intro.
That is why a term is not merely a label — it is a record with an address of its own.
Hierarchy
Terms nest. A child term inherits its place in the tree, and a listing filtered by a parent can be told to include children — which is what makes "everything under Inverters" a single filter rather than a list of six.
Terms have pages
A term is reachable at its own address, and that page is a legitimate destination: a category page with its own text, image and a listing of what belongs to it.
The address comes from the platform, not from you
Never assemble a term URL by hand in a template or a token. Ask for the canonical address; an alias, a per-type rule and the plain form all resolve through it. Hand-built URLs are how a working link quietly starts pointing at the wrong kind of page.
Groups
Vocabularies can carry a group — a label that says which agenda they belong to. With thirty vocabularies in a mature installation, the group is the difference between a list you can read and a list you search.
Per organization
Vocabularies and terms belong to an organization. Two firms may each have a vocabulary called "Categories" with entirely different contents, and neither sees the other.
Including the history. Every vocabulary page lists who changed what and when, and that list belongs to the firm as much as the terms do — the name alone does not say whose a change was once two firms share it.
Vocabularies that belong to nobody
Installations that grew before this rule carry vocabularies with no owner. They still work — a firm without its own falls back to them — but that fallback is exactly what stops a firm from having its own copy, so they are worth adopting:
python manage.py taxonomy_adopt_vocabularies # report only
python manage.py taxonomy_adopt_vocabularies --apply
python manage.py taxonomy_adopt_vocabularies --apply --claim <firm>
Whose a vocabulary is comes from the fields that point at it, not from the organization stamped on its terms: the stamp records where a row was written, which is often whichever firm the person had open at the time. Its terms follow it, and the permissions are renamed in place so every grant stays attached.
--claim names the firm that takes the vocabularies nothing uses yet.
A vocabulary that several firms use is reported and left alone: it needs
a copy per firm with every reference remapped, and that is a decision rather
than something a command should guess.
Installations that were running before 2026-08-18 carry history rows written before the platform recorded the firm. They are still shown wherever the name belongs to exactly one vocabulary. To give the rest their owner:
python manage.py taxonomy_stamp_change_records # report, writes nothing
python manage.py taxonomy_stamp_change_records --apply
Where two firms hold the same vocabulary name, those old rows are left without an owner and reported rather than guessed at — being handed somebody else's history is worse than having none.
System vocabularies
Some lists are nobody's because they are everybody's: the countries of the world, the regions and districts of a country, its municipalities and postal codes. The platform ships them as system vocabularies — declared by the module that owns their meaning (the geo lists come from Maps), created on every installation when missing, standing on the System shelf of the vocabularies directory.
They behave like the shipped listings: no firm can delete, rename or claim one, a firm's configuration export leaves them out, and a re-sync only adds and corrects — it never removes a term a record may point at.
Readable everywhere, public nowhere. A firm places a system term the way it places any term — a "District" field on a branch, a listing filtered by region, a map of municipalities — and those surfaces show it. But a system term never has a page of its own, never appears in a sitemap, a search index or a feed. The lists are reference data, not content.
Large vocabularies
A vocabulary above a threshold (a thousand terms by default) is no longer drawn as one tree: the terms page becomes a searchable, paged list, and a reference field over it is a search box that offers matches as you type rather than a select of every term. Small vocabularies are untouched.
One picker, never rows
A reference field that holds several values is one tag picker: chosen terms sit as removable tags, typing adds another. The platform never renders a multi-value field as a stack of rows.
The geo lists
Five system vocabularies, every term carrying its whole chain upwards:
| Vocabulary | Term | Carries |
|---|---|---|
| Countries | one per ISO country | code, centre |
| Regions | e.g. Košický kraj | code, point, its country |
| Districts | e.g. Okres Trebišov | code, point, its region and country |
| Municipalities | e.g. Trebišov | code, point, its district, region and country |
| Postal codes | e.g. 075 01 Trebišov | code, point, its municipality, district, region and country |
The chain is flat on purpose: a list of municipalities filtered by region is a plain field filter, a map of one district needs no hop, and a postal code knows its country without a lookup. Regions and districts carry the country's own names (Trenčiansky kraj, not "Trenčín Region").
They are filled from open data — GeoNames and Google's canonical country list, both CC BY 4.0 — by an operator command, one country at a time:
python manage.py tenant_command geo_sync --schema=<schema> --countries
python manage.py tenant_command geo_sync --schema=<schema> --country SK
python manage.py tenant_command geo_sync --schema=<schema> --country SK --offline
Downloads are cached; --offline reads the cache only and names what is
missing. Re-running is safe at any time. Every run leaves one entry in the
activity trail with its counts.
Claudia answers the same questions through the maps_geo_lookup tool: a
place by its code with the chain up to its country and the places one level
down, a name search inside a country, or the nearest municipality or post
code to a position — the question a vehicle's coordinates ask. What she
sees is what the map shows.
Translations
Term names are translated like everything else. A visitor reading in Slovak sees Slovak category names — in listings, in reference fields, in breadcrumbs and on the term's own page.
If a label appears in the wrong language
That is a bug, not a setting. Every public rendering of a term goes through the same translation lookup; one that does not is a defect and should be reported.