Teagle ⇄ reference eXplorer (tx.helex.dev) — parity spec
Comparison of the deployed reference Terminology eXplorer (tx.helex.dev) with the current Teagle web, and
specs for the missing pages to add. Per direction: hold the existing Teagle pages (Servers, Catalog,
Expand playground, Authoring, Operations) and add the ones below.
Reference eXplorer — navigation (observed)
Menu: Dashboard (Landing page · Global Search) · Terminology (Code systems · Value sets · Concept maps ·
Structure definitions · Structure maps) · Summary (Topology). Header: logo → /landing, language, GUEST,
overflow menu, global search box. Resource detail opens at /fhir/{Type}/{id} (content-negotiated: browser → UI,
Accept: application/fhir+json → FHIR).
Page inventory & gap
| Reference page | Route | Teagle today | Action |
|---|---|---|---|
| Landing / Ecosystem dashboard | /landing | Servers (plain table) | ADD dashboard (richer); keep Servers |
| Global Search | (search box) | Catalog search only | ADD cross-resource search page |
| Code systems (list) | /terminology/code-systems | Catalog (unified CS/VS/CM tabs) | ADD per-type pages; keep Catalog |
| Value sets (list) | /terminology/value-sets | Catalog | ADD per-type |
| Concept maps (list) | /terminology/concept-maps | Catalog | ADD per-type |
| Structure definitions (list) | /terminology/structure-definitions | — (none) | DONE |
| Structure maps (list) | /terminology/structure-maps | — (none) | DONE |
| Topology | /terminology/topology | — (none) | ADD graph view |
| Rich resource detail | /fhir/{Type}/{id} | Catalog row → raw JSON | ADD rich detail (tabs + content) |
| FHIR API landing / dev hub | /fhir (text/html) | — (none) | ADD static hub (content-negotiated) |
| Operation Examples | (from /fhir hub) | Expand playground + Operations | REUSE existing (link/seed) |
| Health | (from /fhir hub) | — | ADD trivial status page |
| Expand playground | — | ✔ (Teagle-only, keep) | keep |
| Authoring (editable server) | — | ✔ (Teagle-only, keep) | keep |
| Operations console | — | ✔ (Teagle-only, keep) | keep |
Specs for the missing pages
1. Ecosystem Dashboard (Landing) — /teagle/ landing
Structure (observed): a Resources stat card row — Total Code Systems / Value Sets / Concept Maps / Structure
Definitions / Structure Maps (each a link to its list page); a Server types stat row — FHIR servers / NPM
package targets / IG package targets / Open (public) targets; then one card per server: name + type badge
(FHIR / NPM PACKAGE / IG), FHIR versions, Supported Operations chips ($expand/$lookup/$validate-code), and
per-type counts (CS/VS/CM/SD/SM). Top search box. Data: /api/catalog/stats (per-server + totals) + /api/servers
(kind, ops, fhir versions). Use @helex/ui stat/AppCard + ResourceList where tabular. Keep the current
Servers page as the detailed registry table; Dashboard is the overview landing.
2. Global Search — /teagle/search
A single search box that queries all catalogued resources across servers by url / id / title (and optionally
concept text), returning a merged ResourceList grouped or badged by resource type + owning server, row → detail.
Data: /api/catalog?text=… (extend with a cross-type ?q= if needed). Debounced; type/server facets.
3. Per-type resource lists — /teagle/terminology/{code-systems|value-sets|concept-maps|structure-definitions|structure-maps}
ResourceList per type: columns ID (link → detail) · Last version · Title · Publisher · Status
· Count (concept count for CS; expansion size for VS; mapping count for CM), expandable rows (versions),
title/id filter + funnel (server, status). Data: /api/catalog?type=CodeSystem etc. + /fhir/{Type}?url=.
SD/SM — DONE. The catalog scan indexes both types (HttpCatalogScanner.DEFAULT_TYPES, trimmable via
teagle.catalog-scan.types) and TeagleResourceController serves them, so the same generic list page covers
them. Their column set differs from the reference’s only where the reference itself differs: SD adds Type
(the constrained base type) and Kind, SM leads with Name instead of Title, and neither carries a
Count (a StructureDefinition “count” would mean pulling the whole snapshot per row).
4. Topology — /teagle/topology
A force-directed graph of the ecosystem: nodes = resources (colored by type CS/VS/CM/…), edges = references
(VS→CS via compose, CM→CS via source/target), grouped by owning server. Zoom (+/−), fit, layout toggle, filter
(type/server). Use a graph lib bundled self-contained (no external CDN).
Backend: DONE — GET /api/topology (implemented) returns the Cytoscape shape
{ catalogVersion, truncated, elements: { nodes:[{data:{id,label,resourceType,server}}], edges:[{data:{id,source,target,kind}}] } }. Nodes are one-per-canonical (type,url) from the catalog; edges are
derived server-side (ValueSet compose composes/imports, ConceptMap group source/target, *-scope), only
between catalogued nodes (delegated-but-uncatalogued systems e.g. SNOMED are omitted), cached per catalogVersion.
Node id is "{type}|{bare-url}"; the frontend just renders the elements.
5. Rich resource detail — /teagle/fhir/{Type}/{id} (replaces the raw-JSON view)
Tabs Description | Concepts/Expansion/Mappings/Elements | JSON | XML (content-negotiated fetches). The header shows
the title in the UI language (resolved over the _title translation extensions). Description stacks, in
this order (same for every resource type): the other titles the resource carries, one ET / EN-chipped
line each → a metadata card (Official URL, Version, status/date, Computable Name, Flags,
Server source badge — which registry server served it) → Definition (the localized description) →
Properties (CS property declarations: Code / Description / Type with its ValueSet-or-CodeSystem binding /
URI) → Relations (CS “used in value sets”; VS “includes systems”; CM source/target; SD base definition +
the profiles its differential references; SM its structure[] and import[]) → the sanitized
Narrative (text.div) last, since it only restates the above. The content tab holds — for CS: a concept
table (Code / Display with multi-language designations / Properties) with search + total; for VS:
the merged expansion (reuse the Expand playground’s source-colored ResourceList); for CM: the
mappings table (source → target, relationship); for SD: the element tree
(FhirStructureDefinitionViewer from @helex/fhir — the same viewer TEDY uses: merged
snapshot + differential, slices as children, Σ/?!/C flags, cardinality, types with their target profiles,
binding links, and its own diff/hybrid/snap control). SM has no content tab — its groups and rules are the
body, which the JSON tab already shows, and the reference renders nothing for maps either.
Data: /fhir/{Type}/{id} (+ ?_format), and the ops the resource supports.
6. FHIR API landing / developer hub — /teagle/fhir (static GET /fhir as text/html)
The reference serves a developer-facing docs page at /fhir (content-negotiated: browser → this HTML hub,
Accept: application/fhir+json → the FHIR endpoint itself). It is the API entry point, structured as:
- Intro — “FHIR R5 terminology endpoint with content negotiation”; the Base URL for clients
(
…/fhir) shown as a copyable code span; one-line “use as the base URL for CodeSystem, ValueSet,$lookup,$expand,$validate-code”. - Content Negotiation table —
Acceptheader → result (text/html→Web UI,application/fhir+json/application/json→FHIR JSON,application/fhir+xml/application/xml→FHIR XML, none→FHIR JSON). - URL Patterns table — read (
/fhir/ValueSet/foo), versioned (…/foo|1.0.0), formatted views (…/foo.json,…/foo.xml), concept lookup (/fhir/CodeSystem/foo/active),…/foo/$expand,/fhir/CodeSystem/$lookup(POST),/fhir/metadata. - Browse Resources links → Global Concept Search · CodeSystems · ValueSets · ConceptMaps · StructureDefinitions · StructureMaps (the per-type lists above).
- Examples & Info links → Operation Examples (
$lookup,$validate-code,$expand, batch Bundle) · Ecosystem (dashboard) · Topology · API documentation · Health.
For Teagle: serve a static FHIR API hub page at GET /fhir when Accept: text/html (mirrors the
content-negotiation the reference uses), linking to the Teagle pages above. Two net-new leaf pages it references:
- Operation Examples — a small page of ready-to-run
$lookup/$validate-code/$expand/batch-Bundle request examples (Teagle already has the Expand playground + Operations console — this can link to them / seed them with the examples rather than a new page). - Health — a plain status page (
/actuator/healthor/api/health).
Backend touch-points (flag for the backend, mostly config/read-through)
- SD/SM: catalog indexing + read-through for
StructureDefinition/StructureMap(Flint routes, doesn’t own) — DONE (scan types + the resource/batch controller type sets). Topology emits SD/SM nodes but nobaseDefinition/structureedges yet: deriving those means fetching profile bodies, which is only affordable once the fetch asks for_summary=true. /api/topologygraph endpoint — DONE (TopologyController; see spec #4 for the shape).- Global concept-search / concept-detail cross-references (
/concept-search/{quick,harvest,cross-references}) — still needed. /api/catalog/statsalready exists (dashboard);/api/serversalready exists.
Note
The reference eXplorer’s /fhir/{Type}/{id} content-negotiation (browser UI vs FHIR JSON on the same URL) is a
routing nicety; Teagle can keep UI routes under /teagle/ and fetch FHIR from the backend /fhir/*.
Appendix A — source review of the reference frontend (tx-viewer)
Read of terminology-explorer/frontend/projects/tx-viewer/src/app (routes in app.routes.ts →
terminology/routes.ts + fhir/routes.ts; docs in docs/features/*). Corrections and additions to the above:
- No ETag / conditional-request / IndexedDB anywhere in the reference. Its only caching is RxJS
shareReplay(1), an in-memoryComponentStateStore, andsessionStorage. A stale-while-revalidate / ETag layer would be net-new for Teagle, not a port. - Concept-detail page is a distinct route we missed:
/fhir/{Type}/{id}/{code}→HlxTerminologyConceptDescriptionComponent. Header (code, display+lang, system uri, version), designations table, properties table (with binding-resolved codings), and parents / children / associations (cross-references) tables — each navigable. Add as a 7th missing page (net-new). Data:CodeSystem/$lookup(+ hierarchy properties) and a cross-references lookup (new backend endpoint). - Formatted
.json/.xmlview (/fhir/{Type}/{id}.json|.xml,FhirFormattedViewComponent) — pretty-print viaAcceptnegotiation, copy/download. Folds into the Rich-detail JSON/XML tabs (spec #5). /fhir/examples(FhirExamplesComponent) — server-rendered operation examples; the FHIR-hub (spec #6) Operation-Examples link can point at Teagle’s Expand playground / Operations console instead of a new page.- Resource detail two-step load (
resource.component.ts): render the shell from?_summary=true, then stream the full body — a real perf pattern worth adopting in spec #5.
Appendix B — ideas & optimisations to fold into Teagle (prioritised)
Backend support key: have = Teagle’s /api/{servers,catalog,catalog/stats,resolve} + /fhir/* already
cover it; new = needs a backend addition.
Tier 1 (high value, backend already there):
_summary=trueon all list/detail reads — list views never needconcept[]/expansion; seconds → tens of ms on LOINC/SNOMED-sized resources. (have)- Two-step resource load — summary shell first, full body streamed after (spec #5). (have)
- Ecosystem dashboard stat-cards + server-type breakdown + per-server counts from
catalog/stats+servers(spec #1). (have) - Versioned-id
|→--request rewrite in theteagleApiinterceptor (Tomcat rejects%7C;java.net.URIrejects raw|) — Teagle already parses--server-side. (have) - Structured FHIR-error toasts — parse
OperationOutcomein its several shapes; special-case the multi-server routing-conflict 500 into a sticky, actionable notice naming the conflicting servers (directly relevant to Teagle’s aggregation). (have)
Tier 2 (strong UX):
6. CDK-style virtual scrolling for concept lists/trees (flatten to visible rows) — 5k concepts 3000 ms→80 ms
in the reference; use @tanstack/react-virtual for the CS/VS concept viewers + Expand playground. (n/a)
7. Size-adaptive metadata filter default — preselect all <2000, common-only 2000–5000, none >5000. (n/a)
8. Property-filter table — per-property tags input, AND across / OR within, client-side over the loaded
concept list. (n/a)
9. List state + scroll restoration on back-nav (TanStack Query keepPreviousData + a scroll store). (n/a)
10. Debounced search standardised (reference: 250–500 ms per surface). (have)
11. Accept-Language + displayLanguage threaded into $expand/$lookup, showing the resolved-language
chip. (have)
Tier 3 (larger / net-new):
12. Topology graph — Cytoscape + cose, type-colored nodes, client-side .filtered-out filtering,
fullscreen; 503 + Retry-After retry while the graph builds. Needs a /api/topology endpoint (spec #4).
13. Concept-detail relations page (parents/children/associations) — $lookup (have) + a cross-references
endpoint (new).
14. Global concept text-search + $lookup harvest — /concept-search/{quick,harvest,cross-references} are
new backend endpoints; $lookup/$validate-code exist.
15. 503 “backend warming up” banner + poll until ready — fits Teagle’s reloadable in-memory registry; needs a
ready flag on an ecosystem/health endpoint.
Reference files worth lifting from: resource/resource.component.ts,
resource/concept-description/concept-description.component.ts, resource/concepts-tree-view/*,
resource/concepts-paginated-list/*, terminology/topology/*, terminology/global-search/*,
landing/landing.component.*, core/http/* (interceptors: pipe-encoding, error-handling, lang, readiness).