Use cases

Same steps. Different tables.

Krusgraph turns tables without declared keys into an explained graph, then into what people actually use.

It reads table and column names, works out the keys and links, and gives every one the rule that produced it. You check the plan against the rows, then create what you need. The steps are the same in every industry; what differs is the tables.

  1. 1Tablesno declared keys
  2. 2Explained graphplan_backend, then validate_plan
  3. 3What people use
    • GraphQL APIan API for GraphQL item in your workspace, for an app or for questions in Claude
    • Fabric IQ ontology draftentity types, keys and relationships (preview)
    • Semantic modelfor Power BIplanned
    • SQL viewsfor the joins a rule cannot expressplanned
    • Data agentthat answers over the same modelplanned

Ten industries

Each one has the same four parts: typical tables, what Krusgraph finds in them, what you build, and where the value is.

Retail & e-commerce

Who bought what, on which order line, and what came back.

Typical tables

From names alone, as the engine plans them: 6 tables, 6 with keys, 6 relationships
  • customers

    • customer_idkey · K2
    • email
    • country
    • created_at
  • orders

    • order_idkey · K2
    • customer_id customers R1
    • order_date
    • status
  • order_lines

    • order_idkey · K5
    • line_nokey · K5
    • product_id products R1
    • quantity
    • unit_price
  • products

    • product_idkey · K2
    • sku
    • category_id categories R1
    • list_price
  • categories

    • category_idkey · K2
    • parent_category_id categories? confirm
    • name
  • returns

    • return_idkey · K2
    • order_id orders R1
    • line_no
    • reason

    order_id + line_no order_lines R3

What Krusgraph finds

  • R1orders.customer_id → customers: the column is named after the table. The same rule links order_lines.product_id → products and products.category_id → categories.
  • K5order_lines has no key column of its own. The line rule (K5) takes the reference to its header plus the line number, order_id + line_no, and returns.order_id + line_no → order_lines follows by R3.
  • to confirmcategories.parent_category_id points back at its own table, and no rule links a table to itself by name. Confirm it once and the API gets a parent_category field.

What you build

  • A returns desk in Lovable over the GraphQL API: an order, its lines and products, and what came back, in one nested query.
  • Questions in Claude through query_graphql, such as which categories see the most returns.
  • A Power BI semantic model from the same keys (planned).

Where the value is

  • A working read API over the order tables as soon as the plan is accepted, without writing a schema by hand.
  • The line-level key is stated once, so returns are not joined to whole orders and counted once per line.
  • Every link carries its rule. That is the documentation when the data moves to another team.

Back to the industries

Manufacturing

Work orders on machines, what they make, what goes into it, and whether it passed.

Typical tables

From names alone, as the engine plans them: 5 tables, 5 with keys, 5 relationships
  • items

    • item_nokey · K2
    • description
    • unit
    • item_type
  • bill_of_materials

    • parent_item_nokey · K4
    • component_item_nokey · K4
    • quantity
  • work_orders

    • work_order_idkey · K2
    • item_no items R1
    • machine_id machines R1
    • planned_start
    • status
  • machines

    • machine_idkey · K2
    • line_name
    • model
  • quality_checks

    • quality_check_idkey · K2
    • work_order_id work_orders R1
    • checked_at
    • result

What Krusgraph finds

  • R1items gets item_no as its key (K2 also reads _no), and work_orders.item_no → items follows. work_orders.machine_id → machines and quality_checks.work_order_id → work_orders the same way.
  • R4bill_of_materials points at items twice, through parent_item_no and component_item_no. Both are linked by R4, the weaker rule for a role in front of a table's name, as parent_item and component_item fields. Check them before you build.
  • K4bill_of_materials has no key column and starts with those two references, so the junction rule (K4) makes parent_item_no + component_item_no its key. validate_plan counts duplicates and NULLs in it before anything is built.

What you build

  • A shop-floor app over GraphQL: a work order with its item, machine and quality checks.
  • One level of a bill of materials per query. A full explosion is recursive, and that stays a SQL job.
  • Questions in Claude, such as which machines had failed checks last week.

Where the value is

  • The two-way bill of materials is a classic wrong join. Both roles carry the weaker rule, so they get reviewed instead of assumed.
  • A first backend over exported production tables, with no keys declared in the lakehouse.
  • The rules and confirmations are the handover note: the next person sees why each link exists.

Back to the industries

SaaS & subscriptions

Accounts on plans, invoices with lines, and a stream of usage events.

Typical tables

From names alone, as the engine plans them: 6 tables, 5 with keys, 7 relationships
  • accounts

    • account_idkey · K2
    • name
    • owner_email
    • created_at
  • plans

    • plan_idkey · K2
    • name
    • monthly_price
  • subscriptions

    • subscription_idkey · K2
    • account_id accounts R1
    • plan_id plans R1
    • billing_account_id accounts R4
    • started_at
  • invoices

    • invoice_idkey · K2
    • account_id accounts R1
    • subscription_id subscriptions R1
    • issued_at
    • total
  • invoice_lines

    • invoice_idkey · K5
    • line_nokey · K5
    • description
    • amount
  • usage_events

    • event_id
    • subscription_id subscriptions R1
    • event_type
    • occurred_at

    no key · K3

What Krusgraph finds

  • R1subscriptions.account_id → accounts and subscriptions.plan_id → plans; invoices.subscription_id → subscriptions as well.
  • R4subscriptions.billing_account_id → accounts by R4, the weaker rule for a role in front of a table's name, as a billing_account field. Probably right, for example a parent company paying for a subsidiary, but only you know: check it, or confirm another target.
  • K5invoice_lines gets invoice_id + line_no by the line rule (K5). usage_events has event_id, which is not named after the table, so it gets no key (K3). It still points at subscriptions, but nothing can point at it until you give the key (K1).

What you build

  • A self-service billing page in Lovable: an account, its subscriptions, invoices and invoice lines.
  • Usage per plan, asked in Claude and answered through the API without writing SQL.
  • A semantic model for revenue reporting from the same keys (planned).

Where the value is

  • The using account and the paying account are kept apart from the start, not discovered in a wrong revenue figure later.
  • Time to a first working API is the time it takes to read and accept a plan.
  • The plan doubles as a data dictionary for new engineers.

Back to the industries

Professional services

Clients, projects, consultants, and the hours that end up on invoices.

Typical tables

From names alone, as the engine plans them: 5 tables, 5 with keys, 6 relationships
  • clients

    • client_idkey · K2
    • name
    • sector
  • consultants

    • consultant_idkey · K2
    • name
    • grade
    • manager_id consultants? confirm
  • projects

    • project_idkey · K2
    • client_id clients R1
    • lead_consultant_id consultants R4
    • name
  • time_entries

    • time_entry_idkey · K2
    • consultant_id consultants R1
    • project_id projects R1
    • work_date
    • hours
    • invoice_id invoices R1
  • invoices

    • invoice_idkey · K2
    • client_id clients R1
    • issued_at
    • amount

What Krusgraph finds

  • R1time_entries.project_id → projects, time_entries.consultant_id → consultants and time_entries.invoice_id → invoices. An empty invoice_id is an unbilled hour: validate_plan counts rows with a value and orphans separately.
  • R4projects.lead_consultant_id → consultants by R4, a role in front of the table's name, as a lead_consultant field. consultants.manager_id names no table at all, so it stays unlinked until you confirm it; then it is manager.
  • K2Every table here has a key by name (client_id, project_id, time_entry_id, …), so the API can fetch any single row by its key.

What you build

  • A utilisation app: hours per consultant and project, with the client one level up.
  • Questions in Claude, such as which projects have hours that are not invoiced yet.
  • A Fabric IQ ontology draft (preview) with Client, Project, Consultant and Time entry entity types.

Where the value is

  • Hours to invoices is the join that decides revenue. Its rule and its orphan count are visible before anything is built.
  • A backend for an internal tool without a modelling project first.
  • A new controller reads the plan instead of reverse-engineering old reports.

Back to the industries

Financial services: AML

Anti-money laundering: customers, the accounts they hold, transactions, counterparties, alerts and KYC reviews.

Typical tables

From names alone, as the engine plans them: 7 tables, 7 with keys, 8 relationships
  • customers

    • customer_idkey · K2
    • name
    • country
    • risk_rating
  • accounts

    • account_idkey · K2
    • product_type
    • opened_at
    • status
  • account_holders

    • customer_idkey · K4
    • account_idkey · K4
    • holder_role
    • since
  • transactions

    • transaction_idkey · K2
    • account_id accounts R1
    • counterparty_id counterparties R1
    • beneficiary_account_id accounts R4
    • amount
    • booked_at
  • counterparties

    • counterparty_idkey · K2
    • name
    • country
    • bank_code
  • alerts

    • alert_idkey · K2
    • transaction_id transactions R1
    • customer_id customers R1
    • scenario
    • raised_at
  • kyc_reviews

    • kyc_review_idkey · K2
    • customer_id customers R1
    • reviewed_at
    • outcome

What Krusgraph finds

  • R1transactions.account_id → accounts, transactions.counterparty_id → counterparties and alerts.transaction_id → transactions.
  • K4account_holders is a bridge with two outgoing references: account_holders.customer_id → customers and account_holders.account_id → accounts, both R1. The junction rule (K4) makes customer_id + account_id its key: one row per holding.
  • R4transactions.beneficiary_account_id → accounts by R4, the weaker rule for a role in front of a table's name, as a beneficiary_account field. The plan says which rule made it, so it is checked rather than trusted.

What you build

  • One explained model that investigators and an agent in Claude query the same way.
  • Questions such as all transactions between accounts held by the same customer in the last 90 days: one nested GraphQL query from customer through account_holders, accounts and transactions to the beneficiary account, with the rule or confirmation behind each step.
  • A read-only investigation app in Lovable over the same API.

Where the value is

  • Fewer wrong joins in investigations: the bridge and the beneficiary are each stated once, with their rules.
  • A documented model for model-risk and audit review: every link has a rule or a recorded confirmation, and validate_plan counts orphans before anyone relies on it.

Back to the industries

Financial crime prevention

Fraud, sanctions screening and KYC: alerts and cases from teams that usually keep separate tables.

Typical tables

From names alone, as the engine plans them: 7 tables, 6 with keys, 6 relationships
  • customers

    • customer_idkey · K2
    • name
    • onboarded_at
  • cases

    • case_idkey · K2
    • customer_id customers R1
    • linked_case_id cases? confirm
    • case_type
    • status
  • alerts

    • alert_idkey · K2
    • case_id cases R1
    • customer_id customers R1
    • source_system
    • raised_at
  • screening_hits

    • screening_hit_idkey · K2
    • customer_id customers R1
    • list_entry_id
    • match_score
  • sanctions_lists

    • list_entry_id
    • list_name
    • entry_name
    • published_at

    no key · K3

  • devices

    • device_idkey · K2
    • fingerprint
    • first_seen
  • logins

    • login_idkey · K2
    • customer_id customers R1
    • device_id devices R1
    • ip_address
    • logged_in_at

What Krusgraph finds

  • R1logins.device_id → devices, logins.customer_id → customers and alerts.case_id → cases: fraud signals, alerts and cases meet at the customer.
  • R2sanctions_lists has one row per list entry, keyed by list_entry_id, which no key rule reads (K3). Give it as the key (K1) and screening_hits.list_entry_id → sanctions_lists follows by R2.
  • to confirmcases.linked_case_id ties a case to an earlier one. It points back at its own table, which no rule links by name, so you confirm it; then each case has a linked_case field.

What you build

  • One connected view for fraud, sanctions and AML analysts: a customer with cases, alerts, screening hits and logins.
  • Questions in Claude, such as which customers with an open screening hit also have a fraud alert this month.
  • A Fabric IQ ontology draft (preview) as a shared vocabulary across the teams.

Where the value is

  • Teams that work in separate tables share one model and see the same joins.
  • Explained links are defensible to auditors: each one says which rule made it, or that someone confirmed it.
  • validate_plan shows orphans, such as screening hits for customers missing from customers, first.

Back to the industries

Pharmaceutical research

Clinical studies and lab work: subjects at sites, visits, adverse events, compounds and assay results.

Typical tables

From names alone, as the engine plans them: 8 tables, 8 with keys, 9 relationships
  • studies

    • study_idkey · K2
    • compound_id compounds R1
    • phase
    • start_date
  • sites

    • site_idkey · K2
    • country
    • investigator
  • subjects

    • subject_idkey · K2
    • study_id studies R1
    • site_id sites R1
    • arm_code
    • enrolled_at
  • visits

    • subject_id subjects R1
    • visit_nokey · K2
    • visit_date
    • visit_type
  • adverse_events

    • adverse_event_idkey · K2
    • subject_id subjects R1
    • visit_no visits R1
    • severity_code
    • meddra_code
  • compounds

    • compound_idkey · K2
    • code_name
    • modality
  • assays

    • assay_idkey · K2
    • assay_type
    • unit
  • results

    • result_idkey · K2
    • assay_id assays R1
    • subject_id subjects R1
    • visit_no visits R1
    • value

What Krusgraph finds

  • R1visits.subject_id → subjects, results.assay_id → assays, subjects.site_id → sites and studies.compound_id → compounds.
  • K1From names alone, visits gets visit_no as its key (K2) and results.visit_no → visits (R1). Both are wrong: visit numbers repeat per subject, and validate_plan shows the duplicates. The engine does not suggest the fix here; you give subject_id + visit_no (K1). The single-column links go, and results and adverse_events reach visits by R3 on both columns.
  • to confirmCoded columns such as adverse_events.severity_code, adverse_events.meddra_code and subjects.arm_code point at code lists. No rule links them and nothing is guessed: add the code-list tables, or confirm each link.

What you build

  • An agent in Claude that answers research questions through the explained plan, such as which compounds had adverse events at more than one site.
  • A study overview app: a subject with visits, results and adverse events.
  • A semantic model for study reporting (planned).

Where the value is

  • Fewer confident-but-wrong joins: the visit key above is that kind of mistake, caught before an answer depends on it.
  • Orphans are counted first: results without an assay, adverse events without a visit.
  • Regulated use, such as GxP work, needs the organisation's own validation; Krusgraph does not provide it.

Back to the industries

Environment & sustainability

Sites, energy meters and readings, activities with emission factors, and purchases from suppliers (Scope 3).

Typical tables

From names alone, as the engine plans them: 7 tables, 6 with keys, 6 relationships
  • sites

    • site_idkey · K2
    • name
    • region
  • meters

    • meter_idkey · K2
    • site_id sites R1
    • energy_type
  • meter_readings

    • meter_id meters R1
    • read_at
    • value_kwh

    no key · K3

  • activities

    • activity_idkey · K2
    • site_id sites R1
    • emission_factor_id emission_factors R1
    • activity_type
    • quantity
    • period_start
  • emission_factors

    • emission_factor_idkey · K2
    • activity_type
    • valid_from
    • kg_co2e_per_unit
  • suppliers

    • supplier_idkey · K2
    • name
    • country
  • purchases

    • purchase_idkey · K2
    • supplier_id suppliers R1
    • site_id sites R1
    • spend_category
    • amount
    • purchased_at

What Krusgraph finds

  • R1activities.emission_factor_id → emission_factors: the factor behind each activity is an explained join. meters.site_id → sites and meter_readings.meter_id → meters as well.
  • R1purchases.supplier_id → suppliers and purchases.site_id → sites, for spend-based Scope 3 per site and supplier.
  • K3meter_readings has no key, which is fine for rows that are read, not pointed at. Where a factor is picked by activity type and date range instead of an id, that is not a key relationship: Krusgraph does not infer it, and it belongs in a SQL view.

What you build

  • A site app over GraphQL: a site with its meters, activities and purchases.
  • Questions in Claude, such as emissions per site and quarter with the factor behind each figure.
  • SQL views for date-range factor matching (planned); until then, those are written by hand.

Where the value is

  • Traceable numbers for sustainability reporting: every figure has a path back to its source tables, and every step has a rule.
  • Each activity points at the factor row it used, so a changed factor shows up as a changed link.
  • It documents joins. It does not make a report meet any reporting standard.

Back to the industries

Property & real estate

Properties split into units, leased to tenants, with maintenance requests.

Typical tables

From names alone, as the engine plans them: 5 tables, 5 with keys, 5 relationships
  • properties

    • property_idkey · K2
    • address
    • city
  • units

    • unit_idkey · K2
    • property_id properties R1
    • floor
    • area_m2
  • tenants

    • tenant_idkey · K2
    • name
    • contact_email
  • leases

    • lease_idkey · K2
    • unit_id units R1
    • tenant_id tenants R1
    • start_date
    • monthly_rent
  • maintenance_requests

    • maintenance_request_idkey · K2
    • unit_id units R1
    • reported_by_tenant_id tenants R4
    • status
    • opened_at

What Krusgraph finds

  • R1units.property_id → properties (the plural is understood), leases.unit_id → units and leases.tenant_id → tenants.
  • R4maintenance_requests.reported_by_tenant_id → tenants by R4, a role in front of the table's name, as a reported_by_tenant field. Check it before you build.
  • K2All five tables have a key by name, so the API can fetch any unit, lease or request by its key.

What you build

  • A caretaker app in Lovable: a unit with its lease, tenant and open requests. Creating requests from the app needs a warehouse or SQL database source; lakehouse sources are read-only through the API.
  • Questions in Claude, such as which properties have the most open requests per unit.
  • A Fabric IQ ontology draft (preview) with Property, Unit, Lease and Tenant entity types.

Where the value is

  • A first working backend for a property app without a modelling phase.
  • Tenant, lease and unit are joined once, so reports stop guessing which tenant belongs to which unit.
  • When the app changes hands, the plan explains every link.

Back to the industries

Education

Students enrolled in courses each term, taught by teachers, with grades.

Typical tables

From names alone, as the engine plans them: 5 tables, 5 with keys, 6 relationships
  • students

    • student_idkey · K2
    • name
    • cohort
  • teachers

    • teacher_idkey · K2
    • name
    • department
  • courses

    • course_idkey · K2
    • teacher_id teachers R1
    • title
    • credits
  • enrolments

    • student_idkey · K4
    • course_idkey · K4
    • term
    • enrolled_at
  • grades

    • grade_idkey · K2
    • student_id students R1
    • course_id courses R1
    • term
    • grade

    student_id + course_id enrolments R3

What Krusgraph finds

  • R1courses.teacher_id → teachers, enrolments.student_id → students and enrolments.course_id → courses.
  • K4enrolments has no key column and starts with two references, so the junction rule (K4) makes student_id + course_id its key, and grades reaches it by R3. If a student can retake a course in another term, that key is wrong, and validate_plan shows the duplicates.
  • K1Give student_id + course_id + term (K1). Then grades.student_id + course_id + term → enrolments follows by R3 on all three columns.

What you build

  • A course overview app: a course, its teacher and the students enrolled this term.
  • Questions in Claude, such as grades per course and term.
  • A semantic model for term reports from the same keys (planned).

Where the value is

  • A three-column key is easy to half-write in a join and then double-count. Stating it once avoids that.
  • A working API for a course tool without declaring keys in the lakehouse first.
  • Documentation for next term's administrator, generated with the API.

Back to the industries

For Fabric consultancies

The same engine runs on every client's tables, so the first conversation can start from their own schema instead of a slide. The rules and the plan are open source, and every key and link says why it is there, which makes a review with the client's data owners short and concrete.

To discuss a pilot, write to hello@krusgraph.com.

Scenarios are illustrative; they describe how the tool works on typical table designs, not customer projects.