lumnik. / scenarios All scenarios · Français

A claim form's lists come from the CRM without exposing its GraphQL

Goal Feed a form's lists from a GraphQL CRM without the browser depending on the CRM's schema.

The claim type and subtype live in a CRM that speaks GraphQL. lumnik ingests it page by page into a canonical entity.

insurance-case-options.json
[
  {"id":"AUTO-COLLISION","typeCode":"AUTO","typeLabel":"Automobile","subtypeCode":"COLLISION","subtypeLabel":"Collision","typeOrder":10,"subtypeOrder":10,"active":true},
  {"id":"AUTO-GLASS","typeCode":"AUTO","typeLabel":"Automobile","subtypeCode":"GLASS_BREAKAGE","subtypeLabel":"Bris de glace","typeOrder":10,"subtypeOrder":20,"active":true},
  {"id":"AUTO-THEFT","typeCode":"AUTO","typeLabel":"Automobile","subtypeCode":"THEFT","subtypeLabel":"Vol du véhicule","typeOrder":10,"subtypeOrder":30,"active":true},
  {"id":"HOME-WATER","typeCode":"HOME","typeLabel":"Habitation","subtypeCode":"WATER_DAMAGE","subtypeLabel":"Dégât des eaux","typeOrder":20,"subtypeOrder":10,"active":true},
  {"id":"HOME-FIRE","typeCode":"HOME","typeLabel":"Habitation","subtypeCode":"FIRE","subtypeLabel":"Incendie","typeOrder":20,"subtypeOrder":20,"active":true},
  {"id":"HOME-BURGLARY","typeCode":"HOME","typeLabel":"Habitation","subtypeCode":"BURGLARY","subtypeLabel":"Cambriolage","typeOrder":20,"subtypeOrder":30,"active":true},
  {"id":"HEALTH-HOSPITAL","typeCode":"HEALTH","typeLabel":"Santé","subtypeCode":"HOSPITALISATION","subtypeLabel":"Hospitalisation","typeOrder":30,"subtypeOrder":10,"active":true},
  {"id":"HEALTH-DENTAL","typeCode":"HEALTH","typeLabel":"Santé","subtypeCode":"DENTAL_CARE","subtypeLabel":"Soins dentaires","typeOrder":30,"subtypeOrder":20,"active":true},
  {"id":"HOME-OLD-STORM","typeCode":"HOME","typeLabel":"Habitation","subtypeCode":"OLD_STORM_CODE","subtypeLabel":"Ancien code tempête","typeOrder":20,"subtypeOrder":90,"active":false}
]
manifests/20-insurance-case-option.yaml
kind: Entityname: ScenarioInsuranceCaseOptionBdescription: "An insurance claim type and subtype pair curated by the CRM."match: [option_id]scopes: [insurance]columns:  type_code:    label: "Claim type code"  type_label:    label: "Claim type"  subtype_code:    label: "Claim subtype code"  subtype_label:    label: "Claim subtype"  active:    label: "Available"sources:  - table: scenario_insurance_case_option_b    map:      option_id: option_id      type_code: type_code      type_label: type_label      subtype_code: subtype_code      subtype_label: subtype_label      type_order: type_order      subtype_order: subtype_order      active: active
GET /form-options/claim-types
AUTO Automobile · HOME Habitation · HEALTH Santé
… /AUTO/sub-types
COLLISION Collision · GLASS_BREAKAGE Bris de glace · THEFT Vol du véhicule
… /HOME/sub-types
WATER_DAMAGE Dégât des eaux · FIRE Incendie · BURGLARY Cambriolage

evidence: replay.log, 50-claim-types.json, 51-auto-subtypes.json, 52-home-subtypes.json, 53-unknown-type.json · transform v1

… /UNKNOWN/sub-types
404 · claim type not found

evidence: replay.log, 50-claim-types.json, 51-auto-subtypes.json, 52-home-subtypes.json, 53-unknown-type.json · transform v1

Limits

  • The CRM is synthetic but speaks the real request and Relay response shapes of lumnik's GraphQL connector.
  • The BFF is demonstration-sized: it calls lm on every request. A production BFF would call the hub API with its own identity and cache these lists.
  • The BFF only reads; creating the claim in the CRM is outside the scenario.
  • The rule is active == true; effective dates, per-language labels and per-product eligibility would be further business rules.
  • Synthetic data.

Insurance · form

A claim form has two lists.

The type, then the subtype.

Both live in a CRM that speaks GraphQL.

Synthetic CRM

The problem

The CRM's schema becomes the browser's contract.

  • The front end calls the CRM's GraphQL.
  • Every CRM change breaks the form.
  • A retired code can stay on offer.

Nothing is changed

The CRM keeps its GraphQL.

  • lumnik reads it page by page.
  • An entity carries stable names.
  • The form reads REST JSON.

What had to be written

kind: graphql
query: |
  query InsuranceCaseOptions($after: String) {

GraphQL is a request shape, not a connector.

A 78-line scenario, two declaration files.

What the policyholder sees

Car: three subtypes.

  • Collision.
  • Glass breakage.
  • Vehicle theft.

Real BFF answer, replay of 3 November 2026.

A list replaced

Home replaces the list.

  • Water damage, fire, burglary.
  • Collision never stays.
  • The retired code is not offered.

The limit

The BFF is demo-sized.

  • It calls lm on every request.
  • In production: the hub's API and a cache.
  • Creating the claim in the CRM is out of scope.

Try it

The scenario replays end to end.

GraphQL CRM, entity, BFF: every step is published with its output.

This scenario runs on lumnik Open, free and open source.

Try lumnik Open →