A guided studio for configuring onboarding forms per country — without touching JSON by hand.
Digital Onboarding Studio lets non-engineers safely author the base forms, country/channel patches, and journeys that the Digital Onboarding Service consumes — with a live customer-accurate preview, built-in validation, and every change emitted as a downloadable bundle that ships as a reviewable PR. It encodes the FormEngine's own rules so the tool can't produce config the backend would reject.
§1 Executive summary
Today, configuring onboarding forms for a country means hand-editing embedded JSON files that follow strict filename conventions, hand-writing RFC 6902 patch operations, and getting the naming/versioning exactly right — then rebuilding. It's powerful but error-prone and gated behind engineering. Digital Onboarding Studio turns that into a guided, visual, validated workflow.
What it does
Browse the form catalogue, edit base forms, author country & channel patches via visual diffs, build journeys, define validation, and preview the exact customer result — then download the change bundle.
Who uses it
Product/onboarding config authors (primary), reviewers/approvers (engineers or leads), and QA — with engineering owning the merge.
Why now
Expanding to new countries currently bottlenecks on engineers. The base+overlay model is already perfect for a tool — we just need a safe editor over it.
Design bet
The tool generates the filenames, JSON-Pointers, and patch ops. Authors think in fields, forms and rules — never in file paths or JSON pointers.
§2 Scope & non-goals
In scope (this initiative)
- Base forms — the
_schema.json+_ui.jsonpairs under SeedData/Forms/. - Patches — country and channel overlays under
SeedData/Patches/{CC}/(RFC 6902), for both Schema and UiConfig targets. - Journey configs — per-country
SeedData/JourneyConfig/{CC}.json: steps, branches, conditions, exit rules, workflow config. - Validation authoring — field constraints and the
x-crossFieldRulesexpression rules. - Live preview and bundle export for PR-based publishing.
Explicit non-goals (for now)
- Anything outside FormEngine config — no MDM, Documents, Onboarding runtime, or webhook management.
- Authoring C# — new named branch predicates (e.g.
isFatcaCountry) remain an engineering task; the tool only selects from registered predicates. - Editing live customer journeys/instances or any customer data. This tool configures; it does not operate.
- Translations content management — the tool works with i18n keys; it may surface missing keys but does not own the translation store (see Open decisions).
§3 Guiding principles (inherited from the backend)
The tool must be a faithful editor for the FormEngine's model — every rule the backend enforces, the tool enforces earlier and more visibly.
| Backend principle | How the tool honours it |
|---|---|
| Base + overlay (patches change only what differs) | Authors edit a base once; per-country changes are always expressed as patches, never as forked copies. The tool diffs base→desired and emits the minimal patch. |
| Configuration over code | Everything the tool produces is JSON seed data; no code generation, no engineering for standard changes. |
| Filename is the contract | The tool owns naming ({key}_base_v{n}_…, {key}_{cc}_v{n}_{channel}_{target}_patch.json). Authors never type a filename. |
| RFC 6902 patches | Patch ops are generated from a visual before/after diff; authors don't hand-write pointers or ops. |
Draft-07 schema + x- extensions | Schema editing is field-oriented; x-labelKey/x-enumLabels/x-errorMessages are first-class fields, not raw JSON. |
| Two-layer validation | Field constraints + x-crossFieldRules are edited and previewed with the same evaluation the backend uses (§6). |
| Channel precedence (base then channel, then version) | Preview replicates resolution order exactly; the tool shows which overlays applied. |
| Versioning & idempotent seeding | The tool guides "edit in place (non-prod) vs new version (prod)" and prevents accidental edits to already-published versions. |
| i18n keys, never literals | All human text is a key; the tool can flag keys not present in the translation source. |
§4 Decisions already taken
Persistence: downloadable bundle
The tool reads SeedData JSON and emits a zip of the changed files at their repository paths. A human copies them in and raises the PR. CI rebuild + startup seeding publishes. Zero backend write API, and no Git credential anywhere in the system.
Governance: ADO permissions + in-app
Who may change configuration is decided by Azure DevOps repo permissions and branch policies — already governed, already audited. The tool adds an in-app read-only review/diff so reviewers can vet a change set (visual diff + preview) alongside the PR.
Preview: backend-powered
Essential live preview via Option A — a read-only preview/resolve endpoint in FormEngine that reuses the real resolver/validator. We have the backend repo; use it (§6).
SPA: Angular 22+ · Tailwind
Angular v22 or higher, TypeScript throughout, styled with Tailwind CSS.
Design system
Use the components & tokens from the Global Tokens / Visual Language Figma design system. Tokens map into the Tailwind theme (§11).
Repos: split
Frontend lives in a separate repo (form-config-studio); the .NET BFF is a branch of this repo (feature/form-config-studio).
BFF: .NET, in this repo
The Config BFF is .NET, reusing the backend's FormEngine models, developed on a dedicated branch of this repo scoped to the config app (§5, §11).
i18n: keys + mapper
Author with i18n keys, plus a translation mapper. Store = a single JSON file, { "key": { "en": "…", "fr": "…" } } (§8, J9).
Targets: chosen at PR time
The bundle is target-agnostic — the same files apply to any branch. Which branch a change lands on is decided when the author opens the PR, and governed by ADO branch policy rather than by the tool.
Auth: open for now
v1 runs unauthenticated/open. The BFF is read-only and holds no credential, so an open endpoint exposes configuration already committed to the repo. Auth & roles are deferred — the design keeps a seam for OIDC/roles later (§13).
git push. The tool now emits a bundle and a human raises the PR; access control stays with ADO, where it already exists and is already audited. If we later need a path for authors without repo access, it will be an API that writes configuration directly — not a Git credential.§5 Architecture
Three moving parts: the Angular SPA, a thin read-only Config BFF (backend-for-frontend) that serves seed data and preview, and the existing FormEngine (touched only by a small read-only preview endpoint). Nothing in the system can write to the repository.
preview/resolve, persists nothingThe Config BFF#
Decision: the BFF is a .NET service that reuses the backend's FormEngine models and components, developed on a dedicated branch of this repo scoped to the config app. Because it lives in the same solution, it can reference the real JsonPatchEngine, FormResolver, ValidationEngine, and the ResourceNameParser directly — so patch application, resolution, validation, and filename parsing are the same code as production, not reimplementations. It's also the natural host for the read-only preview/resolve endpoint (§6). Responsibilities:
- Seed data read — list the catalogue and read base forms / patches / journey files. The seed files are
EmbeddedResources inOmniDos.FormEngine.Infra, so a deployed BFF serves them from its own assembly with no repository checkout on disk. - Patch generation — given a base document and the author's edited document, compute the minimal RFC 6902 op array (the artifact that becomes a
_patch.json). - Guardrails — enforce the naming contract, no-op detection, pointer existence, and version rules server-side (defense in depth beyond the SPA).
Environments#
The bundle is target-agnostic: the same files apply to any branch, so the author chooses the target when raising the PR (mirroring the existing pipeline's main/releases/*/pilot/releases/*). What the studio reads is per-environment — a BFF deployed alongside a service instance serves that instance's seed data, so the studio shows what that environment actually has. Non-prod targets may allow ClearBeforeSeeding edits-in-place; prod targets steer authors toward new versions (§ Journey J7).
§6 Preview & validation parity (the crux)
"Essential preview" only earns trust if what the author sees is exactly what the customer will get. That means the tool's resolution + validation must match the backend bit-for-bit.
Option A (chosen) — reuse the real components#
The BFF exposes a stateless, compute-only POST preview/resolve that accepts draft inputs (base schema+ui, the ordered patches, country, channel) and returns the resolved schema+ui plus validation results by invoking the real FormResolver, JsonPatchEngine and ValidationEngine — persisting nothing. Parity is guaranteed by construction, and nothing is stored, so it respects the Git/PR model.
FormResolver today loads the base version and patches from repositories and caches results. For draft preview we need to resolve from supplied base+patches with caching bypassed. Plan: extract a pure "apply ordered patches → schema/ui" core (already essentially ApplyPatches + OrderByPrecedence) that both the repository-backed resolver and the draft-preview path call. Low-risk, and it makes the resolver more testable too.get/form and post/validate-form actions already resolve/validate seeded config. The new endpoint is the same logic over unsaved draft input — the minimal, safe backend addition that de-risks the whole preview.Option B (deferred) — replicate resolution in TypeScript#
Not built for v1. If instant offline feedback ever justifies it, mirror the pipeline client-side (RFC 6902 apply, draft-07 validation, a TS port of the expression language) — but only behind a shared golden test-vector suite (inputs → expected output) run against both engines in CI, with Option A remaining the source of truth. For v1 we simply call the BFF, which is fast enough given it's in-process.
§7 Domain model inside the tool
The tool's internal model mirrors the backend entities so the mapping to files is mechanical.
| Tool concept | Backend artifact | Author edits… |
|---|---|---|
| Form (catalogue item) | FormDefinition + FormVersion | fields, constraints, UI layout, widgets — as a base |
| Country overlay | FormPatch (Schema + UiConfig) | a before/after that becomes a patch |
| Channel overlay | channel-tagged FormPatch | layout/widget tweaks for one channel |
| Journey | JourneyConfig/{CC}.json | steps, order, branches, conditions, exit rules, workflow config |
| Validation rule | schema constraints + x-crossFieldRules | field rules & cross-field expressions |
| Country workspace | a {CC}/ patch folder + {CC}.json | the full per-country bundle |
§8 Feature areas
Catalogue & country browser
List base forms and countries; see which forms a country patches, on which channels, and applied-patch counts. Entry point for everything.
Base form editor
Field-oriented schema editor (type, constraints, enum + labels, error keys) side-by-side with a raw-JSON escape hatch (Monaco). UI editor for layout (drag rows/columns) and widget mapping.
Patch author (visual diff)
Open a base for a country/channel, edit the resolved copy, and the tool computes the minimal RFC 6902 patch. Shows the generated ops read-only for transparency.
Journey builder
Visual step list + branch canvas: reorder steps, attach forms, define branch conditions (predicate/operator pickers), exit rules, and workflow config.
Cross-field rule builder
Guided builder for x-crossFieldRules expressions with field pickers, function palette, and an inline "does this pass?" tester against sample data.
Live preview
Country + channel selector renders the resolved form as the customer sees it; toggles show applied patches and i18n keys vs resolved sample text.
Validation panel
Live field + cross-field validation and a "lint" pass: naming contract, no-op patches, dangling pointers, missing i18n keys, version rules.
Translation mapper
Every human string is an i18n key. The mapper collects all keys used by a form/journey, shows coverage per language, lets authors fill/edit key→text, and flags missing keys before publish.
In-app review / diff
Reviewers open a change set read-only inside the tool — the same visual diff + live preview the author saw — alongside the Git PR.
Review & download
Review a human-readable change summary + file diff, then download the change bundle — the files at their repository paths, plus a ready-to-paste PR description.
Translation mapper — design note#
Forms and journeys reference i18n keys throughout — x-labelKey, x-placeholderKey, x-enumLabels, x-errorMessages, cross-field errorKey, step title, x-pageTitle. The mapper closes the loop between "I authored a key" and "the customer sees translated text."
- Key extraction — statically walk the resolved schema/uiSchema + journey to enumerate every key a country/channel actually uses.
- Coverage view — per language, show which keys have values and which are missing; block publish (or warn) on gaps.
- Authoring — edit key→text per language inline; the same PR flow ships the translation changes.
- Preview integration — the live preview can toggle between showing raw keys and resolved text using the mapper's values.
§9 UX principles & guardrails
Make the easy thing the safe thing
- Never expose the plumbing. No filenames, no JSON-Pointers, no raw
oparrays required. They're generated and shown read-only for the curious. - Diff-first. Country/channel changes are always shown as "base → your change," so authors reason about deltas, exactly like patches.
- Guided, not blank-page. New country = clone an existing one and adjust. New form = start from a template. Reduce every task to editing something that already works.
- Validate continuously. Inline errors as you type; a change can't be published while the lint panel has blocking issues.
- Preview is always one glance away. Split view: editor left, live customer preview right, channel switcher on top.
- Escape hatches for experts. Raw JSON / raw patch view is available, round-trips safely, and is reconciled with the visual model.
(FormKey, Version), the tool must detect when an author edits a base that's already published to the target and prompt: "bump to a new version" (prod) vs "edit in place / re-seed" (non-prod with ClearBeforeSeeding). This prevents the classic "my edit didn't show up" trap.§10 User journeys
The core deliverable of this plan. Each journey lists the actor, trigger, preconditions, the step-by-step flow, the artifacts produced (which files), and the guardrails that fire. Primary actor is the Config Author unless noted.
Stand up a new country (clone & adapt)
- Author clicks New country → picks code
TZand a clone source (KE). - The tool creates a TZ workspace: a copy of KE's journey as a starting draft, and an empty patch set (no overlays yet — TZ inherits base forms).
- Author walks the journey in the Journey builder, removing/reordering steps and adjusting branches/workflow config for TZ (see J5).
- For each form that must differ (e.g. ID types on
basic_info), author opens it in the Patch author and edits the resolved TZ copy; the tool records patches (see J2/J3). - Author adds/edits validation where TZ differs (see J4).
- Live preview is switched to
TZ+ each channel to confirm the end-to-end result. - Lint panel must be clean; author hits Publish → J8.
Artifacts: JourneyConfig/TZ.json + Patches/TZ/*.json (only where TZ differs). Guardrails: country-code uniqueness, journey references only existing form keys, naming auto-generated, no-op patches dropped.
Tweak a field for an existing country
- From the catalogue, author opens
basic_info→ context KE / all channels. The tool shows the resolved form (base + existing KE patches). - Author edits the
documentTypefield: adds theMAISHAenum value and itsx-enumLabelsi18n key — all via form controls. - The tool computes the minimal patch (a
replaceon/properties/documentType/enumand/x-enumLabels) and shows it read-only. - Preview updates instantly; validation confirms the enum/labels are consistent; lint confirms the i18n key exists (or flags it).
- Publish → J8.
Artifacts: creates/updates Patches/KE/basic_info_ke_v1_schema_patch.json. Guardrails: enum values ↔ enum-label keys kept in sync; patch stays minimal; base form untouched.
Add a channel-specific layout override
- Author opens
basic_info→ context KE / Web, switches the editor to the UI/layout tab. - Author drags fields into a two-column layout. The tool detects this is a channel change and scopes the patch to
web. - The generated patch targets UiConfig for the web channel only; preview on
Webshows two columns,Android/iOSunchanged. - Publish → J8.
Artifacts: Patches/KE/basic_info_ke_v1_web_ui_patch.json. Guardrails: channel token added to filename automatically; precedence explained in-UI (base overlay then channel overlay).
Add or edit a cross-field validation rule
- In the form's Validation tab, author clicks Add cross-field rule.
- Author builds the expression with field pickers + function palette:
!isNullOrEmpty(data.phoneNumber) || !isNullOrEmpty(data.email), and picks/creates anerrorKey. - The inline tester lets the author enter sample data and see pass/fail using the same evaluation as the backend (§6).
- The rule is written into
x-crossFieldRules(base form) or as a patch op if it's country/channel-specific. - Publish → J8.
Artifacts: base schema x-crossFieldRules entry, or a patch op (add /x-crossFieldRules/-). Guardrails: expression parsed & validated against the grammar before save; unknown functions/fields flagged.
Build or modify a journey
- Author opens the Journey builder for the country's journey (e.g.
retail_onboarding, version). - Author reorders/removes steps (each step = a form key + type: Form/Info/Review/Confirm/Consent) via drag-and-drop.
- Author adds a branch: sets
triggerAfterStep,resumeBeforeStep, a condition (pick a registered predicate likeisCrsCountry, or build an operator comparison on a source-step field), and the branch's steps. - Author adds exit rules on consent steps (e.g. terminate journey if consent declined).
- Author sets workflow config (
initiateAfterStepId,completeOnStepId,otpEnabled). - The builder validates references (every step's form exists; branch trigger/resume steps exist) and previews the flow. Publish → J8.
Artifacts: JourneyConfig/{CC}.json. Guardrails: only registered predicates selectable; dangling step references blocked; branch trigger/resume must be real steps.
id as its navigation identity and its formKey+formVersion as the form it renders — surfaced as separate fields so authors don't conflate them.Add a brand-new base form
- Author clicks New base form → names the key (
proof_of_income), starts at version 1, optionally from a template. - Author defines fields (schema) and layout/widgets (UI) in the base editor.
- Author references the new form from a journey step (J5) and optionally patches it per country (J2/J3).
- Lint flags any widget the renderer doesn't know and any missing i18n keys. Publish → J8.
Artifacts: Forms/proof_of_income_base_v1_schema.json + …_ui.json. Guardrails: widget catalogue check; key format check; version starts at 1.
Version a form safely
- Author edits a published base; the tool detects it's live on the target and offers Create version v+1.
- The tool clones the base to the next version, re-targets country patches to the new version, and offers to bump the journey step's
formVersion. - Preview confirms old vs new; publish → J8. Old cached/in-flight resolutions keep using the prior version.
Artifacts: new …_base_v2_*, re-versioned patches, updated journey step. Guardrails: blocks silent edits to already-seeded versions; explains idempotent-seeding behaviour.
Review & download (and roll back)
- Author opens Review & download: sees a plain-language summary ("KE · basic_info · added MAISHA ID type; web 2-column layout") plus the raw file diff.
- Download bundle emits a zip:
repo/(the changed files at their repository paths),PR.md(a filled-in PR description),manifest.json(data source + timestamp) andREADME.txt. - The author copies
repo/over a clone, commits to a branch, pushes, and opens the PR, pastingPR.mdas the description. - A Reviewer reviews the diff in the Git host (or an in-app read-only diff), approves, and merges. CI rebuild + startup seeding publishes.
- Rollback = revert the PR in git — a normal repository operation, with no tool involvement.
Artifacts: a zip containing only the changed SeedData files, plus the PR description and provenance stamp. Guardrails: can't download with blocking lint errors; PR.md auto-documents scope for the reviewer; manifest.json makes a bundle built on stale seed data identifiable.
Map translations for authored keys
- After editing (J2–J6), the author opens the Translation mapper for the change set.
- The tool extracts every i18n key the resolved config uses and shows a coverage grid (keys × languages), highlighting missing values.
- Author fills in text for each missing key per language; preview can render resolved text instead of keys to sanity-check.
- Lint blocks (or warns) on missing translations per the configured policy.
- Translation changes are bundled into the same PR as the config change (J8).
Artifacts: per-language key→value entries in the chosen translation store (v1 default: versioned JSON files in this repo). Guardrails: key coverage check; consistent key naming; no orphan translations.
Supporting / secondary journeys
- Preview across channels — switch country/channel and toggle "show i18n keys vs sample text" and "highlight applied patches."
- Compare countries — side-by-side of how two countries configure the same form (useful when cloning).
- Find usages — "which journeys/countries use this base form/version?" before versioning or editing.
- Reviewer read-only mode — open a PR's change set inside the tool with the same visual diff + preview the author saw.
§11 Tech stack & key libraries
| Concern | Choice | Notes |
|---|---|---|
| SPA | Angular v22+ + TypeScript | Scaffolded with @angular/cli@latest (must be ≥ 22). Standalone components, Angular signals (or a store if state grows) for editor/preview state. |
| Styling | Tailwind CSS | Utility-first; the design-system tokens are wired into the Tailwind theme (see below). Component styles compose tokens, not ad-hoc values. |
| Design system | Figma "Global Tokens / Visual Language" | Tokens (color, typography, spacing, radius, elevation) + components are the visual source of truth. Extracted to a tokens layer that feeds Tailwind (see "Design system & styling" below). |
| Raw JSON editing | Monaco editor | Schema-aware editing + the expert escape hatch, round-tripped with the visual model. |
| Schema-driven form render (preview) | A JSON-Schema form renderer | Must honour the x- extensions + layout/widgets. Likely a thin custom renderer matching the real frontend's widget set rather than an off-the-shelf one, for fidelity. |
| RFC 6902 patches | fast-json-patch (or equivalent) | Generate (diff) + apply (preview) patch ops in the BFF/SPA. |
| Schema validation | ajv (draft-07) | Client-side field validation; parity checked against backend. |
| Journey flow canvas | A graph/flow library | For the branch/step visualization. |
| Config BFF | .NET, in this repo (dedicated branch) | Reuses FormEngine models & components directly (patch engine, resolver, validators, name parser) and hosts the in-process preview/resolve. Same solution as the backend; scoped to the config app. |
| Git integration | None | Deliberately absent. The studio emits a zip; the author applies it to a clone and raises the PR with their own credentials. No Git client, no token, no write path. |
| Translations | Single JSON file | Shape: { "key": { "en": "…", "fr": "…" } } — each i18n key maps to a per-language string object. Versioned in the repo, shipped via the same PR. Mapper reads coverage + writes values. |
| Auth | None in v1 (open) | Unauthenticated on lower envs for now. Keep a clean seam (route guards + BFF auth middleware stubs) so OIDC/JWT + roles (Author/Reviewer/Admin) drop in later. |
Design system & styling#
The Global Tokens / Visual Language Figma file is the visual source of truth. The integration is token-driven so the UI stays faithful and themeable:
theme.extend reads the token variables- Tokens → Tailwind. Export the Figma tokens to a design-tokens JSON, generate CSS custom properties (e.g.
--color-primary,--space-4,--radius-md), and map them intailwind.configundertheme.extendso Tailwind utilities resolve to the design system's values. - Components. Rebuild the design system's components (buttons, inputs, selects, tabs, cards, dialogs, tables) as Angular standalone components styled with those Tailwind tokens — the studio's building blocks.
- Light/dark & theming. Because tokens are CSS variables, theme switches are variable swaps, not restyles.
@theme (src/styles.css) — see docs/DESIGN-TOKENS.md. Primary #A32A29, Open Sans (400/600), the 8-step size scale and 5-step line-height scale, and the elevation shadows are wired. To verify against Figma: the dark-mode primary tint, and the radius/spacing scales (not shown on the shared sheets — current radius values are provisional).§12 Phased roadmap
Sequenced to front-load value and de-risk the hardest correctness piece (patch generation + preview parity) first.
Phase 0 Foundations
Config BFF skeleton on a dedicated branch of this repo (reuses FormEngine models), Git-host integration (read repo, list catalogue), the in-process preview/resolve (with the small resolver-core refactor, §6), and the golden parity test-vector suite. Read-only catalogue browser in the SPA. Unauthenticated, lower-env target only.
Phase 1 · MVP Patch existing countries
Base form viewer + Patch author (visual diff → RFC 6902) for schema & UI, channel overrides, live preview, validation/lint, bundle download, and a first-cut in-app read-only diff/preview review (J2, J3, J8). Delivers safe, self-service tweaks/extensions to existing countries — the most frequent need.
Phase 2 New countries + translations
Journey builder (steps, branches, conditions, exit rules, workflow config) + clone-country workspace + cross-field rule builder + the translation mapper (J1, J4, J5, J9). Delivers end-to-end new-country configuration including key coverage.
Phase 3 Authoring depth & polish
New base-form authoring, versioning flow, full-fidelity reviewer mode, translation-store hardening, compare-countries/find-usages (J6, J7). Then wire the deferred auth & roles into the prepared seam, and open higher-environment targets.
§13 Risks & mitigations
| Risk | Impact | Mitigation |
|---|---|---|
| Preview/validation drifts from backend | Authors trust a preview that's wrong | Option A (reuse backend resolver) as source of truth; golden test vectors run against both engines in CI (§6). |
| Generated patches are brittle (pointer targets move) | Patch fails to apply after a base change | Regenerate patches against the current base on open; lint dangling pointers; preview applies patches so failures surface immediately. |
| Idempotent-seeding "my change didn't show up" | Confusion, duplicate effort | Version-aware guardrail (§9) + clear prod vs non-prod publish guidance (J7). |
| i18n keys authored but not translated | Blank/placeholder text in the live app | Missing-key detection against the translation source (Phase 3); flag before publish. |
| Rebuild latency (embedded resources) | Publish → live isn't instant | Set expectations in-UI (change is "merged", live after next deploy/seed); revisit DB-backed runtime config later if instant publish becomes a requirement. |
| Concurrent edits to the same country | Merge conflicts / clobbering | Branch-per-change + PR handles it via git; optionally soft-locks/"someone is editing" hints in the tool. |
| Widget added in config but not in the app | Broken render for customers | Widget-catalogue validation against the frontend's supported set (J6). |
| Open/unauthenticated tool (v1) | Anyone on the network can draft config & open PRs | Restrict to lower-environment targets only; PR-merge (human) remains the real gate to any environment; deploy behind internal network; keep the auth seam ready to switch on before any prod target. |
| Resolver-core refactor for draft preview | Regressing production form resolution | Extract a pure patch-apply core called by both paths; cover with the golden test vectors + existing FormEngine tests before/after the refactor. |
| Translations drift from config (missing store) | Keys authored with no home for values | Confirm the translation store (§14) early; mapper blocks/warns on missing keys and ships values in the same PR. |
§14 Decisions record & remaining input
Resolved#
| Question | Decision |
|---|---|
| Frontend stack | Angular v22+, TypeScript, Tailwind CSS. |
| Design system | Figma Global Tokens / Visual Language — components & tokens, wired into the Tailwind theme (§11). |
| Repositories | Split: frontend in a separate repo (form-config-studio); .NET BFF on branch feature/form-config-studio of this repo. |
| Config BFF stack | .NET, reusing backend models, on the dedicated branch of this repo. |
| i18n / translations | Keys + translation mapper; store is a single JSON file shaped { "key": { "en": "…", "fr": "…" } }. |
| Sample data | Maintain a small set of default per-form sample payloads for preview & the rule tester. |
| Preview approach | Option A — reuse the real components in-process via the BFF. |
| Reviewer experience | Both — Git PR review and in-app read-only diff/preview. |
| Environments | Lower environments only for v1; higher envs deferred. |
| Access model | Open / unauthenticated for now; auth & roles deferred with a seam kept. |
Remaining dependency (not a blocker to start)#
- Confirm two token values against Figma. The Equity Global Tokens are transcribed into
src/styles.css; only the dark-mode primary tint and the radius/spacing scales (absent from the shared sheets) need confirming. Names are stable, so it's a values-only drop-in.
form-config-studio Angular 22 + Tailwind repo with the tokens/translations/sample-data structure; (2) prepare the feature/form-config-studio branch for the .NET BFF (resolver-core refactor + preview/resolve); (3) turn this plan into a concrete backlog starting with the Phase 1 MVP.