Skip to content

The platform model — industry × archetype × primitives × grants ​

The four-layer model that ADR-0020 to ADR-0025 design, in the compact form the operating manual carried. The ADRs are the decision records (most are 🟡 Proposed, read as approved-pending and being built to); this page is the summary a reader needs before touching industries, archetypes, primitives, grants, the workspace tree or campaigns. The single index of what is decided, built and open remains Current architecture state — read its date first.

Read before changing anything in this model

  1. This page · 2. ADR-0020 (baseline) ·
  2. ADR-0021 (three axes) · 4. ADR-0022/0023/0024 (tree, sharing, RBAC) · 5. ADR-0025 · 6. Capability classification. Never branch on archetype, industry or plan in app code — ask for a feature (ADR-0021 D4; not lint-gated, QRS-879). A new primitive needs a written justification that it serves ≥ 3 industries (QRS-391). Your plan must answer: which of the three axes does the change touch, and is the default derived or a sparse grant?

The four layers ​

Provenance — moved from CLAUDE.md on 2026-09-23 (QRS-1288)

This is the verbatim text of CLAUDE.md § "The platform model: industry × archetype × primitives × grants" as of commit 00c1eca, relocated here under the context-architecture programme. Sentences of the form "this said X until [date]" are corrections recorded at the time they were made; the live rule is the corrected one. Retired vocabulary inside those corrections names what was retired and is not a live claim.

The platform model: industry × archetype × primitives × grants [ADR-0020..0025, designed 2026-08-07/08] ​

⚠ This section was rewritten 2026-08-08 and SUPERSEDES the previous "Verticals, archetypes & capabilities" text. The old model (5 archetypes · integer business_domain_id · capabilities/get_my_capabilities) is retired by ADR-0020/0021 and survives only as the S1 code still in apps/mobile, which is scheduled for replacement. Nothing below is built yet — it is the approved-pending design the new Dev baseline implements. Authoritative detail: architecture/current-state.md.

Four layers. The cost of the platform is O(primitives), not O(industries).

INDUSTRY  (open set — a row, free to add)
   ↓ declares
ARCHETYPE (what you sell)   ×   PRIMITIVES (how you run)
   ↓ resolved through
GRANTS    (8 scopes × 3 axes, SPARSE deviations only)
  • Industry — one industries row, stable TEXT key ('dairy', 'salon'), never an integer. Integer ids promoted across environments caused QRS-249; a text key makes that hazard class unrepresentable.
  • Archetype — THREE, not five: Goods (a stocked item) · Time (a slot) · Expertise (an enquiry). ecommerce_cart and catalog_informational were compositions, not archetypes (QRS-392).
  • Primitives — the closed set that carries all the cost. Eleven: Catalogue · Party · Schedule · Recurrence · Fulfilment · Ledger · Balance · Location · Resource · Asset · Campaign. A new primitive requires a written justification that it serves ≥3 industries — this is the governing gate of the whole architecture (QRS-391).
  • Grants — one feature_grants table, 8 scopes × 3 axes (applicability = does this apply · entitlement = is it unlocked and how much · availability = is it shipped). effective = all three.

Applicability DEFAULTS are DERIVED from primitive composition; grants hold only sparse deviations (ADR-0021). Dairy's composition includes Recurrence ⇒ Recurrence-backed features apply. Boutique's omits it ⇒ they don't. Zero admin action. Never build a dense industry × feature matrix — ~30 × ~40 = 1,200 cells nobody maintains.

Three distinctions that must never blur:

  • Applicability ≠ entitlement. Does the workflow apply at all (structural) vs is it unlocked and capped (commercial). A free-tier cafe has orders and is capped.
  • Feature grant ≠ RBAC permission. Is this workflow available vs can this role do this action on it (ADR-0024). "Agents may view stock but not edit prices" is RBAC.
  • Archetype ≠ industry. Archetype = what you sell; industry = who you are. Dairy and boutique are both Goods and differ only in composition — which is exactly why archetype-only gating fails.

Never branch on archetype, industry or plan in app code (ADR-0021 D4). Ask for a feature. ⚠ It is NOT lint-gated, and this said "lint-gated" until 2026-08-28 — archetype has zero occurrences in tooling/eslint-config/. The only thing preventing if (industry === "car_sales") today is discipline (QRS-879). A screen containing if (archetype === 'dairy') is the conditional sprawl the whole model exists to prevent, and it is the one item here that cannot be retrofitted.

Never hardcode an industry list in app code. onboarding/constants/domains.ts did exactly that and its invented ids disagreed with the database — 10 of 12 industry choices would have written the wrong industry (QRS-249).

Enterprise tree and campaigns ​

Provenance — moved from CLAUDE.md on 2026-09-23 (QRS-1288)

This is the verbatim text of CLAUDE.md § "Enterprise: organization → workspace TREE → members / Campaigns" as of commit 00c1eca, relocated here under the context-architecture programme. Sentences of the form "this said X until [date]" are corrections recorded at the time they were made; the live rule is the corrected one. Retired vocabulary inside those corrections names what was retired and is not a live claim.

Enterprise: organization → workspace TREE → members [ADR-0022/0023/0024] ​

  • The principal is a USER; the WORKSPACE is the business tenant. Membership count distinguishes the three user categories: consumer 0, solo owner 1 (member-owned), enterprise employee 1 (org-owned).
  • workspaces form a TREE within an organization — parent_id + a materialized path (depth cap 6). Not a fixed Org→Location→User hierarchy: depth genuinely varies (retail 2 levels, dealership 3+), and dealerships differ in organising principle (location-P&L vs division-P&L).
  • A LOCATION is not a business unit. If a place needs its own card and its own P&L it is a WORKSPACE; if it is only an address it is a LOCATION. A showroom is a workspace; a dairy's second collection point is a location.
  • SEATS LICENSE USERS, not workspaces (QRS-397). 8 showrooms + 30 agents = 39 cards but 30 seats. Workspace count is capped separately by an entitlement.
  • Sharing flows DOWN, oversight flows UP — two mechanisms, never symmetric. Sharing = ADR-0022 flags, default off, a child may use an ancestor's resources. Oversight = RBAC subtree scope, an ancestor may read (never write) descendants' data. ⚠ Oversight applies ONLY to org_owned descendants — an employee's personal business and consumer history must never be visible to their employer.
  • Place a resource at the LOWEST node all its legitimate consumers descend from. Customers at the showroom (so Sales↔Service joins by construction) · vehicle stock at Sales · brand assets at the root.
  • ownership_model (member_owned | org_owned) does three jobs: seat-revocation behaviour, who keeps the leads, and the oversight privacy boundary.

Campaigns [ADR-0025 — the Enterprise differentiator] ​

Centrally published, targeted, scheduled, measured offers rendered across many cards. Five of six pieces already exist (sharing · tree targeting · manifest block · analytics · time-bounding). Two rules:

  • A first-party offer is NOT the third-party promo_slot. The latter fails closed forever pending compliance_profile; conflating them either kills campaigns or opens a compliance exposure (ADR-0004).
  • ⚠ A campaign is the first RENDER-TIME temporal gate, and every prior decision kept those away from rendering because they break the edge cache. Answer: scheduled purge at campaign boundaries via the outbox — never a short TTL (contradicts QRS-381), never client-side (violates ADR-0019 Tier-0 and loses the OG image).