Composer · Configurable product experiences
Letting registry teams shape the product without letting them break it
Designing the navigation builder, dashboard and layout system, and announcements module — the three surfaces where registry teams configure what participants and staff actually see.
Approached with the Double Diamond

Overview
Registry administration answers one question — what is configured. These three modules answer a harder one: what does a participant or a site coordinator actually see when they log in? Navigation, dashboards, and announcements are the surfaces where registries genuinely need to differ. A rare-disease registry with three sites and a paediatric oncology registry with forty have different audiences, different priorities, and different things worth announcing. But every unit of flexibility is also a way to build something unusable — a navigation with no destinations, a dashboard of empty widgets, an announcement shown to the wrong audience. The design problem is drawing that line.
The governing principle
Configuration should offer controlled flexibility, not unlimited freedom
The tempting version of this work is a page builder — drag anything anywhere, and every registry gets exactly what it wants. It fails for a specific reason: the people configuring a registry are clinical and operational staff, not designers, and the cost of a bad layout lands on participants who have no way to fix it.
So each module offers a bounded set of decisions. Supported destinations rather than arbitrary links. Approved layouts rather than a blank canvas. Role visibility rather than hoping the right people see the right thing. The flexibility is real, and its edges are deliberate.
Choose from supported options
Destinations, widgets, and layouts come from a platform-defined set. Registries compose; they don't invent.
Preview before publish
Every configuration can be viewed as the role that will receive it, before anyone receives it.
Invalid states can't be saved
Duplicate entries, unavailable destinations, and empty required slots are caught at configuration time, not discovered in production.
Navigation builder
Registry teams needed flexibility without being able to create an unusable navigation
The navigation builder lets a registry decide what appears in the participant and staff navigation, in what order, under what label, and for which roles. The workflow: select an available destination → add it → set label and order → assign visibility → preview → publish.
The constraint that shaped it: navigation is the one surface where a configuration mistake is unrecoverable by the person affected. A participant who can't find consent has no workaround. So the builder shows unavailable destinations rather than hiding them, blocks duplicates, and requires the resulting structure to be previewed as each role before it can go live.

Accessibility was a specification requirement rather than a review step: keyboard reordering, focus management through the builder, and labels that remain meaningful to a screen reader after a registry has renamed them.
Dashboard & layout
Different registries needed different dashboards without fragmenting the platform
Dashboards are where the tension between registry-specific needs and platform consistency is sharpest. A registry wants recruitment progress, participant completion, or treatment status surfaced first — reasonable, and different per registry. The platform needs responsive behaviour, accessibility, and reusable components to hold regardless.
The resolution was a Registry → Page → Widget model with role- and site-resolved visibility. Administrators choose supported content modules, arrange them within defined layout rules, configure labels, assign role visibility, and preview by persona. What they cannot do is build an arbitrary interface — and that limit is the reason the result stays coherent across a hundred registries.
A shared widget contract
Card frame, title behaviour, loading, empty, error, and unknown-type states defined once, so one failing widget never takes down a page.
Curated data, not raw queries
Widgets bind to curated query keys rather than arbitrary SQL — configuration can't become a data-access hole.
Visibility equals access
The system never grants broader access than the experience it displays; every automatic claim grant is recorded and auditable.
Announcements
Important registry updates needed an in-product home instead of relying on email
Registry teams communicate constantly — a protocol amendment, a site going live, a scheduled outage — and were doing it entirely through email, which meant participants who don't reliably read email simply missed it.
Announcements gives that communication a place inside the product, with the properties that make it safe: an audience, a start and end date, a priority, a draft state before publication, and an archive afterwards. The design questions were mostly about time and audience rather than layout — who should see this, when should it appear, what happens when it expires, and can it be edited after publication.
Audience before content
The audience is selected before the message is written, so sensitive information is never drafted against the wrong recipients.
Time-bound by default
Start and end dates are part of creation, not an afterthought — announcements expire rather than accumulating.
Draft, publish, archive
A reviewable state before anything is visible, and a retrievable state after it stops being.
Urgent reads differently
Priority changes presentation, so an outage notice isn't styled identically to a newsletter.
Specification
Configuration surfaces need their edge cases written down
These modules generate more states than a typical feature, because every configuration choice multiplies against roles, sites, and publication status. I specified them as module PRDs rather than Figma files: the state a widget shows when its data source is unavailable, what a navigation item does when its destination is removed, what happens to a published announcement when its audience changes.
The MVP boundary was drawn explicitly. The widget framework ships; the widget composer stays future scope. Writing that line down mattered — technical flexibility has a way of quietly becoming product scope when nobody records the decision.

Reflection
Configuration design is where product judgment shows most clearly, because every decision is really a decision about who is trusted with what. Give too little flexibility and registries route around the platform with spreadsheets and email — which is exactly the problem the platform existed to solve. Give too much and the product fragments into a hundred inconsistent variants that nobody can support. What I'd carry forward: the useful question isn't how configurable something should be, but which specific decisions a registry team is genuinely better placed to make than the platform team. Navigation labels, dashboard priorities, and announcement timing are theirs. Layout rules, component behaviour, and access semantics are not.
Outcome
Three configuration surfaces
Navigation, dashboards, and announcements specified as governed modules rather than open builders.
A shared widget contract
One set of loading, empty, error, and unknown states reused across every dashboard widget.
Scope boundary held
Widget framework in MVP, widget composer deferred — recorded rather than assumed.