Overview

Helios offers customers two ways to use a finished logic, both managed from the Helios Casemix Engine under Admin:

  • The grouping API — the customer's own systems send contacts and receive DRGs as JSON. Access is controlled by API keys that you create and revoke. The customer-facing description is in the API guide.
  • Production sites — every customer gets two public web pages, heliosgroup.dk/<customer>/flow (Atlas) and heliosgroup.dk/<customer>/group (Grouper), with a year picker. They are read-only and open to anyone with the link.

Both only ever serve logics that have been fully approved, so nothing half-reviewed reaches a customer.

Who can do what

Access is set per account with roles in Netlify Identity.

RoleCan do
grouperGrouper, Atlas, Creator (create, import, edit and delete logics, set one active), approve changes in the change log, rename group codes and add codes to them, and manage Production sites (add customers, push logics).
grouper-adminEverything above, plus API keys. Only grouper-admin accounts can create, revoke or delete an API key, and the API keys sit in the Helios-only part of the client portal. Only grouper-admin accounts can also view the engine as a customer.
Extra roleMeaning
customer-<slug>, e.g. customer-regionxTies the account to one customer. Combine it with grouper. The account then sees and changes only that customer's logics — see Customers and their users.
Level inside a customerRoleCan do
Read-onlyviewerLook at the customer's logics and Atlas, group contacts, download bulk results. Cannot change anything.
EditoreditorAlso edit rules, labels and group codes, save and restore versions, run and edit validation tests, push to production, and run bulk jobs.
Approverapprover (also what an account with none of these roles counts as)Also accept or decline a logic Helios pushed, approve change-log entries (never their own), delete a logic, and take a year offline.
Administratorportal-adminAlso invites users, sets their level, and manages the customer's sign-in security. Sees the audit trail.

Helios's own accounts are not limited by these levels. The levels are enforced on the server, not only by hiding buttons.

The public production pages need no login and cannot change anything.

Customers and their users

A customer can have any number of users (for example 11 users at Region X). Customers are kept strictly apart: a customer's users can never see, open, group with, edit, export, use, edit, export or delete another customer's logics, and never see Helios's own.

Set up a customer's users

  1. In Netlify Identity, invite each user.
  2. Give every one of them two roles: grouper and customer-<slug>, where the slug is the customer's address under Production sites (Region X → customer-regionx). The slug must match exactly.
  3. Do not give customer users grouper-admin — that role sees everything.

A user with customer-regionx but without grouper gets no access at all. Always give both roles.

What a customer user sees

  • Only the logics tagged with their customer, in Library, Atlas, Developer and Grouper. Their logic names are prefixed with the customer, e.g. regionx-….
  • Their own users share one set of logics, and the active logic is per customer — activating one logic switches off only that customer's previous one.
  • New and imported logics are created under their own customer automatically. They cannot choose another customer.
  • API calls with their key use their customer's API default logic, never a logic belonging to anyone else.
  • Production sites shows only their own site. They can push their own approved logics to it, but cannot add or delete customers.
  • They can upload their own SKS catalogue under Creator — one file per year, or one file ticked for several years. A year without a file of their own uses the standard catalogue that you import; only Helios administrators can change that one. They see no Helios-only section in the client portal.

What you do as Helios staff

  • Add the customer under Production sites first — it then appears in the client portal's customer list.
  • To work as a customer, open the client portal, scroll to Helios team and choose the customer under View the portal as a customer. The engine then opens exactly as that customer's own login sees it, and a bar at the top says so. Choose Helios — my own view (or press Back to the Helios view) to return.
  • A logic belongs to the customer you were viewing as when it was created or imported; logics created in your own Helios view belong to Helios. There is no way to move an existing logic to another customer — import or duplicate it while viewing as the right customer instead.
  • Logics without a customer are Helios-internal: only Helios accounts see them. Customers never see shared or standard Helios logics — give a customer a copy with Push to client: on a Helios logic in Library, choose the client in the drop-down and press Push. That puts an independent, inactive copy in Library of the client's own account (later edits to either logic do not affect the other; pushing again makes another copy).
  • Every logic and every client has a logic type (DK-DRG unless you set another, shown as a small label that you click to change; clients are changed under Production sites). A logic can only be pushed to a client of the same type — clients of another type are greyed out in the drop-down. As with Set as API default, a logic whose change log still has changes waiting for approval cannot be pushed.
  • A plain grouper account with no customer role is a Helios user: it sees only Helios-internal logics and has no Production sites panel.

The approval rule

Every edit to a logic in the editor is written to its change log. A logic can only be set as API default, pushed to production or used through the API by name when its change log has no entries waiting for approval. Accepted and declined entries do not block; only pending ones do.

In Library, a logic with outstanding approvals shows a warning icon; hover it to see how many. Open the change log, accept or decline each entry (a different person than the editor should do this — the four-eyes principle), and the icon disappears.

Use Lock on a logic row in Library to protect a logic from being edited: rules, labels, code groups, tariff data, year and deletion are all blocked, here and on the server, until someone chooses Unlock. A locked logic shows a lock tag. It can still be duplicated (the copy starts unlocked), set as API default, pushed to production and used for grouping.

The API default logic is the exception for the API: if a logic is already the API default, it keeps serving even if someone later edits it and creates new pending entries. Review the log before the next push or activation.

API keys

Open the client portal and scroll to Helios team → API keys. Only grouper-admin accounts see it, and it is hidden while you are viewing as a customer.

Create a key

  1. Type the customer or system name — one key per customer system, so a single key can be revoked on its own.
  2. Choose Customer. The key is bound to that customer and can only ever group with that customer's logics.
  3. Choose Logic (the list shows that customer's logics): All approved logics, or restrict the key to one logic (for example a customer who must stay on the 2025 logic).
  4. Choose Expires: never, after 90 days or after 1 year.
  5. Press Create key.
  6. Copy the key immediately. It begins with hgk_ and is shown only this once; Helios stores just a one-way hash and the first characters so you can recognise it later. If it is lost, create a new key and revoke the old one.
  7. Send the key to the customer by a secure channel (not plain e-mail if you can avoid it), together with the API guide.

The key list

Each key shows its name, first characters, created date, expiry, logic restriction and last used time (updated at most every ten minutes — useful for seeing whether a customer has actually started calling the API).

  • Revoke switches the key off immediately. Calls with it answer revoked_key.
  • Delete is available only on revoked keys and removes the record completely.

Rotating a key

Create the new key, let the customer switch over, check that last used on the old key stops moving, then revoke it.

Production sites

Tick Production sites in the menu on the left (below the line).

Add a customer

Type the customer's name (for example Region X) and press Add customer. The name is turned into the web address: Region X becomes regionx or similar, shown next to the customer once created. Names that cannot be used as an address, or that collide with an existing page or an internal word (such as api, admin, portal, about, contact), are refused; try another. The two pages for each customer are:

https://heliosgroup.dk/regionx/flow     Atlas
https://heliosgroup.dk/regionx/group    Grouper

Both stay empty ("Nothing is published here yet") until you push a logic.

Delete a customer

Delete customer removes the customer and all its pushed snapshots; the addresses then show "This page doesn't exist". Your own logics in Library are not touched.

Pushing a logic into production

Each customer card has one row per year. For a year:

  1. Pick the logic in Logic to push. The list contains the logics that have that year, so give a logic its year under Library first.
  2. Press Push to production. If the logic still has pending changes, the push is refused — approve its change log first.
  3. The row then reads live: <logic name> — pushed <date> by <who>. The year now appears in the year picker on the customer's public pages.
  • A push is a snapshot. It copies the logic exactly as it is at that moment. Editing the logic afterwards does not change what the public sees. To publish a correction, approve the change and press Push again.
  • A customer can have one live logic per year. Pushing another logic for the same year replaces the previous one.
  • Take offline removes that year from the public pages. If it was the last year, the pages show the "nothing published" message.
  • Pushing copies several large tables and can take a few seconds. Wait for the row to update before pressing anything else.

Staged push: the customer accepts first

When you push a logic to a customer from Library, the customer gets their own copy. By default that copy is pending: they have to open it and press Accept before it can be set as their API default, be used by their API keys, or be put in production. This lets them try it in the Casemix Engine first — it is their sandbox.

  • Type a short What changed? note next to the Push button. It is shown on the customer's copy, in their release notes and in the notification they receive.
  • Untick Client must accept first for a push that needs no review (for example an urgent correction). The copy is then usable straight away.
  • The row shows Awaiting customer review, Accepted by … or Declined. A customer who declines must give a reason; you see it on the row and get a notification. Push a new version to start again.
  • A copy that is pending or declined cannot go to production and is ignored by the API until it is accepted.

Versions, restore and rollback

Versions of a logic

The Versions button on a logic opens its history. A version is saved automatically when the last change waiting for approval is approved, before every push to a customer or to production, and before every restore. You can also press Save a version now (with a label such as "before the January tariff update"). The last 15 are kept; identical states are not saved twice.

  • Compare with now shows how many rules were added, removed or changed since that version, with examples.
  • Restore puts that version's tables back as the live logic. A reason is required; it goes in the change log ("Version restored") and the audit trail, and the customer is told if the logic is theirs. The state before the restore is saved as a version too, so a restore can itself be undone. A locked logic cannot be restored — unlock it first.
  • A version saved when everything was approved restores as approved. One saved by hand mid-edit still needs a second pair of eyes in the change log.

Rolling back production

Each year on a customer card keeps the three previous versions that were live. Under Earlier versions, press Roll back to this (twice, to confirm). The public pages switch at once; the version that was live moves into the history, so a rollback can be undone the same way. A rollback is recorded in the release notes and the customer is notified.

Type a What changed? note when you push to production; it appears under Live in production in the customer's portal.

Usage, release notes and the audit trail

In the client portal, the card Usage, releases and activity shows, for the customer you choose (customers see only their own):

  • API usage — requests, contacts grouped, contacts with an error and refused requests for 7, 30 or 90 days, per day, per API key and per logic. The figures are close but not exact: two requests landing in the same instant can be counted once.
  • Release notes — what is live per year and every push, rollback, acceptance and restore with its note.
  • Audit trail (Helios administrators and customer administrators) — who did what to logics, users, keys and sign-in security, with the address people signed in from. The last three months are shown; Export saves them as a CSV. Customers see everything that concerns their account, including what Helios did on their behalf. Entries cannot be edited or deleted. A month holds at most 2,500 entries.

Security: two-factor, IP limits, idle sign-out

Two-factor sign-in (authenticator app)

Netlify Identity has no two-factor login of its own, so the engine adds one on top: a 6-digit code from an authenticator app (Microsoft Authenticator, Google Authenticator, 1Password …). It is checked on the server for every request, not just on screen.

  1. In Netlify's site settings add the environment variable TWOFA_SECRET with a long random string (at least 16 characters; 40 is better). Without it the feature stays off. Do not change it later: it protects the stored secrets, and changing it locks everyone who enrolled out.
  2. Optional: add REQUIRE_2FA with the value admins to make Helios administrators and customer administrators set it up before they can do anything else.
  3. Everyone can switch it on under Sign-in security in the client portal. The portal shows a key to type into the app (or a link that opens it on a phone) and eight one-time recovery codes — shown once, to be stored safely.
  • Lost phone and recovery codes: a Helios administrator uses Reset someone's two-factor sign-in in the same card. The person signs in normally and sets it up again.
  • If every Helios administrator is locked out: open Netlify Identity, find the account and remove the mfa role. Two-factor is then off for that account.
  • If TWOFA_SECRET is removed while accounts carry the mfa role, those accounts are refused (fail closed). Put the secret back, or remove the role.
  • The proof of the code is valid for 12 hours in that browser; each code can be used once.

Single sign-on (the customer's own identity provider, such as Entra ID or a regional login) is not possible with Netlify Identity as it is used here. It requires moving sign-in to an identity provider that supports SAML or OIDC; the engine's roles and customers would carry over. Plan it as a separate project.

Allowed addresses for an API key

When you create a key, Allowed addresses can limit it to your customer's servers: IPv4 addresses, IPv4 ranges such as 198.51.100.0/24, or IPv6 addresses, separated by commas. The Addresses button on a key changes the list later. A request from any other address gets 403 ip_not_allowed. Leave it empty to allow every address. Customers behind a changing address (mobile networks, some proxies) should not be limited.

Inactivity sign-out

After 45 minutes without activity in any open tab, people are signed out; two minutes before, a notice offers Stay signed in.

Data protection page

The Data protection page describes in plain terms what is stored, where and who can see it. It is a starting point for a data-processing agreement, not the agreement itself; have it reviewed by your legal adviser and confirm the hosting region in Netlify before you send it to a customer.

What the public sees

The two pages are the same engine, with every way to change data removed. They have no login and nothing links to them — anyone who knows the address can open them, so share the address only with the customer. Do not put confidential information in a logic that is pushed to production.

PageWhat it contains
/<customer>/flowAtlas, with Find & filter and DRG information, for the selected year. Click a rule or group code to see its details. A year picker switches between pushed years.
/<customer>/groupGrouper, read-only: enter diagnoses and procedures and see the DRG and the rule that fired.

Not available on the public pages: editing rules, labels, group codes or tariffs, the change log, importing, exporting, logics, and grouping from files.

Validation tests

Every logic can carry a set of validation tests: test contacts together with the DRG each one must group to (and, if you like, the tariff and trim point). They are the safety net before anything reaches a customer.

  • Adding tests. In Grouper, group a contact and choose Save as validation test; or open Validation tests on the logic in Library and import a CSV (download the template there). Up to 300 tests per logic.
  • Running them. Run validation groups every test against the logic's current rules and shows pass or fail per test. Download report saves the result as a CSV.
  • Automatic gate. Pushing a logic to a customer, and pushing to a production site, runs the tests first. If any fail the push is stopped and the failing tests are listed. A Helios administrator can choose to push anyway; the override is recorded on the validation run.
  • When a logic is pushed or duplicated its tests travel with the copy, so the customer's copy can be re-tested after later changes.

A logic without any tests is not blocked — it just has nothing to check. Build up the set from real cases whenever you fix or change a rule.

Notifications, problem reports and customer users

The bell and the "Report a problem" button

Signed-in users see a small bell and a Report a problem button at the bottom right of the portal and the engine. The bell lists what matters to them: a new logic in their library, a logic that went live in production, an approved or declined change, an API key about to expire. Helios sees new problem reports and new invitations.

A problem report carries the description, the page, the logic and year that were open, and recent errors and failed requests. It never contains patient data. Helios administrators work through them under Problem reports in the Helios section of the client portal (mark resolved, reopen).

Customer users

Under Your team in the portal, a customer's administrator can invite colleagues, make someone an administrator, or remove access. A Helios administrator sees the same card with a customer selector. The first administrator of each customer has to be given the portal-admin role by a Helios administrator in Netlify Identity (in addition to grouper and customer-<name>); after that the customer manages their own users. There must always be one administrator left, and nobody can remove their own access.

Optional email

Notifications always appear in the bell. To also send email, set RESEND_API_KEY and NOTIFY_FROM (a verified sender address) as environment variables on the site; set REPORT_TO to receive problem reports by email too. Without them nothing is sent and nothing breaks.

Roles inside a customer

Every customer user has one of four levels: Read-only, Editor, Approver or Administrator (see Who can do what). A customer's administrator sets them under Your team in the client portal: pick the level when inviting someone, or change it afterwards in the drop-down next to the person. A Helios administrator can do the same for any customer.

  • An account that already existed before this feature has none of these roles and counts as an Approver, which is everything it could do before (managing users stays with the administrators). Nothing is taken away; set someone to Editor or Read-only to limit them.
  • Keep at least two people in each customer at Approver level (or administrator): nobody can approve their own change, so a single approver cannot approve their own work. Someone invited as Editor cannot accept a pushed logic or approve a change.
  • A Read-only user sees the Grouper and Atlas panels only. If they try something else the server answers insufficient_role and the screen says their role does not allow it.
  • Each level change is written to the audit trail.

Bulk grouping jobs

For big files, Bulk grouping (under Grouper, below Group from files) groups up to about 20,000 contacts on the server, so nobody has to keep a browser open.

  • The user picks a logic, uploads an Excel workbook (the same Stam / Diag / Proc / Forl layout as Group from files, with forløb grouped by the loop method) or a CSV with one contact per row (a template can be downloaded), and presses Upload and start.
  • The job shows its progress; when it is ready the person who started it gets an email (if email is set up) and a notification, and the result can be downloaded as Excel or CSV. Open the page again at any time — the jobs are listed there.
  • A saved job can repeat every week or month against the logic as it is at that time. The repeat is started by the daily scheduled function; it needs JOBS_SECRET (any long random text) in the site's environment settings, or else TWOFA_SECRET, which is used if it is set. Without either, repeats do not start.
  • A repeat or a run uses a logic only if the customer has accepted it and it has its tables — otherwise the job fails with a clear reason and the person is told.
  • Only Editors and above can create jobs; Read-only users can download results. A customer sees only its own jobs, Helios sees all.
  • Limits: 50,000 records per job (a forløb counts once per contact), 20 saved jobs per customer.
  • Data: the uploaded file is stored as coded fields only (diagnoses, procedures, age, sex and the contact codes, plus the customer's own contact number), together with the result. A job that does not repeat is deleted automatically 30 days after it finished; a repeating job is kept until someone deletes it. Say so to customers — see the Data protection page.

The getting-started checklist

Customer users see a Getting started card at the top of the client portal: accept the logic, group a test contact, get an API key, send a first API request, and (optional) try a whole file and see the live site. The ticks come from what has actually happened, so nobody has to tick anything. Each customer can hide the card and show it again.

The card also links two sample files, sample-contacts.xlsx and sample-contacts.csv, for trying Group from files and Bulk grouping. The codes in them are examples; check the results against your own logic before showing them to a customer.

Alerts and the status page

Alerts

  • Error spike. When a customer's errors for the day pass 20 and make up at least 20 % of what was sent, the customer's bell gets a notice and Helios's bell does too (and an email, if email is set up). At most one a day per customer. Change the limits with ALERT_MIN_ERRORS and ALERT_ERROR_RATE (for example 0.3 for 30 %).
  • Key about to expire. Customers already see it in the bell. In addition, an email goes to the customer's users when a key has 14 days left and again at 3 days, and Helios gets a notice.
  • These run from the daily scheduled function and the API itself, so they work on the live site only.

The status page

status.html is public. Every hour the site asks its own grouping API (/api/v1/health) and the portal page whether they answer, and keeps the result per day. The page shows whether each is up now, uptime for the last 90 days with one bar per day, and recent incidents. It holds no customer data. If the checks stop for more than 90 minutes the page says unknown rather than operational. Helios gets a notice when something stops answering.

The page links from the footer of every page. The checks are Netlify scheduled functions, which run only on the published (production) deploy.

Supporting a customer

  • "Which logic is my key using?" If no logic is named in the request, the one that is active in Library. The result of every call includes the logic's id, name and year.
  • "Results changed." A new logic was set as API default, or an edit to the API default logic was approved. Customers who need stable results should name a logic id in their requests, or have their key restricted to one logic.
  • Edits reach the API within about a minute (logics are cached briefly). Production pages change only when you push.
  • Limits: 500 contacts per request, 100 codes per list. Larger files are sent in several requests.
  • Contacts sent through the API are not stored; only the key's last-used time is recorded.

Troubleshooting

SymptomLikely cause and fix
Customer gets 401 invalid_keyKey mistyped, truncated or with a trailing space/line break. Check the first characters against the key list; if in doubt, issue a new key.
401 revoked_key / expired_keyThe key was revoked or has passed its expiry date. Create a replacement.
403 logic_not_allowedThe key is restricted to certain logics and the active one is not among them. Either name an allowed logic in the request or create a new key without the restriction.
404 logic_not_foundThe logic id is wrong, the logic has pending change-log entries, or the key may not use it. GET /api/v1/logics with that key lists what it can use.
409 no_active_logicNo logic is set as API default. Use Set as API default in Library.
503 logic_unavailableThe logic's tables are incomplete (for example an import that did not finish). Re-import or replace the missing table.
Push is refused: "still has changes waiting for approval"Approve or decline every pending entry in that logic's change log, then push again.
The year is not in the list under "Logic to push"The logic has no year set. Set its year in Library.
A customer page says "Nothing is published here yet"No year has been pushed for that customer, or all years were taken offline.
A customer page says "This page doesn't exist"The customer was deleted or the address is mistyped. Check the address shown on the customer card.
Customer wants the page removedTake the years offline, or delete the customer.

Staging site and automatic checks

Try changes before they reach customers.

  • Automatic checks. Every deploy runs npm test first (the build command in netlify.toml). If a check fails, Netlify does not publish that deploy and the live site stays as it was. GitHub runs the same checks on every pull request (.github/workflows/test.yml).
  • A staging copy. Make a branch called staging in GitHub and, in Netlify, enable Branch deploys for it (Site configuration → Build & deploy). It gets its own address, like staging--heliosgroup.netlify.app. Pull requests get a deploy preview the same way.
  • Separate data. A staging or preview deploy uses its own store (grouper-branch-deploy, grouper-deploy-preview), so nothing done there touches the live logics, keys or customers. It starts empty: import a logic or two to test with. A banner at the top says Test environment.
  • Settings. The environment variables must be available for the contexts Branch deploys and Deploy Previews, not only Production (Site configuration → Environment variables). Use different values for TWOFA_SECRET and for the Resend settings if you do not want test emails going out. Scheduled checks and bulk repeats do not run on staging.
  • Moving a change to the live site. Merge the branch into the main branch; the build runs the checks again before publishing.

First-time setup

  1. Deploy the site with the API and production functions and the updated netlify.toml. The redirects /api/v1/* and /<customer>/flow, /<customer>/group only exist after that deploy.
  2. Check https://heliosgroup.dk/api/v1/health in a browser; it should answer {"ok":true,"apiVersion":"1"}.
  3. Make sure a logic has been set as API default and has its tariff data, then create the first key and test it with the curl example in the customer guide.
  4. Add the first customer, push a logic and open both customer pages in a private browser window (not signed in) to confirm they work for the public.