I designed, from scratch, a dental practice management system that absorbs the complexity of government reimbursement so the clinician never has to think about it.

This is a new product, not a redesign — a competitor to the legacy software most Danish clinics run on today. I designed the entire system, from architecture down to every screen. Below are three slices of it.

Replace the legacy software everyone uses

Most Danish clinics still run on old, clunky software. We’re building its replacement — from the ground up. The hard part isn’t the screens, it’s the domain: who pays for what depends on who the patient is — and a mistake means a rejected claim and lost money.

Dental care in Denmark is funded through three public agreements. Who pays, and whether the patient is billed at all, depends on which one the patient falls under:

01

Voksentandpleje

Adult patients
Who pays
Region + patient
Patient billed
Yes — their share

The region covers part of each service; the patient pays the rest. The system computes their share per service.

02

BUT

Children & adolescents
Who pays
Municipality
Patient billed
Usually none

By default the municipality covers it fully — a different payer, different reporting, and no patient bill. Exception: under free choice of a private clinic for children under 16, parents pay a 35% egenbetaling.

03

Omsorgstandpleje

Non-mobile patients
Who pays
Municipality
Patient billed
None

For those who can’t travel to the clinic. Again a municipal payer — with its own set of services and rates.

On top of this sit the official ydelseskoder (national service codes for billing) and rammestyring — the budget framework. Every action a clinician takes must ultimately resolve to the right code, the right payer and the right price.

The clinician

Thinks in teeth and treatments, documents right at the chair. Should never have to think about codes, payers or rates.

The administrator

Thinks in agreements and price lists. Configures the clinic once and wants billing to reconcile without chasing clinicians.

Our edge: one of the developers of that very legacy software is on the team. He knows every pain point and constraint of that system from the inside — so we’re not designing blind, but working back from the real problems that frustrate clinics every day.

The foundation: an architecture that separates two worlds

Before any screens, I designed a map of the whole system. One layer where the clinician works, another where the administrator hides all the complexity, and a billing engine between them that nobody has to operate by hand. Every module below was designed from scratch; three of them are shown as slices.

Practice Management System

CLINICAL LAYER

daily · clinician
  • Calendar & scheduling
    Chairs, clinicians, recalls
  • Patient record
    Demographics, consent, agreement type
  • Slice 3
    Dental journal · canvas
    Block-based documentation
  • Odontogram
    FDI chart, findings, history
  • Slice 1
    Treatment plans
    Template-driven courses
  • Medical history
    Health history, risk flags

CONFIGURATION & FINANCE

configure once · administrator
  • Slice 2
    Services & service codes
    Mapping to ydelseskoder
  • Price lists & rates
    Per agreement, per payer
  • Partners & payers
    Regions, municipalities, insurers
  • Patient finance
    Invoices, patient share, claims
  • Reporting
    Activity vs. rammestyring cap
  • Clinic administration
    Companies, staff, access
Shared engine An automatic layer between clinic and finance — it runs itself; nobody operates it by hand
Payer resolutionPatient-share calculationCode validationAgreement rules

The highlighted modules are the three slices shown below. The rule that shaped everything: any object the clinician touches (a treatment, a plan step, a journal entry) is bound to its billing meaning at configuration time — never at the moment of care.

Slice 1 of 3 · Clinical layer

Treatment plans that build themselves

The clinician picks a clinical intent; the sequence, intervals and billing steps come bundled.

Multi-visit dental treatment follows a protocol: a periodontal course is diagnosis, deep cleaning, then re-evaluation — cleanings every four weeks. Rather than ask clinicians to assemble this visit by visit, I designed plans around Behandlingsforløb templates: pick a protocol and the system unfolds the full sequence of visits.

1 2 3 4
Live prototype — press “Explore live” to interact
1

Template selector

A plan starts from a named Behandlingsforløb — category, course type and responsible clinician in one card. No assembling a plan from scratch.

2

Visit timeline

Choosing a protocol unfolds the whole sequence of visits. A periodontal course lays out as base treatment → cleanings → re-evaluation.

3

Editable intervals

The recall interval (“every 4 weeks”) is part of the template, edited inline between visits and feeding scheduling directly.

4

Saving separated from building

Adding steps and committing the plan are separate actions (a deliberate late change — see decisions below). Per-tooth detail is chosen later on the FDI chart in the journal.

Key decisions

Templates over building from scratch

A plan starts from a named Behandlingsforløb — most courses are standard.

FDI chart as the selector

The chart itself is the selector: one way to pick a tooth, zero desync.

Saving separate from building

“Add step” and “save plan” are distinct actions, so nobody loses work.

Slice 2 of 3 · Configuration layer

Where the complexity actually lives

The admin configures once — the clinician never sees a code.

Every clinical activity in the system is mapped — once, by the administrator — to its official ydelseskode, its per-agreement rates and its charting behaviour. It’s this single act of configuration that lets every other screen stay clean.

1 2 3 4
Live prototype — press “Explore live” to interact
1

Service catalogue

All of the clinic’s billable services in one searchable list. A service is added or retired here, once — and propagates everywhere downstream.

2

One service, many variants

“Composite filling” expands into 50 billing variants by tooth and surface — each already bound to its own price and code.

3

Clinical behaviour, not codes

For each service: whether a tooth/surface is required, how it marks the odontogram — exactly what the clinician actually meets at the chair.

4

Codes and rates live here

The Price List tab maps each service to its official ydelseskode and per-agreement rate. This is the one screen the clinician never needs to open.

Slice 3 of 3 · Clinical layer

The clinician’s workspace

Documenting the treatment and producing a correct claim are one and the same gesture.

A block-based journal canvas for documenting during the appointment — findings, treatments and notes assembled inline, with the odontogram at hand. Everything recorded here already carries its billing meaning from the configuration layer.

1 2 3 4
Live prototype — press “Explore live” to interact
1

Patient in context

Identity, age and agreement type sit at the top, so the right payer rules are already in force before anything is recorded.

2

Plan and risks alongside

The active treatment plan and medical flags/risks stay in view while documenting — the clinician never leaves the record to check context.

3

Palette of entry blocks

A visit note is composed from typed blocks — reason, treatment, consent — not one empty text field.

4

Documenting = billing

Each block carries the code and price it was configured with in Slice 2 — so a correct claim is a by-product of documenting the treatment, not a separate task.

Three principles the whole system follows

Principle 1

Complexity lives in configuration, not in the clinician’s head.

Agreements, codes and rates are absorbed at configuration time. The clinical layer speaks only the language of treatment.

Principle 2

The system resolves payer and rate — never the user.

Who pays is a function of patient type and agreement, resolved automatically. There is no screen where a human picks a payer from a list.

Principle 3

Billing errors are designed out, not trained away.

If a combination could produce a rejected claim, the interface simply doesn’t offer it. Correctness is structural, not a training requirement.

How the design was stress-tested

In a domain where the wrong code means a rejected claim, correctness had to be validated before development — not discovered in production.

Domain

Checked against real rules

Every billing rule in the design was traced back to the actual agreement texts and the ydelseskode catalogue, together with a billing specialist — before it became UI.

Users

Walked through with both roles

Flows were reviewed with a clinician and a clinic administrator to confirm the separation holds: clinicians reached their goal without meeting a code; admins configured without a designer in the room.

Failure mode

Errors shifted earlier

In review, invalid payer/code combinations couldn’t be assembled at all — the failure moved from “rejected claim weeks later” to “can’t be proposed now.”

The metrics it’s built to move — rejected-claim rate, time to document a visit, and time to configure a clinic — will be measured against the clinic’s current tools once the pilot begins.

Where the project stands

Status

The information architecture, the billing model and the three modules shown here are designed and prototyped. The system is in active development — clinical layer first — and the next validation step is a pilot at a partner clinic.

What 0→1 in an unfamiliar regulatory domain taught me

Learn the domain before drawing a single screen — the architecture is a consequence of the rules, not the other way around. Design daily next to whoever owns the billing logic. And encode the rules the system can be certain of, while leaving honest escape hatches for the edge cases regulation gives no clean answer to.

Designing a product where mistakes are expensive? Let’s talk.

I design complex, rule-heavy products end-to-end — from information architecture to the last empty state.