Skip to content

Align PlantUML entity includes with wikilink refs (<kind:name>) #307

@yumike

Description

@yumike

Problem

PlantUML entity includes today use C4-inspired pseudo-filenames that don't match anything else in the engine:

!include systems/sys_payment_gateway.iuml
!include systems/dmn_billing.iuml
!include systems/svc_invoice_api.iuml
!include systems/ext/sys_yookassa.iuml

For writers and reviewers, this path has several small frictions that compound:

  1. Everything lives under systems/ even when the entity is a domain or service — the directory lies about what it contains.
  2. Short C4 prefixes (dmn_ / sys_ / svc_) require mental decoding every time someone reads a diagram. The site itself uses the full words (domain, system) everywhere else.
  3. Name translation is hidden. A service directory called payment-gateway is referenced as payment_gateway — hyphen-to-underscore substitution that has no user-visible explanation.
  4. The kind vocabulary is narrower than the concept. service doesn't cover libraries, frontends, CLIs, or anything else Backstage treats as a component.
  5. Two incompatible ref dialects coexist in one repo. Wikilinks (introduced in 0.1.21) use stable, future-proof refs: [[domain:billing::overview]]. Diagrams use pseudo-filenames. Writers have to learn both.
  6. The external flag lives inside the path (ext/), not as an attribute. There's no room to express anything else about how an entity is referenced (deprecated, owned by another team, specific version) without inventing more directories.

These paths aren't files. The engine parses the string (see parse_include_path in crates/rw-diagrams/src/meta_includes.rs), looks up the entity in the live site registry, and emits a C4 macro. Writers and reviewers shouldn't have to pretend it's a filesystem path.

Proposal

Use angle-bracket refs that mirror the wikilink syntax:

!include <system:payments>
!include <domain:billing>
!include <component:payment-sdk>
!include <system:yookassa external>

Why angle brackets

PlantUML's stdlib already uses <…> for "resolvable identifier, not a file" (<C4/C4_Context>, <tupadr3/font-awesome/server>). Stdlib paths are slash-separated and never contain :, so <system:payments> is structurally unambiguous — the : is all the disambiguation the parser needs.

Why not load macros once via C4-PlantUML convention

The natural alternative would be:

!include <rw/entities>
$system(payments)
$system_ext(yookassa)

This doesn't fit rw's trajectory: the entity registry is expected to become large and distributed (fetched on demand from an rw hub). Preloading all entity macros upfront doesn't scale. Each !include <system:foo> is already a targeted lookup — angle brackets make that lookup semantics explicit, matching how PlantUML treats stdlib paths.

Symmetric with wikilinks

Doc side and diagram side share one vocabulary:

Surface Syntax
Markdown prose [[system:payments]], [[component:payment-sdk::api]]
Diagram (!include) <system:payments>, <component:payment-sdk>

Same kinds, same names, same mental model. No underscore substitution, no extension, no directory prefix.

Kind vocabulary: add component, deprecate service

Backstage treats component as the umbrella for services, libraries, frontends, and other software units. service is one of several Backstage spec.type values under component. Rename to match:

  • domain — unchanged
  • system — unchanged
  • component — new canonical kind, replaces service
  • service — accepted for one release as a deprecated alias, with a warning on load

This follows the existing precedent where type is accepted as an alias for kind (see crates/rw-storage/src/metadata.rs).

Modifiers (space-separated, extensible)

Variants live after the ref as whitespace-separated tokens:

!include <system:yookassa external>

Today external is the only modifier (it selects System_Ext instead of System). The shape leaves room to grow without new syntax:

!include <system:old-checkout deprecated>
!include <component:payment-sdk external version=v2>

Unknown modifiers would error at parse time with a clear message.

Migration

  • Old iuml paths keep working for one release, with a deprecation warning on use:
    systems/sys_foo.iuml, systems/dmn_foo.iuml, systems/svc_foo.iuml, and their systems/ext/… variants.
  • kind: service keeps working for one release, with a warning, treated as an alias for component.
  • Docs (docs/diagrams.md, docs/metadata.md) rewritten to lead with the new syntax; old syntax mentioned only in a "Migration" section.
  • CHANGELOG.md entries for both the new syntax and the kind rename.

Out of scope

  • URL path structure for pages (e.g., /domains/billing/systems/payments/services/invoice-api) — unchanged.
  • Wikilink syntax — unchanged (this proposal only brings diagrams into alignment with it).
  • PlantUML stdlib path handling — unchanged.
  • Actual !include <rw/entities> macro-library approach — rejected above; revisit only if the rw hub architecture stops making lookup-per-include viable.

Parser sketch

In resolve_includes (crates/rw-diagrams/src/plantuml.rs:45):

  • Strip < / >. If the body contains :, treat as an rw entity ref and dispatch to meta resolution.
  • Otherwise pass through as stdlib (existing behavior, unchanged).
  • In meta resolution: split on first whitespace into ref + modifiers, parse kind:name, look up via MetaIncludeSource, render the matching C4 macro with modifier-driven variant selection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions