User Journey Maps
A User Journey Map describes the end-to-end experience of a customer or user
interacting with a service. kUML’s blueprint {} DSL captures this as a
type-safe model — versionable in Git, renderable as an SVG swimlane diagram,
and executable in CI.
The four-layer model
kUML follows the classic Service Blueprint structure with four horizontal layers separated by three dividing lines:
| Layer | What it contains |
|---|---|
Customer Actions |
Every touchpoint where the customer interacts with the service: search, click, fill in a form, receive an email, pick up a parcel. |
Frontstage |
All visible interactions between staff/system and the customer. This is what the customer can see: the web form, the chat bot reply, the confirmation screen. |
Backstage |
Behind-the-scenes work that the customer cannot see: fulfilment, manual review, account verification, fraud check. |
Support Processes |
Shared infrastructure and third-party services that underpin frontstage and backstage: payment gateway, CRM, email service provider, warehouse system. |
The three dividing lines are rendered as dashed horizontal rules in the SVG:
-
Line of Interaction — between Customer Actions and Frontstage.
-
Line of Visibility — between Frontstage and Backstage.
-
Line of Internal Interaction — between Backstage and Support Processes.
Sentiment
Each step carries an optional sentiment annotation that drives the colour of
that step’s node in the rendered diagram:
| Value | Colour (default theme) | Meaning |
|---|---|---|
|
Green |
Customer is delighted or relieved. |
|
Grey |
No strong emotional signal. |
|
Red |
Customer is frustrated, confused, or blocked. |
|
Amber |
Known friction: acknowledged but not yet eliminated. |
DSL reference
blueprint("…") {
// Actors, channels and touchpoints are declared at the `blueprint { }` level
// (DslMarker scope isolation forbids declaring them inside `phase { }`) and
// referenced from steps by their id.
val someActor = actor("…", ActorRole.STAFF)
val someChannel = channel("…", ChannelKind.WEB)
val someTouchpoint = touchpoint("…", channel = someChannel)
phase("…") { // swimlane column / phase heading
customer("…", Sentiment.POSITIVE, // Layer: Customer Actions
touchpoints = listOf(someTouchpoint))
frontstage("…", actor = someActor, // Layer: Frontstage
touchpoints = listOf(someTouchpoint))
backstage("…", actor = someActor) // Layer: Backstage
support("…", actor = someActor) // Layer: Support Processes
}
// phases are connected left-to-right in declaration order
phase("…") { /* … */ }
// renders all four layers + the three dividing lines; emotionCurve overlays
// the Sentiment-driven curve described above
blueprintDiagram("…", emotionCurve = true)
}
ChannelKind enum values: WEB, APP, PHONE, EMAIL, IN_PERSON, MAIL, SOCIAL, CHAT, OTHER.
ActorRole enum values: CUSTOMER, STAFF, SYSTEM, PARTNER.
Sentiment enum values: VERY_NEGATIVE, NEGATIVE, NEUTRAL, POSITIVE, VERY_POSITIVE.
CLI usage
# render to SVG (default)
kuml render membership-journey.kuml.kts
# render to PNG
kuml render membership-journey.kuml.kts --format png
# validate DSL structure only (no render)
kuml validate membership-journey.kuml.kts
Output: an SVG swimlane diagram with the four layers as horizontal bands, phases as vertical columns, Sentiment colour coding, and dashed dividing lines.
Example — PdV membership journey
The following example models the end-to-end experience of a citizen joining the
Partei der Vernunft (PdV), from first contact on social media through the
"valley of tears" waiting period to full engagement. It is the canonical
Service-Blueprint example used across the kUML documentation (vault source:
03 Bereiche/kUML/Beispiele/33 Blueprint – PdV Mitglieder-Journey.md) and is
rendered live below — the SVG is regenerated from this exact source on every
handbook build, so diagram and DSL source can never drift apart.
The rendered SVG shows six columns (phases) across four horizontal layers, the
three dividing lines, touchpoint symbols with channel icons, and an emotion
curve that dips from NEUTRAL/POSITIVE into a NEGATIVE valley during the
Phase-4 waiting period and climbs back up to VERY_POSITIVE — the classic
"valley of tears" narrative of membership onboarding.
Render it yourself with:
kuml render pdv-membership-journey.kuml.kts --format svg
User journey diagram (simplified view)
When you only need the customer lane — no frontstage / backstage / support layers —
use journeyDiagram instead of blueprintDiagram. The DSL is the same blueprint {}
container; only the closing call differs.
journeyDiagram renders a single-row timeline: phase columns, customer steps,
touchpoint icons, and the optional emotion curve. It is lighter and fits well in a
one-pager or presentation slide.
The emotionCurve = true flag overlays a spline through the Sentiment values —
a quick visual summary of where in the journey friction is highest.
Diagram type summary
| Call | Diagram type | Shows |
|---|---|---|
|
|
All four layers + dividing lines + phases |
|
|
Customer lane only + phases + optional emotion curve |
Both calls live inside the same blueprint { } container, so you can have both
diagram types in one script — one file, two SVG outputs.
Where to go from here
-
Core concepts — rendering pipeline and metamodel.
-
Simulate — execute state machines extracted from blueprints.
-
Pepela Thermostat showcase — an embedded systems showcase using the behaviour runtime.