Rules
Extract testable decisions
Move validation, eligibility and consent selection into small typed policies. Give each rule a focused test and a reason that can be shown in logs and support tooling.
Identity checks, consent decisions and analytics had to remain auditable while a UIKit flow moved into SwiftUI.
Inside the boundary
Onboarding & consent
The onboarding journey looked like a sequence of forms, but its real complexity lived in the decisions between them: eligibility, identity evidence, consent versions, retry rules and the analytics needed to explain where users stopped.
The new module owned those decisions and the state of the journey. Existing identity vendors, account creation APIs and the app-wide analytics transport stayed outside. That distinction let the team modernise presentation without duplicating regulated rules.
Inputs
Identity evidence, policy and API results
Owns
Journey state, decisions and tests
Outputs
Consent record and account request
Validation, network calls, tracking and navigation were mixed into view controllers. The same eligibility rule appeared in more than one screen, and error recovery depended on which callback happened to complete first.
This made compliance work difficult to review and UI work risky to estimate. A new consent version could require changes across presentation, persistence and analytics, while tests had to drive complete screens to prove one small decision. Moving directly to SwiftUI would only have hidden those rules in a newer view layer.
The team first described onboarding as states and decisions. Screens became consumers of that model rather than the place where eligibility and consent logic were decided.
Rules
Move validation, eligibility and consent selection into small typed policies. Give each rule a focused test and a reason that can be shown in logs and support tooling.
Bridge
Let UIKit and SwiftUI consume the same journey state and services. Keep analytics names stable so product teams can compare behaviour instead of stitching together two datasets.
Learn
Start with controlled groups, watch completion, validation failures and vendor errors, and preserve a server-controlled return to the existing path while confidence grows.
Once decisions lived behind the module boundary, the team could review regulated behaviour independently from visual changes and trace a failed journey to a named state rather than a chain of callbacks.
Auditable rulesEligibility and consent decisions gained explicit owners, focused tests and stable reason codes.
Replaceable UISwiftUI screens could evolve without copying logic from the UIKit path or changing service contracts.
Controlled exposureCohorts, shared analytics and a fallback path made each production step observable and reversible.
Illustrative module study. It blends recurring delivery patterns from similar projects and does not represent a named client claim.