← Knowledge library

Clinical care

Tagging

A TagConfig defines one tag: its label, category, scope, and place in a tag tree. Tags are hierarchical labels you attach to resources — patients, encounters, charge items — to classify and filter them. You manage the definitions through…

3.1 · versioned documentation · 7 min read

A TagConfig defines one tag: its label, category, scope, and place in a tag tree. Tags are hierarchical labels you attach to resources — patients, encounters, charge items — to classify and filter them. You manage the definitions through TagConfig; the applied tags live as integer ID arrays on the tagged resources.

Two layers back the tag. The Django model (care/emr/models/tag_config.py) is storage — it holds opaque JSONFields (metadata, cached_parent_json) whose structure it never describes. The Pydantic resource specs (care/emr/resources/tag/config_spec.py) are the API and implementation layer: they pin down the enums, give those JSON fields a real shape, run field validation, and split read from write.

Source:

Models

Model Purpose
TagConfig Definition of a single tag — its display, category, scope, status, metadata, and position in the tag tree

TagConfig extends EMRBaseModel, the shared MANSOQ EMR base providing external_id, the audit fields created_by/updated_by and created_date/modified_date, soft-delete via deleted, and history/meta JSON. Applied tag IDs live on the tagged resource itself — for example Patient.instance_tags / Patient.facility_tags and Encounter.tags.

TagConfig fields

Scope

A tag is scoped to at most one owner — an instance-wide organization, a facility-scoped organization, or a facility.

Field Type Notes
facility FK → Facility PROTECT, nullable, default=None. Facility that owns the tag
facility_organization FK → FacilityOrganization CASCADE, nullable. Owning facility organization. Not allowed on instance-level (no-facility) tags
organization FK → Organization CASCADE, nullable. Owning instance-wide organization
resource CharField(255) The resource type the tag applies to. Constrained by TagResource in the write spec (see enum)

Display & classification

Field Type Notes
status CharField(255) Lifecycle status. Constrained by TagStatus in the spec — active / archived (see enum)
display CharField(255) Human-readable label. Required in the spec
description TextField Nullable, blank-able. Required key in the base spec but accepts null
category CharField(255) Grouping category. Constrained by TagCategoryChoices in the spec (see enum)
priority IntegerField default=100. Ordering weight
metadata JSONField default=None, nullable. Shape defined by TagConfigMetadata: { color: str?, icon: str? } (see nested spec)

Tree structure & caches

TagConfig is self-referential — tags form a tree, and denormalized caches are rebuilt on insert to avoid recursive joins (the same pattern as Organization). These fields are platform-maintained and never writable through the create/update specs.

Field Type Notes
parent FK → self CASCADE, nullable. related_name="children". Null parent means a root tag
root_tag_config FK → self CASCADE, nullable. related_name="root". Top of the tree, derived on save
has_children BooleanField default=False. Flipped to True on the parent when a child is created
level_cache IntegerField default=0. Depth in the tree (parent.level_cache + 1)
parent_cache ArrayField[int] default=list. Full ancestor id chain (parent.parent_cache + [parent.id])
cached_parent_json JSONField default=dict. Materialized parent record with a cache_expiry; rebuilt after cache_expiry_days (15). Shape: { id, display, description, category, parent (nested same shape), level_cache, cache_expiry }

Enums

TagCategoryChoices values

category binds to this enum in every spec (str values).

Value
diet
drug
lab
admin
contact
clinical
behavioral
research
advance_directive
safety

TagResource values

resource binds to this enum in TagConfigWriteSpec (set only on create; the read specs surface it as a plain str).

Value
encounter
activity_definition
service_request
charge_item
charge_item_definition
patient
token_booking
medication_request_prescription
supply_request_order
supply_delivery_order
account

TagStatus values

status binds to this enum in every spec (str values).

Value Meaning
active Tag is available for use
archived Tag retired; retained for historical references

Nested specs (shape of JSON fields)

TagConfigMetadata (shape of metadata)

Gives the opaque metadata JSONField a real structure. A plain Pydantic BaseModel, not an EMRResource.

Field Type Required Default Notes
color str | None no None Display color hint
icon str | None no None Display icon hint

Resource specs (API schema)

Every spec extends EMRResource (care/emr/resources/base.py), which supplies serialize (DB object → spec) and de_serialize (spec → DB object) plus the perform_extra_serialization / perform_extra_deserialization hooks. __exclude__ on the base spec keeps the FK fields (facility, facility_organization, organization, parent) out of the generic field copy so each spec can resolve them explicitly.

Spec class Role Notes
TagConfigBaseSpec shared __model__ = TagConfig; __exclude__ = [facility, facility_organization, organization, parent]. Fields: id (UUID4?), display, category (TagCategoryChoices), description (str | None), priority (int = 100), status (TagStatus), metadata (TagConfigMetadata?)
TagConfigWriteSpec write · create Base + facility?, facility_organization?, organization?, parent? (all UUID4), resource (TagResource, required). Runs two model_validator(after) checks and resolves FKs in perform_extra_deserialization
TagConfigUpdateSpec write · update Base + facility_organization?, organization? (UUID4). Cannot change facility, parent, or resource. Resolves organization/facility_organization in perform_extra_deserialization (facility organization scoped to obj.facility)
TagConfigReadSpec read · list @cacheable. Base + level_cache (int = 0), system_generated (bool), has_children (bool), parent (dict | None), resource (str), facility (dict | None). Inlines parent via get_parent_json() and a FacilityBareMinimumSpec for facility
TagConfigRetrieveSpec read · detail Extends read spec + created_by (dict), updated_by (dict), facility_organization (dict | None), organization (dict | None). Adds audit users and full org/facility-org serialization

Write-spec validation (TagConfigWriteSpec)

Two @model_validator(mode="after") checks run before deserialization:

Server-maintained behaviour

Cache invalidation

A post_save signal connects invalidate_tag_config_cache to TagConfig. Every save does three things.

  1. Invalidates the tag's own TagConfigReadSpec cache and resets cached_parent_json = {}.
  2. Invalidates all descendants (rows whose parent_cache overlaps the tag id) — they embed parent data via get_parent_json().
  3. Invalidates the parent's cache (its has_children may have changed).

Methods & save behaviour

set_tag_config_cache()

When a parent is set, recomputes parent_cache (parent.parent_cache + [parent.id]) and level_cache (parent.level_cache + 1), then derives root_tag_config from the parent — the parent itself if the parent is a root, otherwise the parent's root_tag_config. If the parent had no children, it flips parent.has_children = True, persisting only that field. Finishes with super().save().

get_parent_json()

Returns cached_parent_json when it is present and its cache_expiry is still in the future. Otherwise it recursively rebuilds the nested parent record (id = parent external_id, display, description, category, nested parent, level_cache), stamps a fresh expiry (cache_expiry_days = 15), persists cached_parent_json, and returns it. Returns {} for root tags.

save() side effects

On insert (no id yet), the base save() runs first, then set_tag_config_cache() populates the tree caches in a second write pass. On update, save() persists normally without recomputing caches. Both paths trigger the post_save cache-invalidation signal described above.

API integration notes

The REST API exposes only the definitions. Applied tags are stored as integer ID arrays on each tagged resource (e.g. Patient.instance_tags/facility_tags, Encounter.tags), not as join rows.

Each operation maps to one spec:

metadata carries display hints (color, icon) without a schema migration, shaped by TagConfigMetadata.

Related

Source evidence

References are pinned to the private MANSOQ source repository. Repository access is required to open these links.