<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FTagging</id>
	<title>References/Tagging - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FTagging"/>
	<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Tagging&amp;action=history"/>
	<updated>2026-07-06T07:10:12Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.4</generator>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/Tagging&amp;diff=474&amp;oldid=prev</id>
		<title>Admin: Add Navbox platform (via update-page on MediaWiki MCP Server)</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Tagging&amp;diff=474&amp;oldid=prev"/>
		<updated>2026-07-06T04:25:11Z</updated>

		<summary type="html">&lt;p&gt;Add Navbox platform (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 09:55, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 258:&lt;/td&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 258:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt; carries display hints (&amp;lt;code&amp;gt;color&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;icon&amp;lt;/code&amp;gt;) without a schema migration, shaped by &amp;lt;code&amp;gt;TagConfigMetadata&amp;lt;/code&amp;gt;.&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt; carries display hints (&amp;lt;code&amp;gt;color&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;icon&amp;lt;/code&amp;gt;) without a schema migration, shaped by &amp;lt;code&amp;gt;TagConfigMetadata&amp;lt;/code&amp;gt;.&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Navbox platform}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;!-- diff cache key mediawiki:diff:1.41:old-173:rev-474:wikidiff2=table:1.14.2:bc2a06be --&gt;
&lt;/table&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/Tagging&amp;diff=173&amp;oldid=prev</id>
		<title>Admin: OHC identity seed</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/Tagging&amp;diff=173&amp;oldid=prev"/>
		<updated>2026-07-04T22:45:38Z</updated>

		<summary type="html">&lt;p&gt;OHC identity seed&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Doc header&lt;br /&gt;
|type=reference&lt;br /&gt;
|domain=platform&lt;br /&gt;
|title=Tagging&lt;br /&gt;
|order=6&lt;br /&gt;
|introduced=3.0&lt;br /&gt;
|model=Tagging&lt;br /&gt;
|reference=References/Base models &amp;amp;amp; conventions&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt;; the applied tags live as integer ID arrays on the tagged resources.&lt;br /&gt;
&lt;br /&gt;
Two layers back the tag. The Django model (&amp;lt;code&amp;gt;care/emr/models/tag_config.py&amp;lt;/code&amp;gt;) is storage — it holds opaque &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt;s (&amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cached_parent_json&amp;lt;/code&amp;gt;) whose structure it never describes. The Pydantic resource specs (&amp;lt;code&amp;gt;care/emr/resources/tag/config_spec.py&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Source:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Model: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/models/tag_config.py &amp;lt;code&amp;gt;care/emr/models/tag_config.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Resource spec: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/tag/config_spec.py &amp;lt;code&amp;gt;care/emr/resources/tag/config_spec.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Cache invalidation: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/tag/cache_invalidation.py &amp;lt;code&amp;gt;care/emr/resources/tag/cache_invalidation.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
== Models ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Model&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt;&lt;br /&gt;
| Definition of a single tag — its display, category, scope, status, metadata, and position in the tag tree&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; extends [[References/Base models &amp;amp;amp; conventions|&amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;]], the shared Care EMR base providing &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;, the audit fields &amp;lt;code&amp;gt;created_by&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;updated_by&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;created_date&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;modified_date&amp;lt;/code&amp;gt;, soft-delete via &amp;lt;code&amp;gt;deleted&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;history&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; JSON. Applied tag IDs live on the tagged resource itself — for example &amp;lt;code&amp;gt;Patient.instance_tags&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Patient.facility_tags&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Encounter.tags&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; fields ==&lt;br /&gt;
&lt;br /&gt;
=== Scope ===&lt;br /&gt;
&lt;br /&gt;
A tag is scoped to at most one owner — an instance-wide organization, a facility-scoped organization, or a facility.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Tagging|section=Scope|name=facility|type=FK → Facility|notes=&amp;lt;code&amp;gt;PROTECT&amp;lt;/code&amp;gt;, nullable, &amp;lt;code&amp;gt;default=None&amp;lt;/code&amp;gt;. Facility that owns the tag}}&lt;br /&gt;
{{Field|model=Tagging|section=Scope|name=facility_organization|type=FK → FacilityOrganization|notes=&amp;lt;code&amp;gt;CASCADE&amp;lt;/code&amp;gt;, nullable. Owning facility organization. Not allowed on instance-level (no-facility) tags}}&lt;br /&gt;
{{Field|model=Tagging|section=Scope|name=organization|type=FK → Organization|notes=&amp;lt;code&amp;gt;CASCADE&amp;lt;/code&amp;gt;, nullable. Owning instance-wide organization}}&lt;br /&gt;
{{Field|model=Tagging|section=Scope|name=resource|type=CharField(255)|notes=The resource type the tag applies to. Constrained by &amp;lt;code&amp;gt;TagResource&amp;lt;/code&amp;gt; in the write spec (see [[#tagresource-values}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Display &amp;amp;amp; classification ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=status|type=CharField(255)|notes=Lifecycle status. Constrained by &amp;lt;code&amp;gt;TagStatus&amp;lt;/code&amp;gt; in the spec — &amp;lt;code&amp;gt;active&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;archived&amp;lt;/code&amp;gt; (see [[#tagstatus-values}}&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=display|type=CharField(255)|notes=Human-readable label. Required in the spec}}&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=description|type=TextField|notes=Nullable, blank-able. Required key in the base spec but accepts &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;}}&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=category|type=CharField(255)|notes=Grouping category. Constrained by &amp;lt;code&amp;gt;TagCategoryChoices&amp;lt;/code&amp;gt; in the spec (see [[#tagcategorychoices-values}}&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=priority|type=IntegerField|notes=&amp;lt;code&amp;gt;default=100&amp;lt;/code&amp;gt;. Ordering weight}}&lt;br /&gt;
{{Field|model=Tagging|section=Display &amp;amp;amp; classification|name=metadata|type=JSONField|notes=&amp;lt;code&amp;gt;default=None&amp;lt;/code&amp;gt;, nullable. Shape defined by &amp;lt;code&amp;gt;TagConfigMetadata&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;{ color: str?, icon: str? }&amp;lt;/code&amp;gt; (see [[#tagconfigmetadata-shape-of-metadata}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tree structure &amp;amp;amp; caches ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; is self-referential — tags form a tree, and denormalized caches are rebuilt on insert to avoid recursive joins (the same pattern as [[References/Organization|&amp;lt;code&amp;gt;Organization&amp;lt;/code&amp;gt;]]). These fields are platform-maintained and never writable through the create/update specs.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=parent|type=FK → self|notes=&amp;lt;code&amp;gt;CASCADE&amp;lt;/code&amp;gt;, nullable. &amp;lt;code&amp;gt;related_name=&amp;amp;quot;children&amp;amp;quot;&amp;lt;/code&amp;gt;. Null parent means a root tag}}&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=root_tag_config|type=FK → self|notes=&amp;lt;code&amp;gt;CASCADE&amp;lt;/code&amp;gt;, nullable. &amp;lt;code&amp;gt;related_name=&amp;amp;quot;root&amp;amp;quot;&amp;lt;/code&amp;gt;. Top of the tree, derived on save}}&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=has_children|type=BooleanField|notes=&amp;lt;code&amp;gt;default=False&amp;lt;/code&amp;gt;. Flipped to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; on the parent when a child is created}}&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=level_cache|type=IntegerField|notes=&amp;lt;code&amp;gt;default=0&amp;lt;/code&amp;gt;. Depth in the tree (&amp;lt;code&amp;gt;parent.level_cache + 1&amp;lt;/code&amp;gt;)}}&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=parent_cache|type=ArrayField[int]|notes=&amp;lt;code&amp;gt;default=list&amp;lt;/code&amp;gt;. Full ancestor id chain (&amp;lt;code&amp;gt;parent.parent_cache + [parent.id]&amp;lt;/code&amp;gt;)}}&lt;br /&gt;
{{Field|model=Tagging|section=Tree structure &amp;amp;amp; caches|name=cached_parent_json|type=JSONField|notes=&amp;lt;code&amp;gt;default=dict&amp;lt;/code&amp;gt;. Materialized parent record with a &amp;lt;code&amp;gt;cache_expiry&amp;lt;/code&amp;gt;; rebuilt after &amp;lt;code&amp;gt;cache_expiry_days&amp;lt;/code&amp;gt; (15). Shape: &amp;lt;code&amp;gt;{ id, display, description, category, parent (nested same shape), level_cache, cache_expiry }&amp;lt;/code&amp;gt;}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Enums ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;TagCategoryChoices&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt; binds to this enum in every spec (&amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt; values).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;diet&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;drug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;lab&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;contact&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;clinical&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;behavioral&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;research&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;advance_directive&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;safety&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;TagResource&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt; binds to this enum in &amp;lt;code&amp;gt;TagConfigWriteSpec&amp;lt;/code&amp;gt; (set only on create; the read specs surface it as a plain &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;encounter&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;activity_definition&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;service_request&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;charge_item&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;charge_item_definition&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;patient&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;token_booking&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;medication_request_prescription&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;supply_request_order&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;supply_delivery_order&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;account&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;TagStatus&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; binds to this enum in every spec (&amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt; values).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;active&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tag is available for use&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;archived&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tag retired; retained for historical references&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Nested specs (shape of JSON fields) ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;TagConfigMetadata&amp;lt;/code&amp;gt; (shape of &amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
Gives the opaque &amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt; a real structure. A plain Pydantic &amp;lt;code&amp;gt;BaseModel&amp;lt;/code&amp;gt;, not an &amp;lt;code&amp;gt;EMRResource&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Default&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=Tagging|section=TagConfigMetadata (shape of metadata)|name=color|type=str | None|notes=no}}&lt;br /&gt;
{{Field|model=Tagging|section=TagConfigMetadata (shape of metadata)|name=icon|type=str | None|notes=no}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Resource specs (API schema) ==&lt;br /&gt;
&lt;br /&gt;
Every spec extends &amp;lt;code&amp;gt;EMRResource&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;care/emr/resources/base.py&amp;lt;/code&amp;gt;), which supplies &amp;lt;code&amp;gt;serialize&amp;lt;/code&amp;gt; (DB object → spec) and &amp;lt;code&amp;gt;de_serialize&amp;lt;/code&amp;gt; (spec → DB object) plus the &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; hooks. &amp;lt;code&amp;gt;__exclude__&amp;lt;/code&amp;gt; on the base spec keeps the FK fields (&amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;) out of the generic field copy so each spec can resolve them explicitly.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Spec class&lt;br /&gt;
! Role&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfigBaseSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| shared&lt;br /&gt;
| &amp;lt;code&amp;gt;__model__ = TagConfig&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;__exclude__ = [facility, facility_organization, organization, parent]&amp;lt;/code&amp;gt;. Fields: &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;UUID4?&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;display&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TagCategoryChoices&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;str | None&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;int = 100&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TagStatus&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TagConfigMetadata?&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfigWriteSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · create&lt;br /&gt;
| Base + &amp;lt;code&amp;gt;facility?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;facility_organization?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;organization?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parent?&amp;lt;/code&amp;gt; (all &amp;lt;code&amp;gt;UUID4&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TagResource&amp;lt;/code&amp;gt;, required). Runs two &amp;lt;code&amp;gt;model_validator(after)&amp;lt;/code&amp;gt; checks and resolves FKs in &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfigUpdateSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · update&lt;br /&gt;
| Base + &amp;lt;code&amp;gt;facility_organization?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;organization?&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;UUID4&amp;lt;/code&amp;gt;). Cannot change &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt;. Resolves &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; (facility organization scoped to &amp;lt;code&amp;gt;obj.facility&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfigReadSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| read · list&lt;br /&gt;
| &amp;lt;code&amp;gt;@cacheable&amp;lt;/code&amp;gt;. Base + &amp;lt;code&amp;gt;level_cache&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;int = 0&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;system_generated&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;has_children&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;). Inlines parent via &amp;lt;code&amp;gt;get_parent_json()&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;FacilityBareMinimumSpec&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TagConfigRetrieveSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| read · detail&lt;br /&gt;
| Extends read spec + &amp;lt;code&amp;gt;created_by&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;updated_by&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;). Adds audit users and full org/facility-org serialization&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Write-spec validation (&amp;lt;code&amp;gt;TagConfigWriteSpec&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
Two &amp;lt;code&amp;gt;@model_validator(mode=&amp;amp;quot;after&amp;amp;quot;)&amp;lt;/code&amp;gt; checks run before deserialization:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;validate_exists&amp;lt;/code&amp;gt;:&lt;br /&gt;
** If &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; is set, it must exist; if &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; is also set it must belong to that facility, else &amp;lt;code&amp;gt;ValidationError(&amp;amp;quot;Facility Organization not found&amp;amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
** If &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt; is set, it must exist, else &amp;lt;code&amp;gt;ValidationError(&amp;amp;quot;Organization not found&amp;amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
** If &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; is set, a &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; with that &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt; &amp;#039;&amp;#039;&amp;#039;and the same &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; must exist (and, when &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; is set, belong to that facility), else &amp;lt;code&amp;gt;ValueError(&amp;amp;quot;Parent tag config not found&amp;amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;validate_organizations&amp;lt;/code&amp;gt;: a &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; without a &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; is rejected — &amp;lt;code&amp;gt;ValueError(&amp;amp;quot;Facility Organization not allowed in instance level tag configs&amp;amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Server-maintained behaviour ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;TagConfigWriteSpec.perform_extra_deserialization&amp;lt;/code&amp;gt; resolves &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; (plus &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; scoped to the resolved facility) from their &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;s onto the model instance; &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; is explicitly set to &amp;lt;code&amp;gt;None&amp;lt;/code&amp;gt; when absent.&lt;br /&gt;
* &amp;lt;code&amp;gt;TagConfigReadSpec.perform_extra_serialization&amp;lt;/code&amp;gt; sets &amp;lt;code&amp;gt;id = external_id&amp;lt;/code&amp;gt;, inlines the parent record via &amp;lt;code&amp;gt;obj.get_parent_json()&amp;lt;/code&amp;gt; (only when non-empty), and serializes &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FacilityBareMinimumSpec&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;{ id, name }&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;TagConfigRetrieveSpec.perform_extra_serialization&amp;lt;/code&amp;gt; calls the read-spec hook, then &amp;lt;code&amp;gt;serialize_audit_users&amp;lt;/code&amp;gt; (populates &amp;lt;code&amp;gt;created_by&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;updated_by&amp;lt;/code&amp;gt; from cache) and serializes &amp;lt;code&amp;gt;facility_organization&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;organization&amp;lt;/code&amp;gt; with their full read specs.&lt;br /&gt;
* Tree caches (&amp;lt;code&amp;gt;level_cache&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parent_cache&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;root_tag_config&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;has_children&amp;lt;/code&amp;gt;) are populated by the model&amp;#039;s &amp;lt;code&amp;gt;set_tag_config_cache()&amp;lt;/code&amp;gt; on insert — never accepted from clients.&lt;br /&gt;
* &amp;lt;code&amp;gt;system_generated&amp;lt;/code&amp;gt; is declared on &amp;lt;code&amp;gt;TagConfigReadSpec&amp;lt;/code&amp;gt; but is not a field on the current &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt; model (nor on &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;). The generic &amp;lt;code&amp;gt;serialize&amp;lt;/code&amp;gt; only copies model fields, so it is not populated from storage unless something else provides it. Treat it as a read-only flag and verify against the live model before relying on it.&lt;br /&gt;
&lt;br /&gt;
=== Cache invalidation ===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;post_save&amp;lt;/code&amp;gt; signal connects &amp;lt;code&amp;gt;invalidate_tag_config_cache&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;TagConfig&amp;lt;/code&amp;gt;. Every save does three things.&lt;br /&gt;
&lt;br /&gt;
# Invalidates the tag&amp;#039;s own &amp;lt;code&amp;gt;TagConfigReadSpec&amp;lt;/code&amp;gt; cache and resets &amp;lt;code&amp;gt;cached_parent_json = {}&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Invalidates all descendants (rows whose &amp;lt;code&amp;gt;parent_cache&amp;lt;/code&amp;gt; overlaps the tag id) — they embed parent data via &amp;lt;code&amp;gt;get_parent_json()&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Invalidates the parent&amp;#039;s cache (its &amp;lt;code&amp;gt;has_children&amp;lt;/code&amp;gt; may have changed).&lt;br /&gt;
&lt;br /&gt;
== Methods &amp;amp;amp; save behaviour ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;set_tag_config_cache()&amp;lt;/code&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
When a &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; is set, recomputes &amp;lt;code&amp;gt;parent_cache&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;parent.parent_cache + [parent.id]&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;level_cache&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;parent.level_cache + 1&amp;lt;/code&amp;gt;), then derives &amp;lt;code&amp;gt;root_tag_config&amp;lt;/code&amp;gt; from the parent — the parent itself if the parent is a root, otherwise the parent&amp;#039;s &amp;lt;code&amp;gt;root_tag_config&amp;lt;/code&amp;gt;. If the parent had no children, it flips &amp;lt;code&amp;gt;parent.has_children = True&amp;lt;/code&amp;gt;, persisting only that field. Finishes with &amp;lt;code&amp;gt;super().save()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;get_parent_json()&amp;lt;/code&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Returns &amp;lt;code&amp;gt;cached_parent_json&amp;lt;/code&amp;gt; when it is present and its &amp;lt;code&amp;gt;cache_expiry&amp;lt;/code&amp;gt; is still in the future. Otherwise it recursively rebuilds the nested parent record (&amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; = parent &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;display&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt;, nested &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;level_cache&amp;lt;/code&amp;gt;), stamps a fresh expiry (&amp;lt;code&amp;gt;cache_expiry_days = 15&amp;lt;/code&amp;gt;), persists &amp;lt;code&amp;gt;cached_parent_json&amp;lt;/code&amp;gt;, and returns it. Returns &amp;lt;code&amp;gt;{}&amp;lt;/code&amp;gt; for root tags.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;save()&amp;lt;/code&amp;gt; side effects ===&lt;br /&gt;
&lt;br /&gt;
On insert (no &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; yet), the base &amp;lt;code&amp;gt;save()&amp;lt;/code&amp;gt; runs first, then &amp;lt;code&amp;gt;set_tag_config_cache()&amp;lt;/code&amp;gt; populates the tree caches in a second write pass. On update, &amp;lt;code&amp;gt;save()&amp;lt;/code&amp;gt; persists normally without recomputing caches. Both paths trigger the &amp;lt;code&amp;gt;post_save&amp;lt;/code&amp;gt; cache-invalidation signal described above.&lt;br /&gt;
&lt;br /&gt;
== API integration notes ==&lt;br /&gt;
&lt;br /&gt;
The REST API exposes only the definitions. Applied tags are stored as integer ID arrays on each tagged resource (e.g. &amp;lt;code&amp;gt;Patient.instance_tags&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;facility_tags&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Encounter.tags&amp;lt;/code&amp;gt;), not as join rows.&lt;br /&gt;
&lt;br /&gt;
Each operation maps to one spec:&lt;br /&gt;
&lt;br /&gt;
* Create — &amp;lt;code&amp;gt;TagConfigWriteSpec&amp;lt;/code&amp;gt;. Sets &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt;, the scope FKs, and &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt; must match a [[#tagresource-values|&amp;lt;code&amp;gt;TagResource&amp;lt;/code&amp;gt;]] value.&lt;br /&gt;
* Update — &amp;lt;code&amp;gt;TagConfigUpdateSpec&amp;lt;/code&amp;gt;. Reassigns org/facility-org only, plus the shared display/category/status/metadata fields; &amp;lt;code&amp;gt;facility&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;resource&amp;lt;/code&amp;gt; are fixed.&lt;br /&gt;
* List — &amp;lt;code&amp;gt;TagConfigReadSpec&amp;lt;/code&amp;gt;. Detail — &amp;lt;code&amp;gt;TagConfigRetrieveSpec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;metadata&amp;lt;/code&amp;gt; carries display hints (&amp;lt;code&amp;gt;color&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;icon&amp;lt;/code&amp;gt;) without a schema migration, shaped by &amp;lt;code&amp;gt;TagConfigMetadata&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Related}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>