id: TEDY.02
template: tool-feature
module: tedy
state: Proposed
traces-from: [] # TODO: link terminology-editor user stories
source-refs:
reference-editor/app/src/app/resources/value-set
reference-editor/app/src/app/resources/_lib/value-set/model/value-set.ts
reference-editor/app/src/app/resources/_lib/value-set/model/value-set-version.ts
reference-editor/app/src/app/resources/_lib/value-set/model/value-set-version-rule.ts
reference-editor/app/src/app/resources/_lib/value-set/model/value-set-version-rule-set.ts
reference-editor/app/src/app/resources/_lib/value-set/model/value-set-version-concept.ts
reference-editor/app/src/app/resources/_lib/value-set/services/value-set-lib.service.ts # GET /ts/value-sets*
reference-editor/app/src/app/resources/value-set/services/value-set.service.ts # write /ts/value-sets*
reference-editor/app/src/app/fhir/_lib/value-set/services/fhir-value-set-lib.service.ts # /fhir/ValueSet*
terminology-server (/ts/value-sets, /ts/value-set-versions, /fhir/ValueSet, /file-importer/value-set)
author: TEDY bootstrap
created: 2026-08-08
updated: 2026-08-08
Common specification for Value Set management in TEDY — browse, view, and author FHIR ValueSets over terminology-server (/ts/value-sets). Unlike a Code System (which owns its concepts), a Value Set selects concepts from one or more code systems (or other value sets) through compose rules ; those rules are expanded into the concrete member list (and materialized as a snapshot ). This root spec owns the shared vocabulary, data model, compose/expansion model, FHIR mapping, privileges, the full API surface, and navigation so the child (screen) specs don’t duplicate them.
terminology-server owns persistence + the FHIR + expansion engine; TEDY is the React client. Derived via spec-authoring.md (Step-1 dev-tx.example scan, Step-2 reference-editor + terminology-server reconcile). The complete REST surface below was read from reference-editor’s value-set services and confirmed live on dev-tx.example (guest yupi).
Child specs:
Term (canonical) Meaning
Value Set A FHIR ValueSet — a curated selection of concepts drawn from code systems / other value sets.
Version A ValueSetVersion with a publication status (draft/active/retired) + release date; carries the rule set .
Rule set ValueSetVersion.ruleSet — the container of compose rules for that version (lockedDate, inactive, rules[]).
Compose rule ValueSetVersionRule — one include/exclude entry referencing a code system (or another value set), optionally narrowed by explicit concepts, filters, and properties.
Filter ValueSetRuleFilter — {property, operator, value} on a rule (e.g. is-a, descendent-of); operators per FHIR filter-operator.
Expansion The concrete member list produced by evaluating the rule set (POST /ts/value-sets/expand).
Snapshot ValueSetSnapshot — a stored, materialized expansion for a version (conceptsTotal, expansion[]).
Member (concept) ValueSetVersionConcept — an expanded member: concept (code + system) + display + additionalDesignations + orderNumber + active.
Designation A member’s localized display; display is the chosen one, additionalDesignations the rest.
Publisher ValueSet.publisher — resolved via the publisher value set when a code, else free text.
flowchart LR
US["(TODO) US: manage value sets"] --> ROOT[TEDY.02]
ROOT --> LST[TEDY.02.1 List]
ROOT --> CRT[TEDY.02.2 Add]
ROOT --> VIEW[TEDY.02.3 View]
LST -->|Add value set| CRT
LST -->|row / ID| VIEW
CRT -->|save| VIEW
VIEW --> RULES[Rules / compose]
VIEW --> EXP[Concepts / expansion]
RULES -->|expand| EXP
Shared model for list / create / view. terminology-server owns the tables; TEDY consumes the JSON envelopes.
Entity / Resource the reference platform API FHIR Notes
ValueSet /ts/value-setsValueSet list + detail; lastVersion / versions decorated
ValueSetVersion /ts/value-sets/{id}/versionsValueSet.version status ∈ draft/active/retired; carries ruleSet
ValueSetVersionRuleSet (embedded in version) ValueSet.compose {id, lockedDate, inactive, rules[]}
ValueSetVersionRule (embedded in ruleSet) ValueSet.compose.include/exclude type = include/exclude
ValueSetRuleFilter (embedded in rule) ValueSet.compose.*.filter {property, operator, value}
ValueSetVersionConcept expand result / snapshot ValueSet.compose.*.concept / expansion.contains expanded member
ValueSetSnapshot version.snapshotValueSet.expansion materialized {conceptsTotal, expansion[]}
List envelope n/a n/a { data: [...], meta: { total, offset } }
Field Type Card. Rule
idstring 1..1 identity; renamed only via change-id
uristring 0..1 canonical URL; unique
namestring 0..1 machine name
titleLocalizedName 0..1 multilingual display
description / purposeLocalizedName 0..1
publisherstring 0..1 code from publisher VS or free text
narrativestring 0..1 HTML narrative (FHIR text)
experimentalboolean 0..1
sourceReferencestring 0..1
otherTitle{name, preferred}[]0..* aliases
topic{text, tags[]}0..1
useContext{type, value}[]0..*
identifiersIdentifier[] 0..*
contactsContactDetail[] 0..* name + telecoms
configurationAttributesany[] 0..*
copyright{holder, jurisdiction, statement}0..1
permissions{admin, editor, viewer, endorser}0..1
settings{reviewRequired, approvalRequired}0..1
versions / lastVersionValueSetVersion[] 0..* version + status + releaseDate + ruleSet + snapshot
Field Type Rule
idnumber version key (with version) for PUT vs POST
versionstring semver-ish; unique per value set
statuscode draft / active / retired (lifecycle endpoints)
releaseDate / expirationDatedate (YYYY-MM-DD)
preferredLanguagestring
supportedLanguagesstring[]
descriptionLocalizedName
algorithmstring version algorithm (e.g. semver)
ruleSetValueSetVersionRuleSet the compose rules
snapshotValueSetSnapshot stored expansion (conceptsTotal, expansion[])
identifiersIdentifier[]
ValueSetVersion.ruleSet # ValueSetVersionRuleSet {id, lockedDate, inactive}
└── rules[] # ValueSetVersionRule
├── type # 'include' | 'exclude'
├── codeSystem # source code system id (rule targets a CS…)
├── codeSystemVersion # CodeSystemVersionReference {id, version}
├── valueSet # …or another value set…
├── valueSetVersion # ValueSetVersionReference
├── concepts[] # explicit ValueSetVersionConcept members
├── filters[] # ValueSetRuleFilter {property, operator, value}
└── properties[] # property codes to carry into members
ValueSetVersionConcept (a member): { id, concept: CodeSystemConcept, display: Designation, additionalDesignations: Designation[], orderNumber, active }.
Field ValueSet Canonical URL Binding
publisherpublisher https://tx.example/fhir/ValueSet/publisherextensible
version status publication-status http://hl7.org/fhir/ValueSet/publication-statusrequired
supported/preferred language languages http://hl7.org/fhir/ValueSet/languagesrequired (the reference platform has no all-languages)
rule filter operator filter-operator http://hl7.org/fhir/ValueSet/filter-operatorrequired
Internal field FHIR R5 path Mapping
idValueSet.iddirect
uriValueSet.urldirect
nameValueSet.namedirect
titleValueSet.titletransform (LocalizedName → language-resolved)
publisherValueSet.publisherdirect
purposeValueSet.purposetransform
narrativeValueSet.textdirect (HTML)
version ruleSet.rules[type=include] ValueSet.compose.include[]transform
version ruleSet.rules[type=exclude] ValueSet.compose.exclude[]transform
rule filters[] compose.*.filter[]{property, op, value}
version snapshot.expansion[] ValueSet.expansion.contains[]transform
A value set’s members are derived by expanding the version’s ruleSet; never stored on the ValueSet root. Read the members via expansion (POST /ts/value-sets/expand) or the version snapshot.
Snapshot vs live : prefer the stored snapshot.expansion when present (fast); fall back to a live expand for drafts / previews. Rule editing previews use expand-rule (a single unsaved rule).
Version lifecycle mirrors Code System: draft → active → retire, via dedicated endpoints (empty body, 204); editing an active version’s metadata is frozen server-side (the reference platform rule).
Publisher / status / language / filter-operator selects use TxConceptSelect(url=…) (dev proxies /api/tx/$expand → the reference platform FHIR).
Concept/member display resolves from display (a Designation) → language match → the member code.
Action Privilege
View / browse authenticated (dev: guest via the reference platform yupi)
Create / edit / delete / versions / rules ValueSet.write (the reference platform {id}.ValueSet.write)
Base /ts/value-sets unless noted. All TEDY calls go through @helex/tedy’s txApi (/txapi → dev-tx.example /api).
Method Path Priv Description
GET /ts/value-setsread list — params below
GET /ts/value-sets/{id}?decorate={bool}read load one (decorate embeds versions + ruleSet + snapshot)
POST /ts/value-sets/transactionwrite create/update — body ValueSetTransactionRequest {valueSet, version?, identifiers?}
POST /ts/value-sets/{id}/change-idwrite rename id — body {id: newId}
DELETE /ts/value-sets/{id}write delete value set
GET /ts/value-sets/{id}/provenances?version=read provenance history
List params (ValueSetSearchParams): id, ids, idContains, uri, uriContains, name, nameContains, description, descriptionContains, text, textContains, versionId, versionVersion, versionStatus, versionSource, decorated, lastVersionDecorated, lang, codeSystem, conceptCode, spaceId, packageId, packageVersionId, + limit/offset/sort.
Method Path Priv Description
GET /ts/value-sets/{id}/versionsread version list
GET /ts/value-sets/{id}/versions/{version}read load one version (with ruleSet + snapshot)
GET /ts/value-set-versions/{id}read load a version by numeric id
POST /ts/value-sets/{id}/versionswrite create version (body ValueSetVersion)
PUT /ts/value-sets/{id}/versions/{version}write update version
POST /ts/value-sets/{id}/versions/{version}/draftwrite → draft (empty body, 204)
POST /ts/value-sets/{id}/versions/{version}/activatewrite → active
POST /ts/value-sets/{id}/versions/{version}/retirewrite → retired
POST /ts/value-sets/{id}/versions/{version}/duplicatewrite duplicate — body {valueSet, version}
DELETE /ts/value-sets/{id}/versions/{version}write delete version
Method Path Priv Description
POST /ts/value-sets/{id}/versions/{v}/ruleswrite add a compose rule (ValueSetVersionRule)
PUT /ts/value-sets/{id}/versions/{v}/rules/{ruleId}write update a rule
DELETE /ts/value-sets/{id}/versions/{v}/rules/{ruleId}write delete a rule
PUT /ts/value-sets/{id}/versions/{v}/rule-sets/{ruleSetId}write update the rule set (e.g. inactive)
Method Path Priv Description
POST /ts/value-sets/expandread expand a saved version — body {valueSet, valueSetVersion} → ValueSetVersionConcept[]
POST /ts/value-sets/expand-asyncread async expand → JobLogResponse (poll)
POST /ts/value-sets/expand-ruleread preview one unsaved rule — body {valueSet, valueSetVersion, inactiveConcepts?, rule} → ValueSetVersionConcept[]
GET /ts/value-sets/{id}/versions/{v}/expansion-export?format={csv|xlsx|…}read start expansion export (→ processId)
GET /ts/value-sets/expansion-export-{format}/result/{processId}read download export result
Method Path Description
GET /fhir/ValueSet/{id}[|{version}]read FHIR ValueSet
GET /fhir/ValueSetFHIR search
GET /fhir/ValueSet/{id}/$expandexpand by id
GET /fhir/ValueSet/$expand?url=…expand by canonical (used by @helex/tx selects)
GET /fhir/ValueSet/$validate-codevalidate a code against the VS
POST /fhir/ValueSet/$syncsync (body Parameters)
Method Path Description
POST /file-importer/value-set/processfile import (multipart) → JobLogResponse
/tedy/value-sets — list (TEDY.02.1)
/tedy/value-sets/new — create (TEDY.02.2)
/tedy/value-sets/{id} — view shell (TEDY.02.3): Summary · Metadata · Concepts (expansion) · Rules
/tedy/value-sets/{id}/versions/new · /versions/{version}/edit — version form
/tedy/value-sets/{id}/compare — version compare (placeholder, shared pattern)
(Standalone Router basename="/tedy"; menu routes are basename-relative.)
Requirement Target
List load < 2s; server-side pagination (20/page); lastVersionDecorated only
Expansion (snapshot) < 2s; prefer stored snapshot; live expand only for drafts/preview
Rule preview (expand-rule) responsive; debounce edits
Search debounce ~400ms
List / view / create operate over /ts/value-sets* with the shared envelope.
A version’s members come from expanding its ruleSet (or its snapshot), never from the root.
Version lifecycle (draft/activate/retire) + rule add/edit/delete require ValueSet.write; read is open on the guest dev server.
Publisher/status/language/filter-operator render via their value sets.
traces-from: TODO user stories
children: TEDY.02.1, TEDY.02.2, TEDY.02.3
sibling family: TEDY.01 Code System (shares the shell, version form, summary widgets)