The fast path for maintaining the fhir.ch IG catalog. If you just need to start a ballot cycle, hide an IG, or add a workgroup attribution, you're in the right place. For the full data contracts and every curation knob, see WEBSITE_README.md. For the IG publication pipeline see README.MD.
./package-registry.json ─┐ fetch at page-load (same-origin)
./ig/<slug>/package-list ─┘
│
▼
js/load-data.js ← curated overlay
(OVERRIDES, (workgroup, organization,
BLACKLIST, description, hidden IGs,
EXTRA_IGS, extra IGs, ballot cycle)
BALLOT_CYCLE)
│
▼
js/app.js ← renderer
│
▼
index.html ← page chrome
(hero CTA, tabs, sub-tabs)
Two JSON files (the registry and one package-list.json per IG) live in this repo, produced by the IG publication workflow. The browser fetches them same-origin on every page load, applies the curated overlay in js/load-data.js, and the renderer in js/app.js paints the result into index.html. No build step, no Node, no CI runtime — edit a file, reload the page.
The per-IG package-list.json is the version history: the loader walks it newest-first and picks at most two versions per IG (latest published + latest open ballot). A ballot is silently dropped if a newer published release already exists.
python3 -m http.server 8000
open http://localhost:8000/An internet connection is required — the catalog data is fetched at load time, not bundled.
| You want to change… | Edit this | Notes |
|---|---|---|
| IG metadata (workgroup, organization, description, ballot info) | js/load-data.js → OVERRIDES |
Keyed by package-id. |
| Whether an IG appears at all | js/load-data.js → BLACKLIST or EXTRA_IGS |
Drop / add. |
| Ballot vote forms + hero "Register to vote" button | js/load-data.js → BALLOT_CYCLE |
One object for the whole cycle; set to null to close. |
| Hero buttons, ballot sub-tab strip, page header | index.html |
Static markup; no template engine. |
| The actual catalog data (a new IG, a new version, a fixed title) | PR against hl7ch/hl7ch.github.io |
Don't try to fake it locally — file the PR upstream. |
-
In Google Drive, find each
<IG short name> - HL7.ch Ballot 20XXform plus theRegistration HL7.ch Ballots 20XXform. Each Drive URL ishttps://docs.google.com/forms/d/<FILE_ID>/edit— copy the<FILE_ID>segment. -
In
js/load-data.js, fill in theBALLOT_CYCLEobject (just belowBLACKLIST):var BALLOT_CYCLE = { year: '20XX', registrationFormId: '<REGISTRATION_FILE_ID>', forms: { 'ch.fhir.ig.ch-core': '<CORE_FILE_ID>', 'ch.fhir.ig.ch-emr': '<EMR_FILE_ID>', // …one entry per per-IG form } };
Reload
http://localhost:8000/: every open ballot row gets a green VOTE chip, the hero shows a blue Register to vote · Ballot 20XX → button. No HTML edit required —js/app.jsreadsBALLOT_CYCLEon load and toggles the hero buttons.
Set BALLOT_CYCLE = null in js/load-data.js. That's it — the hero Register button hides, "Join FHIR.ch work group calls" goes back to primary, and every per-IG VOTE chip disappears. No other edits needed.
Two ISO-date fields on BALLOT_CYCLE let registration and voting expire on their own — useful when registration closes weeks before voting:
var BALLOT_CYCLE = {
year: '2026',
registrationCloses: '2026-08-03', // hero Register button hides 2026-08-04
votingCloses: '2026-09-30', // all VOTE chips hide 2026-10-01
registrationFormId: '…',
forms: { … }
};Both fields are INCLUSIVE (the day named is still active; the UI piece hides starting the day after) and use the browser's local date. Either is optional — omit one to keep that piece live until you flip BALLOT_CYCLE = null by hand. The forms themselves should still be closed in Google Drive ("Accepting responses" off) as the authoritative kill switch; these dates only handle the UI.
Dev-mode sanity check. When you're running on
localhost/127.0.0.1/file://, the page prints[ballot-cycle]warnings to the browser console for any drift betweenBALLOT_CYCLEand the catalog data:BALLOT_CYCLEisnullwhile IGs are still under-ballot, an under-ballot IG has no form entry, aBALLOT_CYCLE.formskey is stale / a typo / references a now-published IG, orBALLOT_CYCLE.yeardoesn't match any IG'sballotClosesyear. Open devtools after any edit and you'll see what to fix. Production hostnames stay silent.
Add or edit an entry in OVERRIDES (js/load-data.js), keyed by the IG's package-id:
'ch.fhir.ig.ch-core': {
description: '…', // overrides the upstream introduction
workgroup: WG_FHIR, // use one of the WG_* shorthands above
organization:'hl7ch', // id matching ORG_NAMES
ballotType: 'stu', // 'stu' | 'dstu' — overrides sequence inference
ballotCloses:'2026-07-15', // ISO date shown on the ballot row
links: { source, wiki, jira }, // optional overrides
publicationStatus: 'published' // force-promote a ballot-tagged release
}All fields are optional — set only what you want to override. IGs with no OVERRIDES entry get sensible defaults; check the browser devtools for a console.warn listing every IG currently running on defaults.
Append the package-id to BLACKLIST (js/load-data.js) with a one-line // why comment. Existing entries (CH ATC, CH EPR PPQm, CH EPR mHealth — all superseded by CH EPR FHIR) are good templates.
Append a fully-specified record to EXTRA_IGS in js/load-data.js. The Swissnoso and MedNet Interface entries are the working templates — copy one and replace the fields. This is a stopgap; the proper fix is to publish the IG through the publication workflow (see README.MD) so it lands in package-registry.json natively.
Open WEBSITE_README.md when you need:
- The full per-field contract for upstream
package-registry.jsonandpackage-list.json. - How the automatic fallbacks (
CI_BUILD_ORG,ORG_DEFAULT_WG, sequence/DSTU inference) decide an IG's organization and ballot type whenOVERRIDESis silent. - The pinning / sort rules in
js/app.js(which IGs float to the top, how org groups are ordered).