|

Vape architecture and workflows

Keystone schema by domain, the go-live release gate, product publication, checkout evidence, fulfillment, safety stop, reporting, GraphQL operations, and access control.

Application surfaces

SurfaceLocationNotes
Storefrontapp/(storefront)/[countryCode]/**, features/storefrontAge gate, catalog, bag, checkout with compliance panel, account
Operator dashboardapp/dashboard/(admin)/platform/**, features/platformVape and retail workspaces inside the shared shell
Generic model pagesapp/dashboard/(admin)/[listKey]/**, features/dashboardKeystone list and item screens for lists without a dedicated page
GraphQL/api/graphqlKeystone CRUD (where access allows) plus custom queries and mutations
Other HTTP/api/payment-webhooks/[providerId], /api/oauth/*, /api/mcp-transport/[transport], /api/completionPayment webhooks, OAuth apps, MCP tools, dashboard AI chat

Schema by domain

Catalog. Product (status draft / proposed / published / rejected, regulatedCommerceRequired defaulting to true, exemption fields), ProductVariant (SKU, barcodes, inventory, one-to-one regulatedClassification), ProductImage, ProductOption, ProductOptionValue, ProductCategory, ProductCollection, ProductTag, ProductType, Measurement, StockMovement, Location.

Pricing and markets. MoneyAmount, PriceList, PriceSet, PriceRule, RuleType, CustomerGroup, Region, Country, Currency, TaxRate, TaxProvider, Discount, DiscountRule, DiscountCondition, GiftCard, GiftCardTransaction.

Carts, orders, and fulfillment. Cart, LineItem, LineItemAdjustment, ShippingMethod, Order (GraphQL create/update/delete disabled; changed only through custom mutations), OrderLineItem, OrderEvent, DraftOrder, Fulfillment, FulfillmentItem, ShippingLabel, Return, ReturnItem, Refund, ClaimOrder, ClaimItem, Swap, IdempotencyKey.

Payments and shipping. PaymentProvider, PaymentCollection, PaymentSession, Payment, Capture, ShippingProvider, ShippingOption, ShippingProfile, FulfillmentProvider.

Customers and accounts. User, Address, Role, Team, Invite, BusinessAccountRequest, Account, AccountLineItem, Invoice, InvoiceLineItem, UserField, Notification.

Regulated authority. Jurisdiction (draft → active → retired), RegulatedRuleSet (draft → approved → active → retired / emergency_disabled; signed policy hash, citations, validated rules JSON), RegulatedMerchantProfile (draft → review → active → suspended / revoked; PACT registration fields, launch jurisdictions, killSwitch defaulting to true), MerchantLicense, ProviderApproval (purpose identity, payment, tax, registry, or carrier; payment and carrier approvals bind to a PaymentProvider or ShippingProvider).

Product evidence. RegulatedProductClassification (one per variant: category, nicotine source and concentration, flavor, volume, marketing review) and ProductAuthorization (federal_marketing_order, preexisting_status, state_directory, local_directory).

Transaction evidence and ledger. AgeVerificationAttempt, RegulatedTaxQuote, CarrierEligibilityDecision, ComplianceDecision (immutable per-cart verdict with snapshot, expiring within five minutes), ComplianceEvent (append-only), ComplianceReportRun.

Platform. ApiKey, OAuthApp, OAuthToken, WebhookEndpoint, WebhookEvent, BatchJob, Note.

Evidence counts as current only between effectiveAt and expiresAt. Nothing expires records on a schedule; lapsed evidence stops counting when it is read. Once a regulated record reaches a usable state, its evidence fields are immutable (validateAuthorityRevision); it can only move to a terminal or suspended state, and a change needs a new revision.

Workflow: go live

regulatedCommerceReadiness reports blockers; releaseBlockers in features/regulated-commerce/core/release-gate.ts is the hard gate on every cart, payment, and checkout step.

  1. Store business details and all five policies saved in store settings, or the gate returns STORE_POLICIES_REQUIRED.
  2. One active RegulatedMerchantProfile with PACT registration reference and SHA-256 digest, origin jurisdiction, and bounded dates.
  3. The profile's kill switch turned off, or the gate returns KILL_SWITCH_ENABLED.
  4. At least one active launch Jurisdiction with authority sources.
  5. Verified MerchantLicense records where a rule set has a license_required rule.
  6. Exactly one active, approved, signed RegulatedRuleSet per destination.
  7. Active ProviderApproval records for identity, payment, tax, carrier, and registry.
  8. At least one approved classification with a current federal authorization.

Only when the gate returns no blockers is transactionMode enabled; otherwise checkout throws "Checkout isn't available for this store yet."

Workflow: product to publish

  1. Create the product as a draft (a regulated product cannot be created as published).
  2. Add options, variants, prices, images, and measurements.
  3. Classify each variant and approve the classification with a reviewer, digest, dates, and approved marketing review.
  4. Add an authorized federal ProductAuthorization (authorized needs lastVerifiedAt and a digest).
  5. Publish. assertProductPublicationEvidence requires evidence for every variant, or a current reviewed exemption.

After publishing, customer-facing copy and variant identity edits are refused. Swapping an image, or moving a classification or authorization out of a usable state, moves the product back to draft.

Workflow: checkout

  1. createActiveCart, then updateActiveCartLineItem / updateActiveCart; each variant must pass publication evidence, and every cart change revokes prior evidence and open decisions.
  2. Address resolves a destination jurisdiction such as US-CA.
  3. addActiveCartShippingMethod evaluates the cart and requires an allowed CarrierEligibilityDecision for that option.
  4. Age verification, committed tax quote, and carrier eligibility must be recorded for the same cart fingerprint (internal functions only; see limitations).
  5. Payment sessions (createActiveCartPaymentSessions, setActiveCartPaymentSession, initiatePaymentSession) need an active payment approval covering the destination and categories.
  6. evaluateActiveCartCompliance previews the decision; the storefront compliance panel shows readable reasons and keeps Place order disabled unless allowed.
  7. completeActiveCart persists a checkout ComplianceDecision, uses an IdempotencyKey, creates the Order, line items, and payment, and binds the evidence to the order.

Workflow: fulfillment, returns, and orders

  • getRatesForOrder returns only the exact approved carrier rate for regulated orders; createProviderShippingLabel needs an allowing fulfillment decision and order-bound adult-signature carrier evidence. Manual createOrderFulfillment is refused for regulated orders.
  • cancelShippingLabel must precede cancelOrderFulfillment; trackShipment reads label status.
  • Orders move from pending to completed when every line is fulfilled. transitionOrderStatus cancels only fully refunded, unfulfilled orders.
  • processReturnRefund records the refund and a regulated.return_refunded event with reason TAX_AND_REPORTING_REVERSAL_REVIEW_REQUIRED, shown on the order page.

Workflow: safety stop and reporting

  • stopRegulatedCommerce(profileId, reason) (needs canOperateComplianceKillSwitch, reason 10 to 500 characters) turns the kill switch on, suspends the active profile, revokes open decisions and unbound carrier allows, and writes merchant.emergency_stop, in one transaction. Resuming is done on the merchant profile page.
  • exportComplianceInventory and generateComplianceReport (only evidence_inventory, period of 93 days at most) create ComplianceReportRun records; recordComplianceReportSubmission records a filing receipt as submitted, accepted, or rejected. A generated report is not a jurisdiction filing.

Custom GraphQL operations

Queries: activeCart, activeCartShippingOptions, activeCartPaymentProviders, activeCartRegion, getCustomerOrder, getCustomerOrders, getCustomerAccount, getCustomerAccounts, getUnpaidLineItemsByRegion, getInvoicePaymentSessions, activeInvoice, getCustomerPaidInvoices, getAnalytics, getFinanceClose, getMyPrivacyData, regulatedCommerceReadiness, evaluateActiveCartCompliance, getProductsSortedByPrice, redirectToInit.

Mutations: active-user and address mutations, active-cart mutations (create, update, line items, discounts, shipping method, payment sessions, completeActiveCart), initiatePaymentSession, handlePaymentProviderWebhook, adjustInventory, getRatesForOrder, validateShippingAddress, trackShipment, createProviderShippingLabel, cancelShippingLabel, createOrderFulfillment, cancelOrderFulfillment, transitionOrderStatus, invoice mutations, processReturnRefund, stopRegulatedCommerce, exportComplianceInventory, generateComplianceReport, recordComplianceReportSubmission, retryWebhookDeliveries, registerWebhookEndpoint, updatePrivacyPreferences, requestPrivacyAction.

Access control

Dashboard visibility is not the control. Every list and custom operation checks role permissions on the server.

  • Role checkbox permissions (features/keystone/models/fields.ts, features/keystone/access.ts) decide human sessions. API keys and OAuth tokens need both the credential scope and the owner's role permission.
  • managedComplianceAccess (authority and evidence lists): read with read or manage compliance, create and update with canManageCompliance, delete denied.
  • immutableComplianceAccess (ledger lists): read with compliance read; create, update, and delete denied and omitted from GraphQL. Only system code writes them.
  • Evidence digests are never readable; identity fields on AgeVerificationAttempt need canAccessIdentityEvidence. Updating killSwitch needs canOperateComplianceKillSwitch.

On this page