{"entities":[{"name":"Actor","class":"Core","subsystem":"CONFIG","area":"Configuration","desc":"A platform identity that can own or consume resources, hold configurations, and appear in audit trails. Actors are split into two kinds: Standard actors (human-tied — associated to a User entity) and Service actors (system, service, or application identities with no User association). Actor is the canonical principal across the platform — services, audit logs, and tool-level RBAC reference Actor rather than User directly so that human and non-human principals can be authorized and attributed uniformly. Resolves to a User only when the Actor is Standard.","status":"draft","properties":[{"n":"actorId","r":true,"t":"string"},{"n":"actorType","r":true,"t":"enumeration","v":["Standard","Service"],"info":"Discriminates the kind of identity this Actor represents. Standard = human-tied; the Actor MUST be associated to a User via the user property. Service = system, service, or application identity; the Actor MUST NOT have a user value set. Service actors are how non-human principals (background workers, integration accounts, external system credentials) participate in audit trails and RBAC without polluting the User entity."},{"n":"name","r":true,"t":"string"},{"n":"user","t":"entityDetail","re":"User","info":"The human User this Actor represents. Populated only when actorType = Standard; must be null/absent when actorType = Service. Modeled as entityDetail rather than entityRef because both Actor and User are Company-scoped — the reference must respect the Company isolation boundary. Conditional-required relationship enforced via business validation rather than the property being unconditionally required."}],"service":"APR Config","shopify":"API client credentials / app installations","related":["Config","Secret","Environment","User"],"bv":{"rules":[{"rule":"user must be set when actorType is Standard — a Standard Actor represents a human and must resolve to a User entity","when":"always","field":"user","severity":"error"},{"rule":"user must be null/absent when actorType is Service — a Service Actor represents a non-human identity and must not be associated to a User","when":"always","field":"user","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Advanced Shipping Notice","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Advance Shipment Notice from a Vendor confirming goods in transit, broken into Cartons.","status":"stub","properties":[{"n":"asnId","r":true,"t":"string"},{"n":"cartons","r":true,"t":"array","re":"Advanced Shipping Notice Carton"},{"n":"eta","t":"datetime"},{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"}],"ext":"OperationalDocument","shopify":"EDI 856","related":["Purchase Order","Vendor","Advanced Shipping Notice Carton","Goods Receipt"],"bv":{"rules":[],"lifecycle":{"states":["Pending","Received","PartiallyReceived","Discrepant"],"transitions":[{"to":"Received","from":"Pending","conditions":["All items matched to receipt"]},{"to":"PartiallyReceived","from":"Pending","conditions":["Some items received"]},{"to":"Discrepant","from":"Pending","conditions":["Received quantities do not match ASN"]}],"initialState":"Pending"},"calculations":[],"crossEntityConstraints":[{"rule":"Should reference a valid Purchase Order for reconciliation","entity":"Purchase Order"}]}},{"name":"Advanced Shipping Notice Carton","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Individual carton within an ASN shipment, tracking packed items at the box level.","status":"stub","properties":[{"n":"asn","r":true,"t":"entityRef","re":"Advanced Shipping Notice"},{"n":"cartonId","r":true,"t":"string"},{"n":"cartonNo","t":"string"},{"n":"lines","r":true,"t":"array","info":"Array of AdvancedShippingNoticeLine sub-documents within this ASN carton."},{"n":"trackingNo","t":"string"},{"n":"weight","t":"decimal"}],"ext":"OperationalSubDocument","related":["Advanced Shipping Notice","Goods Receipt"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must belong to a valid ASN","entity":"Advanced Shipping Notice"}]}},{"name":"Application","class":"Core","subsystem":"ALLPOINT","area":"Organization","desc":"A registered application that interacts with the All Point platform. This covers both APR platform products (CONNECT, Fulcrum X, APR Config) and APR-developed apps for external platforms (e.g., APR's Shopify App, APR's NetSuite Integration App). Defines the product's capabilities and supported features. Applications exist in a global registry, independent of any Client or Company. They are deployed to Companies as Application Installations.","status":"draft","properties":[{"n":"applicationNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"description","t":"string"},{"n":"developer","r":true,"t":"enumeration","v":["all-point","3rd-party"],"info":"Who built the application. all-point (developed by APR) or 3rd-party (developed by a third party)"},{"n":"distribution","r":true,"t":"enumeration","v":["public","all-point","custom"],"info":"How the application is made available. public (publicly listed), all-point (internal to APR), custom (built for a specific company)"},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"name","r":true,"t":"string","u":true},{"n":"platform","r":true,"t":"enumeration","v":["all-point","shopify"],"info":"Where the application runs. all-point (runs on APR's platform) or shopify (runs on Shopify)"},{"n":"slug","r":true,"t":"string","u":true,"info":"Human-readable key (e.g., franchise-portal, shopify-app, netsuite-app). Globally unique"},{"n":"supportedFeatures","t":"array","info":"Feature capabilities this Application supports (e.g. 'inventory', 'orders', 'reporting'). Used to validate Application Configuration feature flags."},{"n":"type","r":true,"t":"enumeration","v":["web-application","service","embedded"],"info":"What the application is technically. web-application (Web/React app), service (microservice), embedded (embedded app)"}],"notes":"Canonical subsystem is PLATFORM. Currently registered under ALLPOINT pending subsystem reassignment — needs delete-and-recreate to move to PLATFORM.","related":["Application Installation","Connector"],"bv":{"rules":[{"rule":"Must be globally unique","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Deactivating an Application must revoke all associated Client tokens","entity":"Client"}]}},{"name":"Application Installation","class":"Core","subsystem":"CONNECT","area":"Organization","desc":"A Company-scoped installation of an Application. This is the entity created when an Application is actually deployed or installed for a specific Company — whether that's deploying Fulcrum X for a franchise group, installing APR's Shopify app on a merchant's Shopify store, or setting up API credentials for NetSuite. Application Installation holds the authenticated connection state: OAuth tokens, API keys, external account identifiers, and health status. It is the credentials and identity boundary — a single installation can be shared across multiple Connections.","status":"draft","properties":[{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"installationNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"application","r":true,"t":"entityRef","re":"Application","info":"The Application this is an installation of"},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this installation belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export."},{"n":"displayName","r":true,"t":"string","info":"Operator-facing label (e.g., Acme Shopify Store, Acme Fulcrum X)"},{"n":"status","r":true,"t":"enumeration","v":["pending_install","pending_auth","connected","error","disconnected","suspended"],"info":"Installation lifecycle status"},{"n":"credentials","r":true,"t":"encrypted","info":"OAuth tokens, API keys, secrets (encrypted at rest)"},{"n":"externalAccountId","t":"string","info":"Account/store/tenant ID on the external system (e.g., Shopify store ID, NetSuite account ID)"},{"n":"externalAccountUrl","t":"string","info":"URL to the account on the external system (e.g., acme.myshopify.com)"},{"n":"configuration","t":"schema","info":"Application-specific config (API version, sync preferences, feature toggles)"},{"n":"healthStatus","t":"enumeration","v":["healthy","degraded","failing","unknown"],"info":"Current health of the installation"},{"n":"lastHealthCheckAt","t":"datetime","info":"Last time health was verified"},{"n":"installedBy","t":"entityRef","re":"User","info":"User who set up the installation"},{"n":"installedAt","t":"datetime","info":"When this installation was created"}],"related":["Application","Company","Connection"]},{"name":"Area","class":"Dictionary","subsystem":"ACCESS","area":"Security & Permissions","desc":"A logical grouping of related Permissions — roughly equivalent to a resource domain (e.g. 'Inventory', 'Orders').","status":"draft","properties":[{"n":"areaId","r":true,"t":"string"},{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"permissions","r":true,"t":"array","re":"Permission"}],"service":"APR Access","related":["Permission","Scope"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Attribute","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Defines a product dimension (e.g. Color, Material). A combination of attribute values uniquely identifies an Item.","status":"draft","properties":[{"n":"alias","t":"string"},{"n":"code","r":true,"t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"attributeValues","r":true,"t":"schema","info":"Array of AttributeValue inline schemas. Each value extends LookupEntityValue — inherits id, identifiers, code, name, aliases, isActive, isDeleted, isDefault, sequence, audit fields, and customData."}],"ext":"LookupEntity","shopify":"ProductOption resource","related":["Product","Item"],"bv":{"rules":[{"rule":"Must be unique within the Attribute type","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[{"name":"productCount","formula":"COUNT(Product WHERE attributes CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[]},"inlineSchemas":[{"name":"AttributeValue","desc":"A single value within an Attribute's value set. Extends LookupEntityValue — inherits id, identifiers, code, name, aliases, isActive, isDeleted, isDefault, sequence, audit fields, and customData.","extends":"LookupEntityValue","properties":[]}]},{"name":"Bill","class":"Transactional","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Internal payable record generated from a matched Vendor Invoice (type 'invoice') or a matched Vendor Credit (type 'credit'). Tracks line-item costs, discounts, payment terms, and due dates against a Purchase Order. Credit-type Bills reduce the outstanding AP balance.","status":"stub","properties":[{"n":"billNo","r":true,"t":"string"},{"n":"type","r":true,"t":"string","info":"Discriminator: 'invoice' for standard payables (from Vendor Invoice), 'credit' for credit memos (from Vendor Credit). Determines sign of the AP impact."},{"n":"discount","t":"decimal"},{"n":"dueDate","t":"datetime"},{"n":"lines","r":true,"t":"array","info":"Array of BillLine sub-documents. Each line represents a charge on the bill, which may be non-inventory (services, freight, etc.)."},{"n":"location","t":"entityDetail","re":"Location"},{"n":"paymentMethod","t":"string"},{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"vendorCredit","t":"entityRef","re":"Vendor Credit","info":"Source Vendor Credit when type is 'credit'. Null for invoice-type Bills."},{"n":"vendorInvoice","t":"entityRef","re":"Vendor Invoice","info":"Source Vendor Invoice when type is 'invoice'. Null for credit-type Bills."},{"n":"status","r":true,"t":"string"},{"n":"termsCode","t":"string"},{"n":"totalAmount","r":true,"t":"decimal"},{"n":"vendor","t":"entityRef","re":"Vendor"}],"ext":"TransactionalDocument","related":["Vendor","Vendor Invoice","Vendor Credit","Purchase Order","Location"]},{"name":"Brand","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Brand or manufacturer label associated with a product.","status":"stub","properties":[{"n":"brandId","r":true,"t":"string"},{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Product"],"bv":{"rules":[],"lifecycle":null,"calculations":[{"name":"productCount","formula":"COUNT(Product WHERE brand = this)","trigger":"query-time"}],"crossEntityConstraints":[]}},{"name":"Business Entity","class":"Core","subsystem":"ALLPOINT","area":"Organization","desc":"Legal business entity within a Company — the registered legal/compliance unit for invoicing, tax, and regulatory purposes.","status":"stub","properties":[{"n":"address","t":"valueType","vt":"Address"},{"n":"businessEntityNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this business entity belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export."},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"legalName","r":true,"t":"string"},{"n":"locations","t":"array","re":"Location","info":"Locations operating under this legal entity for tax, invoicing, and regulatory purposes."},{"n":"registrationNumber","t":"string"},{"n":"taxId","t":"string"}],"notes":"A Company can have multiple Business Entities. Each Business Entity is scoped to a Company and optionally associated with specific Locations for tax and invoicing purposes.","related":["Company","Location"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"always","field":"LegalName","severity":"error"},{"rule":"Must conform to jurisdiction-specific tax ID format","when":"always","field":"TaxId","severity":"warning"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid active Company","entity":"Company"}]}},{"name":"Calendar Event","class":"Operational","subsystem":"CONNECT","area":"Messaging","desc":"A platform-native calendar event scoped to the Company tenant. Supports attendees with RSVP status, recurrence rules (RFC 5545 RRULE), and linking to source entities (e.g. a PO review meeting linked to a Purchase Order, a delivery window linked to a Ship Order). Franchise-group scoping controls visibility — users only see events tagged with their assigned franchise groups.","status":"draft","properties":[{"n":"attendees","r":true,"t":"array","info":"Invited users with individual response status."},{"n":"description","t":"string","info":"Event description. Supports markdown formatting."},{"n":"endAt","r":true,"t":"datetime","info":"Event end time in UTC."},{"n":"eventType","r":true,"t":"enumeration","v":["meeting","deadline","delivery","stockTake","shift","custom"],"info":"Classifies the event purpose. Used for filtering and calendar view grouping."},{"n":"isAllDay","r":true,"t":"boolean","info":"Whether this is an all-day event. When true, startAt and endAt represent date boundaries."},{"n":"isCancelled","r":true,"t":"boolean","info":"Soft-cancel flag. Cancelled events remain visible (with strikethrough) but are excluded from reminders and feeds."},{"n":"location","t":"string","info":"Free-text event location. May reference a platform Location name or an external address."},{"n":"organizer","r":true,"t":"entityRef","re":"User","info":"The User who created and owns this event. Only the organizer can edit or cancel."},{"n":"recurrenceRule","t":"string","info":"RFC 5545 RRULE string defining the recurrence pattern (e.g. FREQ=WEEKLY;BYDAY=MO;COUNT=10). Null for one-off events."},{"n":"reminderMinutes","t":"integer","info":"Minutes before the event to send a reminder notification. Null means no reminder."},{"n":"sourceEntity","t":"string","info":"Entity type this event is linked to (e.g. 'Purchase Order', 'Stock Take'). Enables contextual navigation from the calendar to the source document."},{"n":"sourceEntityId","t":"string","info":"ID of the specific entity instance this event is linked to."},{"n":"startAt","r":true,"t":"datetime","info":"Event start time in UTC."},{"n":"title","r":true,"t":"string","info":"Event title displayed in calendar views and notifications."}],"ext":"OperationalDocument","related":["User"],"bv":{"rules":[{"rule":"Must be after startAt","when":"always","field":"EndAt","severity":"error"},{"rule":"All attendees must be active Users within the same Company","when":"always","field":"Attendees","severity":"error"},{"rule":"If set, must be a valid RFC 5545 RRULE string","when":"always","field":"RecurrenceRule","severity":"error"}],"lifecycle":{"states":["Scheduled","Completed","Cancelled"],"transitions":[{"to":"Completed","from":"Scheduled","conditions":["Event endAt has passed or organizer marks complete"]},{"to":"Cancelled","from":"Scheduled","conditions":["Organizer cancels the event"]}],"initialState":"Scheduled"},"calculations":[{"name":"attendeeCount","formula":"COUNT(attendees)","trigger":"query-time"},{"name":"acceptedCount","formula":"COUNT(attendees WHERE status = 'accepted')","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Organizer and all attendees must be active Users within the same Company","entity":"User"},{"rule":"Reminder notifications may use an Email Template for delivery","entity":"Email Template"}]}},{"name":"Catalog","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"A curated subset of Products made available to specific markets or customer segments.","status":"stub","properties":[{"n":"catalogId","r":true,"t":"string"},{"n":"markets","r":true,"t":"array","re":"Market"},{"n":"name","r":true,"t":"string"},{"n":"products","r":true,"t":"array","re":"Product"}],"ext":"OperationalDocument","shopify":"Catalog resource","related":["Product","Market"],"bv":{"rules":[],"lifecycle":null,"calculations":[{"name":"productCount","formula":"COUNT(products)","trigger":"query-time"},{"name":"marketCount","formula":"COUNT(markets)","trigger":"query-time"}],"crossEntityConstraints":[]}},{"name":"Chat Channel","class":"Operational","subsystem":"CONNECT","area":"Messaging","desc":"A conversation container scoped to the Company tenant. Channels are segmented by franchiseGroups — users only see channels whose franchise groups overlap with their own assignments. Supports direct (1:1), group, and broadcast channel types.","status":"draft","properties":[{"n":"channelNo","r":true,"t":"integer","info":"Auto-incrementing channel number within the Company."},{"n":"isArchived","r":true,"t":"boolean","info":"Soft-archive flag. Archived channels are hidden from default views but data is retained."},{"n":"name","r":true,"t":"string","info":"Display name for the channel. For direct channels, typically auto-generated from participant names."},{"n":"participants","r":true,"t":"array","re":"User","info":"Users who can view and post in this channel. For broadcast channels, only admins can post."},{"n":"pinnedMessages","r":true,"t":"array","re":"Chat Message","info":"Messages pinned for quick reference. Ordered by pin date descending."},{"n":"topic","t":"string","info":"Channel topic or purpose description. Displayed in channel header."},{"n":"type","r":true,"t":"enumeration","v":["direct","group","broadcast"],"info":"Channel type. direct = 1:1 conversation; group = multi-party; broadcast = admin-post-only announcements."}],"ext":"OperationalDocument","related":["User","Chat Message"],"bv":{"rules":[{"rule":"Direct channels must have exactly two participants","when":"create","field":"Participants","severity":"error"},{"rule":"Group channels must have at least two participants","when":"create","field":"Participants","severity":"error"},{"rule":"Must be unique within the Company for group and broadcast channels","when":"always","field":"Name","severity":"error"}],"lifecycle":{"states":["Active","Archived"],"transitions":[{"to":"Archived","from":"Active","conditions":["Manual archive by channel admin or system policy"]},{"to":"Active","from":"Archived","conditions":["Manual unarchive by channel admin"]}],"initialState":"Active"},"calculations":[{"name":"participantCount","formula":"COUNT(participants)","trigger":"query-time"},{"name":"messageCount","formula":"COUNT(Chat Message WHERE channelId = this)","trigger":"query-time"},{"name":"pinnedMessageCount","formula":"COUNT(pinnedMessages)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"All participants must be active Users within the same Company","entity":"User"},{"rule":"Messages inherit tenant scope from their parent channel","entity":"Chat Message"}]}},{"name":"Chat Message","class":"Transactional","subsystem":"CONNECT","area":"Messaging","desc":"An individual message within a Chat Channel. Supports threaded replies, @mentions, emoji reactions, file attachments, and pinning. Inherits tenant isolation from its parent channel — no franchiseGroups or idmpKey on the message itself.","status":"draft","properties":[{"n":"attachments","r":true,"t":"array","info":"File attachments on this message."},{"n":"body","r":true,"t":"string","info":"Message content. Supports markdown formatting."},{"n":"channelId","r":true,"t":"entityRef","re":"Chat Channel","info":"The channel this message belongs to. Drives tenant isolation — the channel's companyId and franchiseGroups scope access."},{"n":"editedAt","t":"datetime","info":"Timestamp of last edit. Null if never edited."},{"n":"isEdited","r":true,"t":"boolean","info":"Whether the message body has been modified after sending."},{"n":"isPinned","r":true,"t":"boolean","info":"Whether this message is pinned in the channel for quick reference."},{"n":"mentions","r":true,"t":"array","re":"User","info":"Users @mentioned in this message. Drives notification delivery."},{"n":"messageType","r":true,"t":"enumeration","v":["text","system","attachment"],"info":"Message classification. text = user-authored; system = auto-generated (join/leave/archive); attachment = file-only message."},{"n":"reactions","r":true,"t":"array","info":"Emoji reactions aggregated by emoji. Each entry contains the emoji code and the list of Users who reacted."},{"n":"sender","r":true,"t":"entityRef","re":"User","info":"The User who sent this message."},{"n":"sentAt","r":true,"t":"datetime","info":"When the message was sent. Distinct from createdDate to support offline/queued message delivery."},{"n":"threadParentId","t":"entityRef","re":"Chat Message","info":"Reference to the parent message for threaded replies. Null for top-level messages."}],"ext":"OperationalSubDocument","related":["Chat Channel","User"],"bv":{"rules":[{"rule":"Must not be empty for text and system message types","when":"create","field":"Body","severity":"error"},{"rule":"Must have at least one attachment when messageType is 'attachment'","when":"create","field":"Attachments","severity":"error"},{"rule":"If set, must reference a message in the same channel","when":"always","field":"ThreadParentId","severity":"error"},{"rule":"Must be an active participant of the channel","when":"create","field":"Sender","severity":"error"}],"lifecycle":{"states":["Active","Edited","Deleted"],"transitions":[{"to":"Edited","from":"Active","conditions":["Sender modifies the message body"]},{"to":"Edited","from":"Edited","conditions":["Sender modifies the message body again"]},{"to":"Deleted","from":"Active","conditions":["Sender or channel admin deletes the message"]},{"to":"Deleted","from":"Edited","conditions":["Sender or channel admin deletes the message"]}],"initialState":"Active"},"calculations":[{"name":"reactionCount","formula":"SUM(reactions[].users.length)","trigger":"query-time"},{"name":"replyCount","formula":"COUNT(Chat Message WHERE threadParentId = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Message must belong to a valid, non-deleted channel","entity":"Chat Channel"},{"rule":"Sender must be a participant of the channel. Mentioned users must be in the same Company.","entity":"User"}]}},{"name":"Classification","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Merchandise hierarchy: Department → Class → Subclass. Carries default tax code and weeks of supply.","status":"draft","properties":[{"n":"class","t":"entityDetail","re":"Classification Class"},{"n":"code","r":true,"t":"string"},{"n":"defaultTaxClass","t":"entityDetail","re":"Tax Class"},{"n":"defaultWeeksOfSupply","t":"integer"},{"n":"department","t":"entityDetail","re":"Classification Department"},{"n":"fullName","t":"string","info":"Calculated field. Concatenation of the department name, class name, and each subclass name (e.g. 'Apparel > Men > Outerwear')."},{"n":"name","r":true,"t":"string","u":true},{"n":"subclasses","r":true,"t":"array","re":"Classification Subclass","info":"All subclasses belonging to this classification node. Each entry is a denormalized entityDetail snapshot."}],"ext":"LookupEntity","related":["Product","Tax Class","Classification Department","Classification Class","Classification Subclass"],"bv":{"rules":[{"rule":"Must be unique within the classification level/type","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Cannot delete a Classification that is referenced by Products","entity":"Product"}]}},{"name":"Classification Class","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Mid level of the merchandise hierarchy, one step below Department (e.g. Mens Shirts, Televisions). Groups related Classification Subclasses for assortment planning.","status":"stub","properties":[],"ext":"TaxonomyEntityNode","related":["Classification","Classification Department"]},{"name":"Classification Department","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Top level of the merchandise hierarchy (e.g. Apparel, Electronics, Home). Groups related Classification Classes under a single department for reporting and planning.","status":"stub","properties":[],"ext":"TaxonomyEntityNode","related":["Classification"]},{"name":"Classification Subclass","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Finest level of the merchandise hierarchy, below Class (e.g. Dress Shirts, OLED TVs). Products are assigned at the subclass level for precise categorization.","status":"stub","properties":[],"ext":"TaxonomyEntityNode","related":["Classification","Classification Class"]},{"name":"Client","class":"Core","subsystem":"ACCESS","area":"Infrastructure","desc":"A deployed platform instance — the environment boundary. The Client IS the environment. \"Acme Production\" and \"Acme Sandbox\" are two separate Clients. A Client hosts one or many Companies (tenants). Some Clients are shared infrastructure (multiple tenants), others are dedicated to a single Organization (single tenant). Each Client carries its own OAuth2/OIDC credential sets and scope grants. Auth and permissions are scoped to the Client/Company boundary — a token issued for one Client/Company cannot access resources belonging to another.","status":"draft","properties":[{"n":"allowedScopes","r":true,"t":"array","re":"Scope"},{"n":"clientNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"clientSecret","r":true,"t":"encrypted","info":"Hashed OAuth2 client secret. Never stored or transmitted in plaintext."},{"n":"companies","r":true,"t":"array","re":"Company","info":"Tenants hosted within this Client"},{"n":"deploymentType","r":true,"t":"enumeration","v":["shared","dedicated"],"info":"shared = multi-tenant infrastructure, dedicated = single Organization"},{"n":"environment","r":true,"t":"entityRef","re":"Environment","info":"The Environment this Client is deployed to (e.g. dev, qa, uat, prod)."},{"n":"grantTypes","r":true,"t":"array"},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"name","r":true,"t":"string","info":"Display name (e.g., \"APR Cloud US-East Production\")"},{"n":"redirectUris","r":true,"t":"array"},{"n":"status","r":true,"t":"enumeration","v":["active","provisioning","maintenance","decommissioned"]}],"service":"APR Access","shopify":"App/Client credentials model","notes":"Canonical subsystem is PLATFORM (Infrastructure). Currently registered under ACCESS pending subsystem reassignment — needs delete-and-recreate to move to PLATFORM.","related":["Company","Environment","Scope"],"bv":{"rules":[{"rule":"Must be globally unique (UUID)","when":"create","field":"ClientId","severity":"error"},{"rule":"Must be stored hashed, never in plaintext","when":"always","field":"ClientSecret","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must be scoped to a valid Application","entity":"Application"},{"rule":"Must belong to a valid Company tenant","entity":"Company"},{"rule":"Must target a valid Environment","entity":"Environment"}]}},{"name":"Company","class":"Core","subsystem":"ALLPOINT","area":"Organization","desc":"The tenant boundary in the platform's multi-tenant architecture. All data — products, inventory, sales, locations, pricing, users, and access control — is isolated within a Company. Each Company belongs to an Organization and scopes commerce operations end-to-end. Each Company lives within a Client (the deployed instance). The Company's deploymentModel (Shared / Dedicated) determines whether the Company shares its Client with other tenants or receives an isolated Client at an increased licensing tier — tenancy is enforced at the Company level, not at the Organization level.","status":"draft","properties":[{"n":"client","r":true,"t":"entityRef","re":"Client","info":"The Client (deployed instance) this Company lives within"},{"n":"companyNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Company's configuration record in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Holds tenant-scoped configuration — commerce rules, feature flags, integration defaults — that applies to all data within the Company boundary."},{"n":"defaultCostingMethod","r":true,"t":"enumeration","v":["FIFO","LIFO","WAC"],"info":"Tenant-default inventory costing method. FIFO is the platform default per the Stock Ledger Service PRD. Individual item × location pairs may override this via Item Stock.costingMethod; if not overridden, they inherit this value. Changing this after go-live only affects new item-locations; existing positions retain whatever method they were last configured with until an offline replay job is run."},{"n":"deploymentModel","r":true,"t":"enumeration","v":["Shared","Dedicated"],"info":"Shared: this Company runs on multi-tenant infrastructure (a Client hosting multiple tenants). Dedicated: this Company receives an isolated environment (compute, databases, cache) — a Client dedicated to a single tenant — provisioned at an increased licensing tier. Tenancy is enforced at the Company level (the tenant boundary), so deploymentModel is a Company property, not an Organization property. Infrastructure details are managed as Config Service configurations, not as entity properties."},{"n":"externalId","t":"string","info":"Shared identifier linking the same logical business across Clients (sandbox ↔ production)"},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"locations","r":true,"t":"array","re":"Location","info":"All locations belonging to this company."},{"n":"name","r":true,"t":"string"},{"n":"organization","r":true,"t":"entityRef","re":"Organization","info":"Many-to-one. Each Company belongs to exactly one Organization."},{"n":"settings","t":"schema"},{"n":"status","r":true,"t":"schema","info":"CompanyStatus inline schema capturing current status with audit trail."},{"n":"tier","t":"enumeration","v":["starter","growth","professional","enterprise"]}],"related":["Organization","Client","Location","Market","Business Entity","Application Installation","Connection"],"bv":{"rules":[{"rule":"Must be unique across the platform","when":"create","field":"Name","severity":"error"},{"rule":"Must contain valid currency, timezone, and locale configuration","when":"create","field":"Settings","severity":"error"}],"lifecycle":null,"calculations":[{"name":"locationCount","formula":"COUNT(Location WHERE company = this)","trigger":"query-time"},{"name":"userCount","formula":"COUNT(User WHERE company = this)","trigger":"query-time"},{"name":"applicationCount","formula":"COUNT(Application WHERE company = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot delete a Company that has active Locations","entity":"Location"},{"rule":"At least one Market must exist before Commerce operations can begin","entity":"Market"}]},"inlineSchemas":[{"name":"CompanyStatus","properties":[{"n":"status","r":true,"t":"enumeration","v":["Draft","Active","Archived"],"info":"Current status of the company."},{"n":"changedBy","t":"string","info":"User who last changed the status."},{"n":"changedDate","t":"datetime","info":"Timestamp of the last status change."}]}]},{"name":"Config","class":"Core","subsystem":"CONFIG","area":"Configuration","desc":"A resolved configuration instance for a given Actor and Environment. Derived from a Config Template with overrides applied.","status":"stub","properties":[{"n":"actor","r":true,"t":"entityRef","re":"Actor"},{"n":"configId","r":true,"t":"string"},{"n":"environment","r":true,"t":"entityDetail","re":"Environment"},{"n":"template","r":true,"t":"entityRef","re":"Config Template"},{"n":"values","r":true,"t":"schema"},{"c":true,"n":"version","r":true,"t":"integer"}],"service":"APR Config","shopify":"Shop resource settings / metafield-based config","related":["Config Template","Actor","Environment"],"bv":{"rules":[{"rule":"Must validate against the associated Config Template schema","when":"always","field":"Value","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid Config Template","entity":"Config Template"},{"rule":"Values may be overridden per Environment","entity":"Environment"}]}},{"name":"Config Template","class":"Core","subsystem":"CONFIG","area":"Configuration","desc":"A reusable schema defining the shape and defaults of a Config. Services register expected config structure via templates.","status":"draft","properties":[{"n":"actor","t":"entityRef","re":"Actor"},{"n":"defaultValues","t":"schema"},{"n":"documentType","t":"entityDetail","re":"Document Type"},{"n":"name","r":true,"t":"string"},{"n":"schema","r":true,"t":"schema"},{"n":"templateId","r":true,"t":"string"}],"service":"APR Config","related":["Config","Actor","Document Type"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Templates define the schema that Config instances must conform to","entity":"Config"}]}},{"name":"Connection","class":"Core","subsystem":"CONNECT","area":"Integration","desc":"A Company-scoped configuration that pairs a Source and Destination — each defined by a Connector (what data flows) and an Application Installation (authenticated access) — plus the transformation rules and workflow logic governing how data moves between them. The Connection is the central orchestration entity in CONNECT. Connections reference Application Installations for credentials rather than holding credentials directly. Multiple Connections can share the same Application Installation.","status":"draft","properties":[{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"connectionNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"name","r":true,"t":"string","info":"Operator-facing label (e.g., Fulcrum X → Shopify Product Sync)"},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this connection belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export."},{"n":"sourceConnector","r":true,"t":"entityRef","re":"Connector","info":"Source integration blueprint (from global registry)"},{"n":"destinationConnector","r":true,"t":"entityRef","re":"Connector","info":"Destination integration blueprint (from global registry)"},{"n":"sourceInstallation","r":true,"t":"entityRef","re":"Application Installation","info":"Authenticated source (credentials, external account)"},{"n":"destinationInstallation","r":true,"t":"entityRef","re":"Application Installation","info":"Authenticated destination (credentials, external account)"},{"n":"entityScope","r":true,"t":"array","info":"Canonical schema entities this Connection covers"},{"n":"direction","r":true,"t":"enumeration","v":["unidirectional","bidirectional"]},{"n":"status","r":true,"t":"enumeration","v":["draft","active","paused","error","archived"]},{"n":"syncMode","r":true,"t":"enumeration","v":["realtime","scheduled","manual"]},{"n":"syncSchedule","t":"string","info":"Cron expression (if scheduled)"},{"n":"workflowRules","t":"schema","info":"Transformation rules, field mappings, filters, conflict resolution"},{"n":"errorPolicy","t":"schema","info":"Retry config, dead-letter behavior, alert thresholds"},{"n":"lastSyncAt","t":"datetime","info":"Last successful sync timestamp"},{"n":"lastSyncStatus","t":"enumeration","v":["success","partial","failed"]},{"n":"createdBy","t":"entityRef","re":"User","info":"User who configured the Connection"},{"n":"createdAt","t":"datetime"}],"related":["Company","Connector","Application Installation"]},{"name":"Connector","class":"Core","subsystem":"CONNECT","area":"Organization","desc":"A source or destination integration blueprint that defines the data exchange capabilities for a system. Each Connector describes what canonical schema entities it supports, what directions it can operate in, and what sync capabilities it has. Connectors exist once in a global registry. Connectors are linked to Applications — the Shopify Connector is linked to the APR Shopify App Application, the Fulcrum X Connector is linked to the Fulcrum X Application. The Connector defines what data can flow; the Application Installation (via Connection) provides the authenticated access.","status":"draft","properties":[{"n":"applicationId","t":"entityRef","re":"Application","info":"FK to Application (the APR app that provides auth and data exchange for this connector)"},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Connector's configuration record in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Holds connector-level defaults for supported entities, sync cadence, and capability toggles — distinct from per-Connection runtime settings."},{"n":"connectorNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"description","t":"string","info":"What this Connector integrates with"},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"name","r":true,"t":"string","u":true,"info":"Display name (e.g., Shopify, Fulcrum X). Globally unique"},{"n":"slug","r":true,"t":"string","u":true,"info":"Human-readable key (e.g., shopify, fulcrum-x, netsuite). Globally unique"},{"n":"supportedDirections","r":true,"t":"array","info":"source, destination, or both"},{"n":"supportedEntities","r":true,"t":"array","info":"Canonical schema entities this Connector can source/sink (e.g., Product, Order, Customer)"},{"n":"type","r":true,"t":"enumeration","v":["first_party","commerce_platform","erp","accounting","marketing","loyalty","wms","3pl","shipping","marketplace"],"info":"Integration category"}],"related":["Application","Connection"]},{"name":"Cost Adjustment","class":"Transactional","subsystem":"CONNECT","area":"Products & Pricing","desc":"Transactional document recording a cost change applied to items for a specific vendor. Writes entries to the Cost Ledger. Standard in retail merchandising systems for managing vendor cost lifecycle events. Distinct from option-level vendorCostModifier deltas on OptionValues which are relative and non-transactional.","status":"stub","properties":[{"n":"adjustmentId","r":true,"t":"string"},{"n":"costLevel","t":"entityDetail","re":"Cost Level"},{"n":"currency","r":true,"t":"enumeration","v":["USD","CAD","EUR","GBP","AUD","NZD","MXN","JPY","CNY","INR","BRL","CHF","SEK","NOK","DKK","SGD","HKD","KRW","ZAR","AED"],"info":"ISO 4217 currency code for this cost adjustment."},{"n":"item","r":true,"t":"entityRef","re":"Item"},{"n":"newCost","r":true,"t":"decimal"},{"n":"oldCost","r":true,"t":"decimal"},{"n":"reason","t":"string"},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"}],"ext":"TransactionalDocument","related":["Product","Item","Vendor","Cost Level","Cost Ledger"],"bv":{"rules":[{"rule":"Must be >= 0","when":"always","field":"NewCost","severity":"error"},{"rule":"Must differ from OldCost","when":"submit","field":"NewCost","severity":"error"},{"rule":"Must not be in the past unless backdating is enabled in Company settings","when":"create","field":"EffectiveDate","severity":"warning"}],"lifecycle":{"states":["Draft","Approved","Posted","Cancelled"],"transitions":[{"to":"Approved","from":"Draft","conditions":["At least one item line exists","Vendor is valid and active","NewCost differs from OldCost"]},{"to":"Posted","from":"Approved","conditions":["Cost Ledger entries written","Item cost updated at the specified Cost Level"]},{"to":"Cancelled","from":"Draft","conditions":[]},{"to":"Cancelled","from":"Approved","conditions":["Not yet posted"]}],"initialState":"Draft"},"calculations":[{"name":"CostDelta","formula":"NewCost - OldCost","trigger":"On cost value change"},{"name":"CostDeltaPct","formula":"((NewCost - OldCost) / OldCost) × 100","trigger":"On cost value change"}],"crossEntityConstraints":[{"rule":"Must reference a valid active Vendor","entity":"Vendor"},{"rule":"Must reference a valid active Item","entity":"Item"},{"rule":"Must reference a valid Cost Level if provided","entity":"Cost Level"},{"rule":"Posting writes an immutable Cost Ledger entry recording the old→new cost change","entity":"Cost Ledger"}]}},{"name":"Cost Ledger","class":"Ledger","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Immutable chronological audit log of vendor unit cost changes. Records entries for both Product/Vendor and Item/Vendor relationships at each cost level. Functions identically to the Price Ledger but for vendor purchase costs rather than retail prices.","status":"stub","properties":[{"n":"costLevel","t":"entityDetail","re":"Cost Level","info":"Cost level this entry applies to (parallels PriceLevel on Price Ledger)"},{"n":"item","t":"entityRef","re":"Item","info":"Item-level cost entry (for Item/Vendor granularity); mutually exclusive with Product"},{"c":true,"n":"ledgerLine","r":true,"t":"integer"},{"n":"product","t":"entityRef","re":"Product","info":"Product-level cost entry (for Product/Vendor granularity); mutually exclusive with Item"},{"n":"unitCost","r":true,"t":"decimal","info":"The new vendor unit cost for this item"},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor","info":"The vendor whose unit cost is being recorded"}],"ext":"LedgerEntry","notes":"Mirrors the Price Ledger pattern. Each entry records a vendor unit cost change at either the Product/Vendor or Item/Vendor level for a given cost level.","related":["Vendor","Product","Item","Cost Level"],"bv":{"rules":[{"rule":"Append-only — existing entries must not be modified or deleted","when":"always","field":"LedgerLine","severity":"error"},{"rule":"Must be non-negative","when":"create","field":"UnitCost","severity":"error"},{"rule":"Exactly one of Product or Item must be set per entry","when":"create","field":"Product|Item","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Product-level entries track vendor cost per Product × Vendor × CostLevel","entity":"Product"},{"rule":"Item-level entries track vendor cost per Item × Vendor × CostLevel","entity":"Item"},{"rule":"Must reference a valid Cost Level","entity":"Cost Level"}]}},{"name":"Cost Level","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Tier or level at which product costs are defined (e.g. by vendor, by region, by channel). Extends LookupEntity — no additional fields beyond the base.","status":"stub","properties":[],"ext":"LookupEntity","related":["Market","Vendor","Item"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Country","class":"Dictionary","subsystem":"CONNECT","area":"Organization","desc":"ISO 3166 country reference. Used for country of origin on products, address countries, tax jurisdictions, and regulatory compliance. Pure LookupEntity — no additional fields beyond the base.","status":"stub","properties":[],"ext":"LookupEntity","related":["Product"]},{"name":"Coupon","class":"Operational","subsystem":"CONNECT","area":"Promotions","desc":"A unique or generic code that customers redeem to activate a Promotion or Discount.","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true},{"n":"couponId","r":true,"t":"string"},{"n":"expiryDate","t":"datetime"},{"n":"promotion","r":true,"t":"entityRef","re":"Promotion"},{"c":true,"n":"usageCount","t":"integer"},{"n":"usageLimit","t":"integer"}],"shopify":"DiscountCode resource","related":["Promotion","Sales Order"],"bv":{"rules":[],"lifecycle":null,"calculations":[{"name":"usageCount","formula":"COUNT(Sales Order WHERE coupons CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[]}},{"name":"Currency","class":"Dictionary","subsystem":"ALLPOINT","area":"Organization","desc":"ISO 4217 currency definition. Defines the currencies available for use across the platform — pricing, costing, transactions, and vendor payments. Each currency carries its code (e.g. USD, EUR, GBP), display symbol, and decimal precision. Referenced by Market.baseCurrency, Location.baseCurrency, Vendor.orderCurrency, and monetary fields throughout the system.","status":"draft","properties":[{"n":"symbol","r":true,"t":"string","info":"Display symbol for the currency (e.g. $, €, £, ¥)."},{"n":"decimalPrecision","r":true,"t":"integer","info":"Number of decimal places for monetary amounts in this currency. Typically 2 (USD, EUR) or 0 (JPY, KRW)."},{"n":"isoNumericCode","t":"string","info":"ISO 4217 three-digit numeric code (e.g. 840 for USD, 978 for EUR)."}],"ext":"LookupEntity","related":["Market","Location","Vendor"]},{"name":"Custom Unit","class":"Dictionary","subsystem":"CONFIG","area":"Configuration","desc":"A user-defined unit of measure or business-specific enumeration extending platform defaults for a given Company or Market.","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"name","r":true,"t":"string","u":true},{"n":"unitId","r":true,"t":"string"}],"service":"APR Config","shopify":"weight_unit on products/variants","related":["Company","Market","Item"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Customer","class":"Operational","subsystem":"CONNECT","area":"Customers","desc":"A person or account that purchases goods. Carries credit profile and purchase history.","status":"draft","properties":[{"n":"anniversaryDate","t":"datetime","info":"Customer anniversary date for marketing."},{"n":"billToAddresses","r":true,"t":"array","info":"Billing addresses."},{"n":"birthday","t":"datetime","info":"Customer birthday for marketing and age verification."},{"n":"contacts","r":true,"t":"array","info":"Customer contacts."},{"n":"creditLimit","t":"decimal"},{"n":"customerNo","r":true,"t":"integer"},{"n":"emails","r":true,"t":"array","info":"Customer email addresses with communication preferences."},{"n":"firstName","t":"string"},{"n":"gender","t":"string","info":"Customer gender."},{"n":"isActive","r":true,"t":"boolean","info":"Whether the customer account is active."},{"n":"isCompany","r":true,"t":"boolean","info":"Whether this customer represents a company/organization."},{"n":"isEmployee","r":true,"t":"boolean","info":"Whether this customer is also an employee."},{"n":"isTaxExempt","r":true,"t":"boolean","info":"Whether the customer is exempt from tax."},{"n":"isWholesale","r":true,"t":"boolean","info":"Whether this is a wholesale customer."},{"n":"lastName","t":"string"},{"n":"loyaltyPrograms","r":true,"t":"array","re":"Loyalty Program","info":"Loyalty program enrollments with points balances."},{"n":"memberships","r":true,"t":"array","info":"Customer membership records with type and expiration."},{"n":"middleName","t":"string","info":"Customer middle name."},{"n":"organization","t":"string","info":"Company or organization name if isCompany is true."},{"n":"phones","r":true,"t":"array","info":"Customer phone numbers with communication preferences."},{"n":"postalAddresses","r":true,"t":"array","info":"Postal addresses."},{"n":"rfmGroup","t":"entityDetail","re":"RFM Group","info":"Customer's current RFM (Recency, Frequency, Monetary) segmentation group. Computed by analytics from purchase history and used to drive targeted marketing, retention, and service tiering."},{"n":"shipToAddresses","r":true,"t":"array","info":"Shipping addresses."},{"n":"title","t":"string","info":"Name title/prefix (e.g. Mr, Mrs, Dr)."}],"ext":"OperationalDocument","shopify":"Customer resource","related":["Sales Order","Customer Credit","Sale"],"bv":{"rules":[{"rule":"Must be a valid email format and unique within the Company if provided","when":"always","field":"Email","severity":"error"},{"rule":"Must be >= 0 if provided","when":"always","field":"CreditLimit","severity":"error"}],"lifecycle":{"states":["Active","Inactive","Archived"],"transitions":[{"to":"Inactive","from":"Active","conditions":["No open orders"]},{"to":"Active","from":"Inactive","conditions":[]},{"to":"Archived","from":"Inactive","conditions":["No outstanding balance","Meets data-retention policy"]}],"initialState":"Active"},"calculations":[{"name":"salesOrderCount","formula":"COUNT(Sales Order WHERE customer = this)","trigger":"query-time"},{"name":"saleCount","formula":"COUNT(Sale WHERE customer = this)","trigger":"query-time"},{"name":"creditCount","formula":"COUNT(Customer Credit WHERE customer = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot archive a Customer with open Sales Orders","entity":"Sales Order"},{"rule":"Archiving a Customer does not expire their Gift Cards","entity":"Gift Card"}]},"inlineSchemas":[{"name":"CustomerMembership","extends":"OperationalSubDocument","properties":[{"info":"Date the membership expires.","name":"expirationDate","type":"datetime"},{"info":"Type or level of the membership.","name":"membershipType","type":"string","required":true},{"info":"Date the membership started.","name":"startDate","type":"datetime"}]},{"name":"CustomerLoyaltyProgram","extends":"OperationalSubDocument","properties":[{"info":"Date the customer enrolled in this loyalty program.","name":"enrolledDate","type":"datetime"},{"info":"Reference to the Loyalty Program.","name":"loyaltyProgramId","type":"string","required":true},{"info":"Current points balance in this program.","name":"pointsBalance","type":"integer","required":true},{"info":"Current loyalty tier within the program.","name":"tierId","type":"string"}]}]},{"name":"Customer Credit","class":"Balance","subsystem":"CONNECT","area":"Payments & Stored Value","desc":"Monetary credit balance held on a customer account for future purchases or refunds.","status":"stub","properties":[{"n":"balance","r":true,"t":"decimal"},{"n":"creditId","r":true,"t":"string"},{"n":"customer","r":true,"t":"entityRef","re":"Customer"},{"n":"expiryDate","t":"date"}],"shopify":"Store credit / Refund adjustment","related":["Customer","Sale"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Dashboard","class":"Core","subsystem":"CONNECT","area":"Analytics","desc":"A configured dashboard composed of one or more Report widgets. Provides a consolidated view of analytics across domains. Dashboards are scoped by franchise group and can be shared or personal.","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"name","r":true,"t":"string"}],"ext":"BaseDocument","related":["Report"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Discount","class":"Dictionary","subsystem":"CONNECT","area":"Promotions","desc":"A price reduction rule (%, fixed amount, BOGO, etc.) referenced by Promotions and applied at Sale.","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"discountId","r":true,"t":"string"},{"n":"name","r":true,"t":"string","u":true}],"shopify":"Discount types in GraphQL","related":["Promotion","Price Rule"],"bv":{"rules":[{"rule":"Must be before EndDate if both are set","when":"always","field":"StartDate","severity":"error"}],"lifecycle":{"states":["Draft","Active","Expired","Archived"],"transitions":[{"to":"Active","from":"Draft","conditions":["Start date reached or manually activated"]},{"to":"Expired","from":"Active","conditions":["End date passed"]},{"to":"Archived","from":"Active","conditions":[]},{"to":"Archived","from":"Expired","conditions":[]}],"initialState":"Draft"},"calculations":[{"name":"promotionCount","formula":"COUNT(Promotion WHERE discounts CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Applied discount amount recorded on Sale line","entity":"Sale"}]}},{"name":"Document Custom Data Config","class":"Core","subsystem":"CONNECT","area":"Platform","desc":"Metadata definition for extensible custom fields attached to documents. Configures field type, label, allowed values, and the target document type (32+ supported). System-wide schema extension mechanism.","status":"stub","properties":[{"n":"availableValues","r":true,"t":"array","info":"Allowed values for lookup or multiselect field types."},{"n":"fieldType","r":true,"t":"enumeration","v":["text","longtext","integer","decimal","date","flag","lookup","multiselect"]},{"n":"isDeleted","r":true,"t":"boolean"},{"n":"label","r":true,"t":"string","info":"User-facing display label."},{"n":"relatedDocumentType","r":true,"t":"enumeration","v":["PurchaseOrder","SalesOrder","TransferOrder","StockAdjustment","StockTake","GoodsReceipt","Sale","Bill","VendorInvoice","VendorCredit"],"info":"The document type this custom field attaches to (e.g. PurchaseOrder, SalesReceipt, Vendor, Customer)."},{"n":"sequence","t":"integer","info":"Display ordering hint."},{"n":"sourceFieldName","r":true,"t":"string","info":"Underlying field key in the custom data payload."}],"notes":"Supports 32+ document types including: PurchaseOrder, SalesOrder, SalesReceipt, Vendor, Customer, Employee, Location, StockTransfer, and more.","related":[]},{"name":"Document Type","class":"Dictionary","subsystem":"CONFIG","area":"Configuration","desc":"Defines a category of structured document managed within the platform (PO, ASN, Invoice).","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Document Type's policy configuration in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Acts as the policy anchor for every document of this type — e.g., the Purchase Order Document Type's Config holds rules like autoExpireDaysAfterCancellation, requireApprovalOverAmount, numberingPrefix. Concrete documents (Purchase Order, Bill, ASN, Vendor Invoice) resolve their effective policy at runtime by reading documentType.configuration.config rather than carrying per-document overrides. The templateCode field names the Config Template that defines which policy keys are valid for this Document Type."},{"n":"description","t":"string"},{"n":"documentTypeId","r":true,"t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"processingRules","t":"schema"},{"n":"schema","t":"schema"}],"service":"APR Config","related":["Config Template"],"bv":{"rules":[{"rule":"Must be unique","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Email Log","class":"Ledger","subsystem":"CONNECT","area":"Messaging","desc":"Immutable delivery audit trail. One record per email sent via AWS SES. Tracks the full delivery lifecycle from queue through delivery, bounce, or complaint. Records are append-only — status updates are written as new action entries, not field overwrites. Links back to the triggering entity and template for traceability. Inherited sourceEntityType/sourceEntityId identify the entity that triggered the email (e.g. 'Sales Order' / orderId).","status":"draft","properties":[{"n":"bounceReason","t":"string","info":"SES bounce diagnostic message. Only populated when status is bounced."},{"n":"bounceType","t":"enumeration","v":["hard","soft","undetermined"],"info":"Bounce classification. Hard bounces trigger recipient suppression. Only set when status is bounced."},{"n":"deliveredAt","t":"datetime","info":"SES delivery confirmation timestamp. Null until delivery is confirmed."},{"n":"messageId","r":true,"t":"string","info":"SES Message-ID returned on send. Used for delivery status tracking via SES notifications."},{"n":"recipientEmail","r":true,"t":"string","info":"Destination email address."},{"n":"recipientUser","t":"entityRef","re":"User","info":"User reference if the recipient is a platform user. Null for external recipients (e.g. vendor contacts)."},{"n":"sentAt","t":"datetime","info":"When the email was handed to SES for delivery. Null while status is queued."},{"n":"status","r":true,"t":"schema","info":"Delivery status of the email. Tracks current state and who/when it was last changed."},{"n":"subject","r":true,"t":"string","info":"Rendered subject line after variable interpolation."},{"n":"template","t":"entityRef","re":"Email Template","info":"The Email Template used to render this email. Null for ad-hoc emails not based on a template."}],"ext":"LedgerEntry","related":["Email Template","User"],"bv":{"rules":[{"rule":"Must be unique — one log entry per SES send","when":"create","field":"MessageId","severity":"error"},{"rule":"Transitions are append-only — status can only move forward, never backward","when":"always","field":"Status","severity":"error"}],"lifecycle":{"states":["Queued","Sent","Delivered","Bounced","Complained","Failed"],"transitions":[{"to":"Sent","from":"Queued","conditions":["SES accepts the send request"]},{"to":"Failed","from":"Queued","conditions":["SES rejects the send request (invalid address, suppressed recipient)"]},{"to":"Delivered","from":"Sent","conditions":["SES delivery notification received"]},{"to":"Bounced","from":"Sent","conditions":["SES bounce notification received"]},{"to":"Complained","from":"Sent","conditions":["SES complaint notification received (recipient marked as spam)"]}],"initialState":"Queued"},"calculations":[],"crossEntityConstraints":[{"rule":"If template is set, the template must exist and be Active at send time","entity":"Email Template"},{"rule":"If recipientUser is set, must reference a valid User within the same Company","entity":"User"}]},"inlineSchemas":[{"name":"EmailLogStatus","schema":"schemas/email-log/EmailLogStatus.ts","properties":[{"info":"Current delivery status. Updated via SES notification webhooks.","name":"status","type":"enumeration","values":["queued","sent","delivered","bounced","complained","failed"],"required":true},{"info":"User or system actor who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Email Template","class":"Operational","subsystem":"CONNECT","area":"Messaging","desc":"A reusable, tenant-scoped email layout with variable placeholders for merge-field interpolation. Templates define the subject, HTML body, plain-text fallback, and sender identity. Each template can be linked to an entity state transition to trigger automated transactional emails (e.g. Sales Order → Completed fires an order-confirmation email via AWS SES).","status":"draft","properties":[{"n":"bodyHtml","r":true,"t":"string","info":"HTML email body with {{variable}} placeholders for merge-field interpolation."},{"n":"bodyText","t":"string","info":"Plain-text fallback body. Used when the recipient's client does not render HTML."},{"n":"fromEmail","r":true,"t":"string","info":"Sender email address. Must be a verified identity in the Company's SES configuration."},{"n":"fromName","r":true,"t":"string","info":"Sender display name shown in the From header."},{"n":"isActive","r":true,"t":"boolean","info":"Whether this template is currently in use. Inactive templates are skipped by the delivery pipeline."},{"n":"subject","r":true,"t":"string","info":"Email subject line. Supports {{variable}} interpolation."},{"n":"templateCode","r":true,"t":"string","info":"Machine-readable template key (e.g. order-confirmation, po-submitted). Unique within the Company."},{"n":"triggerEntity","t":"string","info":"Entity name whose state transition fires this template (e.g. 'Sales Order'). Null for manually-triggered emails."},{"n":"triggerState","t":"string","info":"The lifecycle state transition that triggers delivery (e.g. 'Completed'). Used with triggerEntity to wire automatic sends."},{"n":"variables","r":true,"t":"array","info":"Documents available merge fields for this template."}],"ext":"OperationalDocument","related":["Email Log"],"bv":{"rules":[{"rule":"Must be unique within the Company and follow kebab-case naming","when":"always","field":"TemplateCode","severity":"error"},{"rule":"Must be a verified sender identity in the Company's SES configuration","when":"always","field":"FromEmail","severity":"error"},{"rule":"All {{variable}} placeholders must have a matching entry in the variables array","when":"always","field":"BodyHtml","severity":"warning"}],"lifecycle":{"states":["Draft","Active","Inactive"],"transitions":[{"to":"Active","from":"Draft","conditions":["Subject and bodyHtml are non-empty","fromEmail is a verified SES identity"]},{"to":"Inactive","from":"Active","conditions":["Manual deactivation or replacement by newer template"]},{"to":"Active","from":"Inactive","conditions":["Re-activation by admin"]},{"to":"Draft","from":"Active","conditions":["Template pulled back for revision"]}],"initialState":"Draft"},"calculations":[{"name":"sendCount","formula":"COUNT(Email Log WHERE template = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Each sent email creates an immutable Email Log entry referencing this template","entity":"Email Log"}]}},{"name":"Employee","class":"Operational","subsystem":"CONNECT","area":"Organization","desc":"A staff member with login credentials, a role, a default location, and an hourly rate.","status":"draft","properties":[{"n":"address","t":"valueType","vt":"Address","info":"Employee's personal address."},{"n":"changePasswordOnNextLogin","r":true,"t":"boolean","info":"Flag requiring password change on next login."},{"n":"email","r":true,"t":"string","u":true},{"n":"employeeId","r":true,"t":"string"},{"n":"employeeNo","t":"string","info":"Human-readable employee number."},{"n":"expirationDate","t":"datetime","info":"Account expiration date. Null for non-expiring accounts."},{"n":"firstName","r":true,"t":"string"},{"n":"functions","r":true,"t":"array","v":["Buyer","Cashier","SalesPerson","StockHandler","Manager"],"info":"Operational functions this employee can perform. Used to filter employee references on transactional documents (e.g. PO → Buyer, Sale → Cashier / SalesPerson)."},{"n":"hourlyRate","t":"decimal"},{"n":"isManager","r":true,"t":"boolean","info":"Whether this employee has manager-level privileges."},{"n":"lastName","r":true,"t":"string"},{"n":"locations","r":true,"t":"array","re":"Location","info":"Array of EmployeeLocation sub-documents. Each entry references a Location with an isPrimary flag."},{"n":"middleName","t":"string"},{"n":"nickName","t":"string","info":"Preferred display name."},{"n":"passwordChangeDate","t":"datetime","info":"When the password was last changed."},{"n":"phone","t":"string"},{"n":"role","t":"entityDetail","re":"Employee Role"},{"n":"salesPersonType","t":"enumeration","v":["Location","Global"],"info":"Applicable when Functions includes 'SalesPerson'. Location-scoped reps sell at a single site; Global reps operate across all locations."},{"n":"status","r":true,"t":"schema","info":"EmployeeStatus inline schema capturing current document status."},{"n":"type","r":true,"t":"enumeration","v":["Location","Global"],"info":"Location: assigned to specific locations. Global: operates across all locations."},{"n":"username","r":true,"t":"string","info":"Login username for the employee."}],"ext":"OperationalDocument","shopify":"Staff / User resource","related":["Employee Role","Location","User","Purchase Order","Sale","Sales Order"],"bv":{"rules":[],"lifecycle":{"states":["Draft","Active","Archived"],"transitions":[{"to":"Active","from":"Draft","conditions":["Location assigned"]},{"to":"Archived","from":"Active","conditions":[]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"Must be assigned to a valid active Location","entity":"Location"},{"rule":"Cannot archive Employee with Sales in the current fiscal period","entity":"Sale"}]},"inlineSchemas":[{"name":"EmployeeStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status of the employee.","name":"documentStatus","type":"enumeration","values":["Draft","Active","Archived"],"required":true}]},{"name":"EmployeeLocation","extends":"OperationalSubDocument","properties":[{"info":"Whether this is the employee's primary location.","name":"isPrimary","type":"boolean","required":true},{"info":"Reference to the assigned Location.","name":"location","type":"entityDetail","relatedEntity":"Location"}]}]},{"name":"Employee Role","class":"Dictionary","subsystem":"CONNECT","area":"Organization","desc":"Named role or job function assigned to employees defining their responsibilities and access.","status":"stub","properties":[{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"permissions","r":true,"t":"array"},{"n":"roleId","r":true,"t":"string"}],"ext":"LookupEntity","related":["Employee"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Entity Action Log","class":"Ledger","subsystem":"CONNECT","area":"Platform","desc":"Immutable, append-only audit trail of all actions performed on any entity in the system. Each record captures a single action — either a field-level change (FieldChange) or a domain operation (Operation) — along with the actor, timestamp, and optional before/after values. Entities carry a denormalized recentActions array (capped at the last 5 entries) for quick display; this ledger is the authoritative system of record for the full history. Inherited entryDate maps to the action timestamp; sourceEntityType/sourceEntityId identify the target entity. Inherited createdBy maps to the acting user.","status":"draft","properties":[{"n":"actionType","r":true,"t":"enumeration","v":["FieldChange","Operation"],"info":"Discriminator: FieldChange for property-level mutations, Operation for domain events (e.g. status transition, approval, publish)."},{"n":"changes","r":true,"t":"array","info":"Structured list of field-level changes that occurred as part of this action. For FieldChange actions, contains one or more entries detailing each property that was modified. For Operation actions, the array may be empty when the operation has no field-level side effects (e.g. 'print', 'export')."},{"n":"code","r":true,"t":"string","info":"Stable, machine-readable action identifier (e.g. 'status.transition', 'price.update', 'approve', 'line.add'). Provides an enumerable key for building reports, dashboards, and automation triggers without parsing the description or deriving intent from actionType alone. While actionType captures the category, code captures the semantic intent of the action."},{"n":"description","r":true,"t":"string","info":"Human-readable summary of what happened and why (e.g. 'Status changed from Draft to Active', 'Approved by manager', 'Quantity updated on 3 lines'). Serves as the display text in activity feeds and audit UIs."},{"n":"entityNo","t":"string","info":"Human-readable identifier from the source entity (e.g. productNo, salesOrderNo) at the time of the action. Denormalized for display without a join."},{"n":"metadata","t":"object","info":"Freeform context about the action. May include source IP, originating system, batch ID, or other operational context."},{"n":"subDocumentId","t":"uuid","info":"UUID of the sub-document/line item the action was performed on (e.g. a Purchase Order Line, Shipment Carton). Null when the action is at the header/entity level."},{"n":"subDocumentType","t":"string","info":"Sub-document type name (e.g. 'PurchaseOrderLine', 'ShipmentCarton'). Null when the action is at the header/entity level. Used alongside subDocumentId for indexed lookups."}],"ext":"LedgerEntry","related":[],"bv":{"rules":[{"rule":"When actionType is FieldChange, the changes array must contain at least one entry","when":"create","field":"actionType","severity":"error"},{"rule":"Must reference an existing entity of the specified entityType","when":"create","field":"entityId","severity":"error"},{"rule":"Records are immutable once written — no updates or deletes permitted","when":"always","field":"*","severity":"error"}],"calculations":[],"crossEntityConstraints":[]},"inlineSchemas":[{"name":"ActionChange","schema":"schemas/common/ActionChange.ts","properties":[{"info":"The property name that was modified (e.g. 'status', 'quantity', 'unitPrice').","name":"fieldName","type":"string","required":true},{"info":"Serialized new value after the change. Null when a property was removed/cleared.","name":"newValue","type":"string"},{"info":"Serialized old value before the change. Null when a property was set for the first time.","name":"previousValue","type":"string"}]}]},{"name":"Environment","class":"Dictionary","subsystem":"ACCESS","area":"Infrastructure","desc":"A named deployment context that scopes configuration, feature flags, and access control. Environments are dictionaries — they define the set of valid deployment targets rather than tracking runtime state. Typical values: dev (Development), qa (Quality Assurance), uat (User Acceptance Testing), prod (Production). A Client references an Environment to declare what context it operates in.","status":"draft","properties":[{"n":"code","r":true,"t":"string","info":"Human-readable key. Unique within scope."},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true}],"service":"APR Access","ext":"LookupEntity","notes":"Canonical subsystem is PLATFORM (Infrastructure). Currently registered under ACCESS pending subsystem reassignment — needs delete-and-recreate to move to PLATFORM.","related":["Client"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Franchise Group","class":"Dictionary","subsystem":"CONNECT","area":"Organization","desc":"Organizational grouping of retail locations under a common franchise operator or ownership entity.","status":"draft","properties":[{"n":"billingAddress","t":"valueType","vt":"Address"},{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"postalAddress","t":"valueType","vt":"Address"}],"ext":"LookupEntity","related":["Location","Company"],"bv":{"rules":[{"rule":"Must be unique across the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[{"name":"locationCount","formula":"COUNT(Location WHERE franchiseGroups CONTAINS this)","trigger":"query-time"},{"name":"userCount","formula":"COUNT(User WHERE franchiseGroups CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot delete while Locations are assigned","entity":"Location"}]}},{"name":"Fulfillment","class":"Transactional","subsystem":"CONNECT","area":"Sales & Orders","desc":"Process of picking, packing, and shipping items to fulfill a customer order.","status":"stub","properties":[{"n":"fulfillmentId","r":true,"t":"string"},{"n":"fulfillmentOrder","r":true,"t":"entityRef","re":"Fulfillment Order"},{"n":"lines","r":true,"t":"array","info":"Array of FulfillmentLine sub-documents. Each line records the quantity fulfilled for an item."}],"ext":"TransactionalDocument","shopify":"Fulfillment resource","related":["Fulfillment Order","Shipment"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Fulfillment Order","class":"Order","subsystem":"CONNECT","area":"Sales & Orders","desc":"Request or instruction to fulfill specific items from an order, potentially routed to different locations.","status":"stub","properties":[{"n":"fulfillmentOrderId","r":true,"t":"string"},{"n":"lines","r":true,"t":"array","info":"Array of FulfillmentOrderLine sub-documents. Each line tracks pick/pack progress for an item."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"salesOrder","r":true,"t":"entityRef","re":"Sales Order"}],"ext":"OperationalDocument","shopify":"FulfillmentOrder resource","related":["Sales Order","Location","Fulfillment","Ship Order"],"bv":{"rules":[],"lifecycle":{"states":["New","InProgress","Fulfilled","Cancelled"],"transitions":[{"to":"InProgress","from":"New","conditions":["Items being picked"]},{"to":"Fulfilled","from":"InProgress","conditions":["All items packed and shipped/ready"]},{"to":"Cancelled","from":"New","conditions":[]}],"initialState":"New"},"calculations":[{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"shipOrderCount","formula":"COUNT(Ship Order WHERE fulfillmentOrder = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Must reference a valid Sales Order","entity":"Sales Order"},{"rule":"Generates Shipment records for delivery","entity":"Shipment"}]}},{"name":"Gift Card","class":"Balance","subsystem":"CONNECT","area":"Payments & Stored Value","desc":"A stored-value instrument issued and redeemed at Sale.","status":"stub","properties":[{"n":"balance","r":true,"t":"decimal"},{"n":"expiryDate","t":"date"},{"n":"giftCardNo","r":true,"t":"string"},{"n":"issuedDate","r":true,"t":"date"}],"shopify":"GiftCard resource","related":["Customer","Sale"],"bv":{"rules":[{"rule":"Must be >= 0 at all times","when":"always","field":"Balance","severity":"error"},{"rule":"Must be after IssuedDate","when":"create","field":"ExpiryDate","severity":"error"}],"lifecycle":{"states":["Active","Depleted","Expired","Cancelled"],"transitions":[{"to":"Depleted","from":"Active","conditions":["Balance reaches zero"]},{"to":"Expired","from":"Active","conditions":["ExpiryDate passed"]},{"to":"Cancelled","from":"Active","conditions":["Manual cancellation"]}],"initialState":"Active"},"calculations":[],"crossEntityConstraints":[{"rule":"Payment against Gift Card must not exceed current balance","entity":"Payment"}]}},{"name":"Goods Receipt","class":"Transactional","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Confirms physical receipt of goods against a PO or ASN. Triggers inventory increase.","status":"draft","properties":[{"n":"asn","t":"entityRef","re":"Advanced Shipping Notice"},{"n":"fees","r":true,"t":"array","info":"Receipt-level fees."},{"n":"fiscalDate","t":"datetime","info":"Fiscal date for accounting period assignment."},{"n":"isMatched","r":true,"t":"boolean","info":"Whether this receipt has been matched to a purchase order for three-way matching."},{"n":"lines","r":true,"t":"array","info":"Array of GoodsReceiptLine sub-documents. Each line records a received Item, quantity, and cost against a Purchase Order."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"postedDate","t":"datetime","info":"Date the receipt was posted and inventory updated."},{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"purchaseReceiptDate","r":true,"t":"datetime","info":"Date the goods were physically received."},{"n":"purchaseReceiptNo","r":true,"t":"string"},{"n":"reversedPurchaseReceiptId","t":"string","info":"ID of the receipt this reverses, if this is a reversal."},{"n":"reversingPurchaseReceiptId","t":"string","info":"ID of the reversal receipt, if this receipt has been reversed."},{"n":"status","r":true,"t":"schema","info":"GoodsReceiptStatus inline schema with documentStatus and operationalStatus."},{"n":"type","r":true,"t":"enumeration","v":["Purchase","Return"],"info":"Receipt type — Purchase for incoming goods, Return for vendor returns."},{"n":"vendor","r":true,"t":"entityDetail","re":"Vendor","info":"The vendor supplying the goods."},{"n":"vendorInvoiceId","t":"string","info":"Reference to associated vendor invoice for matching."}],"ext":"TransactionalDocument","related":["Purchase Order","Advanced Shipping Notice","Location","Stock Ledger"],"bv":{"rules":[{"rule":"Cannot exceed PO line outstanding quantity unless over-receive is enabled","when":"always","field":"ReceivedQty","severity":"error"}],"lifecycle":{"states":["Draft","Posted"],"transitions":[{"to":"Posted","from":"Draft","conditions":["All received quantities validated","Stock Ledger entries written"]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid open or partially received PO","entity":"Purchase Order"},{"rule":"Posting writes Stock Ledger entries for received items","entity":"Stock Ledger"},{"rule":"Posting increments Item Stock at the receiving Location","entity":"Item Stock"}]},"inlineSchemas":[{"name":"GoodsReceiptStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status.","name":"documentStatus","type":"enumeration","values":["Draft","Processing","Posted"],"required":true},{"info":"Operational sub-status for reversal tracking.","name":"operationalStatus","type":"enumeration","values":["Reversed","Complete","Reversal"]}]}]},{"name":"Hs Code","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Harmonized System (HS) tariff classification code maintained by the World Customs Organization. Hierarchical 6–10 digit codes used for customs declarations, duty rate determination, and trade compliance. The first 6 digits are internationally standardized; digits 7–10 are country-specific extensions.","status":"draft","properties":[{"n":"chapter","r":true,"t":"string","info":"First 2 digits — the HS chapter (e.g. 61 = Articles of apparel, knitted or crocheted)."},{"n":"heading","r":true,"t":"string","info":"Digits 3–4 — the HS heading within the chapter (e.g. 6109 = T-shirts, singlets, and other vests)."},{"n":"subheading","t":"string","info":"Digits 5–6 — the HS subheading (e.g. 610910 = Of cotton). Null for chapter/heading-level codes."},{"n":"countryExtension","t":"string","info":"Digits 7–10 — country-specific tariff schedule extension (e.g. HTS for US, CN for EU). Null for internationally-standardized 6-digit codes."},{"n":"dutyRate","t":"decimal","info":"Default duty rate percentage for this classification. May be overridden by trade agreements or country-specific schedules."},{"n":"country","t":"entityDetail","re":"Country","info":"The country whose tariff schedule this extended code belongs to. Null for universal 6-digit HS codes."}],"ext":"LookupEntity","related":["Product","Country"]},{"name":"Item","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"A specific sellable variant of a Product (e.g. size/color combination). Has its own SKU, barcodes, costs, prices, and item-level commerce flags.","status":"draft","properties":[{"n":"allocationStartDate","t":"datetime"},{"n":"attributeValues","t":"array","re":"Attribute","info":"Nullish in Zod — not required at creation time."},{"n":"availableDate","t":"datetime"},{"n":"barcodes","t":"array","info":"Array of barcode objects, each with barcode string and isPrimary flag. Nullish in Zod — not required at creation time."},{"n":"basePrice","t":"decimal","info":"Item-level override of Product.DefaultBasePrice. The sticker price for this variant before price-level overrides."},{"n":"blockDiscount","r":true,"t":"boolean"},{"n":"canBackorder","r":true,"t":"boolean"},{"n":"canPreOrder","r":true,"t":"boolean"},{"c":true,"n":"currentUnitCost","t":"decimal","info":"Calculated, method-agnostic. Quantity-weighted roll-up across all Item Stock rows for this Item of Item Stock.unitCost — the current per-unit inventory value under each row's configured costing method (FIFO = oldest remaining layer, LIFO = newest, WAC = running average). Cached read from the Stock Ledger Service's InventoryPositionChanged events; the Stock Ledger is the source of truth. Null if the item has no Item Stock rows with positive on-hand qty."},{"n":"discontinuedDate","t":"datetime"},{"n":"dropshipEligibility","t":"enumeration","v":["Available","Required","Unavailable"]},{"c":true,"n":"firstOrderedAt","t":"datetime","info":"Earliest timestamp this Item (SKU/variant) appeared on a purchase order. Roll-up (MIN) of Item Stock.firstOrderedAt across all locations. Item Stock is the immediate source; ultimate SoR is the PO subsystem (PurchaseOrderLine activity). Null if never ordered."},{"c":true,"n":"firstReceivedAt","t":"datetime","info":"Earliest timestamp this Item (SKU/variant) was received into any location. Roll-up (MIN) of Item Stock.firstReceivedAt across all locations holding this Item. Item Stock is the immediate source; ultimate SoR is Stock Ledger Service (RECEIPT entries). Null if never received."},{"c":true,"n":"firstSoldAt","t":"datetime","info":"Earliest timestamp this Item (SKU/variant) was sold at any location. Roll-up (MIN) of Item Stock.firstSoldAt across all locations holding this Item. Item Stock is the immediate source; ultimate SoR is Stock Ledger Service (SALE entries). Null if never sold."},{"n":"isDiscontinued","r":true,"t":"boolean"},{"n":"isFinalSale","r":true,"t":"boolean"},{"n":"isLrpEligible","r":true,"t":"boolean","info":"Eligible for loyalty rewards program."},{"n":"isReplenishment","r":true,"t":"boolean"},{"n":"itemName","t":"string","info":"Calculated field. Concatenation of the currently set AttributeValue names on this item separated by a space (e.g. 'Red Large Cotton')."},{"n":"itemNo","r":true,"t":"string"},{"c":true,"n":"lastOrderedAt","t":"datetime","info":"Most recent timestamp this Item (SKU/variant) appeared on a purchase order. Roll-up (MAX) of Item Stock.lastOrderedAt across all locations. Item Stock is the immediate source; ultimate SoR is the PO subsystem (PurchaseOrderLine activity). Null if never ordered."},{"c":true,"n":"lastOrderedCost","t":"decimal","info":"Calculated field. Roll-up of VendorItemValue.lastOrderedCost across all vendors for this Item — the unit cost from the single most recent Purchase Order line (regardless of vendor). Null if the item has never been ordered. For the per-vendor value, see VendorItemValue.lastOrderedCost."},{"c":true,"n":"lastReceivedAt","t":"datetime","info":"Most recent timestamp this Item (SKU/variant) was received into any location. Roll-up (MAX) of Item Stock.lastReceivedAt across all locations holding this Item. Item Stock is the immediate source; ultimate SoR is Stock Ledger Service (RECEIPT entries). Null if never received."},{"c":true,"n":"lastReceivedCost","t":"decimal","info":"Calculated field. Roll-up of VendorItemValue.lastReceivedCost across all vendors for this Item — the unit cost from the single most recent received inventory transaction (regardless of vendor). Sourced from the Cost Ledger. Null if the item has never been received. For the per-vendor value, see VendorItemValue.lastReceivedCost."},{"c":true,"n":"lastSoldAt","t":"datetime","info":"Most recent timestamp this Item (SKU/variant) was sold at any location. Roll-up (MAX) of Item Stock.lastSoldAt across all locations holding this Item. Item Stock is the immediate source; ultimate SoR is Stock Ledger Service (SALE entries). Null if never sold."},{"n":"measurements","t":"schema","info":"Item-level override of Product.defaultMeasurements. Variant-specific height/length/width/weight. Nullish — when unset, the Item inherits Product.defaultMeasurements at read time. Shape defined by the ItemMeasurements inline schema."},{"n":"media","t":"array","info":"Array of ItemMedia inline schema objects. Each entry represents a media asset (image, thumbnail, or video) associated with the item."},{"n":"optionValues","t":"array<OptionValue>","re":"Option","info":"Array of OptionValue objects ({ code: string, name: string|null, option: EntityDetail→Option, aliases: string[]|null, priceModifier: decimal|null, vendorCostModifiers: VendorOptionCostModifier[]|null }). Each VendorOptionCostModifier is { costModifier: decimal, vendor: EntityDetail→Vendor }. Price modifiers are flat; cost modifiers are per-vendor. IMPORTANT: These are relative deltas representing the impact of selecting this option on line-level price/cost (e.g. +$5 for engraving). They do NOT create entries in the Price Ledger or Cost Ledger. Contrast with the Price Adjustment and Cost Adjustment transactional entities which DO write to ledgers. Nullish in Zod — not required at creation time."},{"n":"preferredVendors","r":true,"t":"array","info":"Array of ItemPreferredVendor inline schema objects. One entry per Franchise Group, designating the Vendor that group prefers to source this Item from. Item-level override of Product.preferredVendors per Franchise Group — if an Item entry is absent for a given Franchise Group, Product.preferredVendors is used. Referenced Vendor must already exist in Item.vendors[] (VendorItemValue). At most one preferred vendor per Franchise Group. Nullish — not required at creation time."},{"n":"prices","t":"array<ItemPrice>","re":"Price Level","info":"Array of ItemPrice inline schema objects. Overrides Product.DefaultPrices for this Item. One entry per Price Level. Nullish in Zod — not required at creation time."},{"n":"salesChannels","t":"array<SalesChannelItemValue>","re":"Sales Channel","info":"Per-channel publish state for this item. Nullish in Zod — not required at creation time."},{"n":"salesVelocity","t":"enumeration","v":["High","Medium","Low"]},{"n":"sku","t":"string"},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the item. Tracks current state and who/when it was last changed."},{"n":"stockLimits","t":"array<StockLimitItemValue>","re":"Stock Limit Group","info":"Per stock-limit-group min/max thresholds by location and period. Nullish in Zod — not required at creation time."},{"n":"vendors","t":"array<VendorItemValue>","re":"Vendor","info":"Array of VendorItemValue inline schema objects. Item-level override of Product.vendors[].costs per Vendor × Cost Level. Nullish in Zod — not required at creation time."},{"n":"weeksOfSupply","t":"integer","info":"Weeks of supply for this item. Inherited from the parent Product's weeksOfSupply on creation but can be overridden at the Item level."}],"ext":"OperationalDocument","shopify":"ProductVariant resource","related":["Product","Item Stock","Price Level","Vendor","Sales Channel","Stock Limit Group","Franchise Group"],"bv":{"rules":[{"rule":"Must be globally unique across the Company","when":"always","field":"SKU","severity":"error"},{"rule":"Must conform to GTIN-12 or GTIN-13 format if provided","when":"always","field":"UPC","severity":"warning"},{"rule":"Each preferredVendors[].vendor must reference a Vendor that is present in Item.vendors[].vendor (VendorItemValue)","when":"always","field":"preferredVendors","severity":"error"},{"rule":"franchiseGroup must be unique within preferredVendors — at most one preferred vendor per Franchise Group","when":"always","field":"preferredVendors","severity":"error"},{"rule":"For any Franchise Group not present in Item.preferredVendors, Product.preferredVendors is inherited at read time","when":"read","field":"preferredVendors","severity":"info"}],"lifecycle":{"states":["Draft","Active","Archived"],"disallowed":[{"to":"Draft","from":"Active","reason":"Items cannot revert to Draft once activated"},{"to":"Draft","from":"Archived","reason":"Items cannot revert to Draft once activated"}],"transitions":[{"to":"Active","from":"Draft","conditions":["Parent Product is Active","SKU is assigned"]},{"to":"Archived","from":"Active","conditions":["No open order lines reference this Item"]},{"to":"Active","from":"Archived","conditions":["Parent Product is Active"]}],"initialState":"Draft","terminalExits":["Draft"]},"calculations":[{"info":"Concatenation of the currently set AttributeValue names separated by a space (e.g. 'Red Large Cotton'). Recalculated when attributeValues change.","name":"itemName","formula":"CONCAT(attributeValues[].name, ' ')","trigger":"on-write"},{"name":"vendorCount","formula":"COUNT(DISTINCT vendor via vendors)","trigger":"query-time"},{"name":"salesChannelCount","formula":"COUNT(DISTINCT salesChannel via Product.salesChannels)","trigger":"query-time"},{"name":"priceCount","formula":"COUNT(prices)","trigger":"query-time"},{"info":"Per-vendor. Unit cost from the most recent Receipt entry in the Stock Ledger Service for this Item × Vendor. Event-sourced — CONNECT does not compute this natively; it is a cached read updated when the Stock Ledger publishes LedgerEntryCreated with txType='Receipt' for this Item × Vendor pairing. Stock Ledger is the source of truth.","name":"VendorItemValue.lastReceivedCost","formula":"read-through from Stock Ledger Service: FIRST(LedgerEntry.unitCost ORDER BY transactionDate DESC WHERE item = self.item AND vendor = self.vendor AND txType = 'Receipt')","trigger":"event: LedgerEntryCreated(txType=Receipt) from Stock Ledger Service"},{"info":"Per-vendor. Unit cost from the most recent Purchase Order line for this Item × Vendor. POs live in CONNECT (out-of-scope for Stock Ledger Service v1), so this is computed from CONNECT's PO module on PO line write.","name":"VendorItemValue.lastOrderedCost","formula":"FIRST(PurchaseOrderLine.unitCost ORDER BY PurchaseOrderLine.orderDate DESC WHERE PurchaseOrderLine.item = self.item AND PurchaseOrderLine.vendor = self.vendor)","trigger":"on-po-line-write (CONNECT PO module)"},{"info":"Item-level roll-up across all vendors. Unit cost from the single most recent Receipt LedgerEntry in the Stock Ledger Service for this Item regardless of vendor. Event-sourced cached read.","name":"lastReceivedCost","formula":"read-through from Stock Ledger Service: FIRST(LedgerEntry.unitCost ORDER BY transactionDate DESC WHERE item = self AND txType = 'Receipt')","trigger":"event: LedgerEntryCreated(txType=Receipt) from Stock Ledger Service"},{"info":"Item-level roll-up across all vendors. Unit cost from the single most recent Purchase Order line for this Item regardless of vendor. Computed from CONNECT PO module (POs are not in Stock Ledger Service v1 scope).","name":"lastOrderedCost","formula":"FIRST(PurchaseOrderLine.unitCost ORDER BY PurchaseOrderLine.orderDate DESC WHERE PurchaseOrderLine.item = self)","trigger":"on-po-line-write (CONNECT PO module)"},{"info":"Method-agnostic per-unit inventory value for this Item, rolled up across all Item Stock rows (locations). Weighted by on-hand qty across rows, where each row's unitCost reflects its own configured costingMethod (FIFO=oldest remaining layer, LIFO=newest, WAC=running average). Cached read derived from Item Stock.unitCost values, which are themselves event-sourced from Stock Ledger Service's InventoryPositionChanged events. Null if no Item Stock rows have positive on-hand qty.","name":"currentUnitCost","formula":"SUM(ItemStock.unitCost * ItemStock.onHand) / SUM(ItemStock.onHand) WHERE ItemStock.item = self AND ItemStock.onHand > 0","trigger":"event: InventoryPositionChanged from Stock Ledger Service (propagated via Item Stock)"}],"crossEntityConstraints":[{"rule":"Must belong to a valid Product","when":"always","entity":"Product"},{"rule":"Cannot archive Item with non-zero stock at any Location","when":"archive","entity":"Item Stock"},{"rule":"preferredVendors[].vendor must resolve to an Active Vendor within the Company","when":"always","entity":"Vendor"}]},"inlineSchemas":[{"name":"ItemMedia","schema":"schemas/item/ItemMedia.ts","properties":[{"n":"images","t":"array","re":"Media","info":"Item image assets."},{"n":"thumbnails","t":"array","re":"Media","info":"Thumbnail image assets."},{"n":"videos","t":"array","re":"Media","info":"Video assets."}]},{"name":"ItemPrice","schema":"schemas/item/ItemPrice.ts","properties":[{"name":"price","type":"decimal","required":true},{"name":"priceLevel","type":"entityDetail","required":true,"relatedEntity":"Price Level"}]},{"name":"ItemStatus","schema":"schemas/item/ItemStatus.ts","properties":[{"info":"Current lifecycle state of the item.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]},{"name":"VendorCost","info":"Shared with Product — see Product.inlineSchemas.VendorCost","schema":"schemas/product-common/VendorCost.ts"},{"name":"ItemBarcode","schema":"schemas/item/ItemBarcode.ts","properties":[{"info":"GTIN-validated string","name":"barcode","type":"string","required":true},{"name":"isPrimary","type":"boolean","required":true}]},{"name":"OptionValue","desc":"A single selectable value within an Option's value set, as assigned to an Item. Extends LookupEntityValue — inherits id, identifiers, code, name, aliases, isActive, isDeleted, isDefault, sequence, audit fields, and customData.","schema":"schemas/product-common/OptionValue.ts","extends":"LookupEntityValue","properties":[{"info":"Reference to the parent Option dictionary entity this value belongs to.","name":"option","type":"entityDetail","required":true,"relatedEntity":"Option"},{"info":"A +/- difference the option value applies to the line-level price. This is a relative modifier, not a transactional adjustment — does not write to the Price Ledger.","name":"priceModifier","type":"decimal"},{"name":"vendorCostModifiers","type":"array<VendorOptionCostModifier>"}]},{"name":"AttributeValue","schema":"schemas/product-common/AttributeValue.ts","properties":[{"info":"Reference to the parent Attribute dictionary entity this value belongs to.","name":"attribute","type":"entityDetail","required":true,"relatedEntity":"Attribute"},{"name":"code","type":"string","required":true},{"name":"name","type":"string"},{"info":"Ordinal position of this value within the parent Attribute (e.g. 1 = first colour, 2 = second colour).","name":"sequence","type":"integer"},{"name":"aliases","type":"array<string>"}]},{"name":"VendorItemValue","schema":"schemas/item/VendorItemValue.ts","properties":[{"name":"barcodes","type":"array<ItemBarcode>","required":true},{"name":"baseCost","type":"decimal"},{"name":"canDropship","type":"boolean","required":true},{"name":"costs","type":"array<VendorCost>","required":true},{"name":"isPrimary","type":"boolean","required":true},{"name":"minOrderQty","type":"decimal"},{"name":"sku","type":"string"},{"name":"unitOfMeasure","type":"enumeration","values":["Case","Unit"],"required":true},{"name":"unitOfMeasureQty","type":"decimal"},{"name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"},{"info":"Calculated field. Unit cost from the most recent received inventory transaction for this Item from this specific Vendor. Sourced from the Cost Ledger. Null if never received from this vendor. Item.lastReceivedCost is the roll-up across all vendors.","name":"lastReceivedCost","type":"decimal","calculated":true},{"info":"Calculated field. Unit cost from the most recent Purchase Order line for this Item from this specific Vendor. Null if never ordered from this vendor. Item.lastOrderedCost is the roll-up across all vendors.","name":"lastOrderedCost","type":"decimal","calculated":true}]},{"name":"ItemMeasurements","schema":"schemas/item/ItemMeasurements.ts","properties":[{"name":"height","type":"string"},{"name":"length","type":"string"},{"name":"weight","type":"string"},{"name":"width","type":"string"}]},{"name":"ItemPreferredVendor","info":"Per-Franchise-Group preferred vendor override for this Item. Item-level override of Product.preferredVendors for the same Franchise Group — if unset for a given Franchise Group, the Item inherits Product.preferredVendors. The referenced Vendor MUST already exist in Item.vendors[].vendor (VendorItemValue) — preferred vendor cannot be an un-linked vendor. At most one entry per Franchise Group.","schema":"schemas/item/ItemPreferredVendor.ts","extends":"OperationalSubDocument","properties":[{"info":"The Franchise Group this preferred vendor applies to.","name":"franchiseGroup","type":"entityDetail","required":true,"relatedEntity":"Franchise Group"},{"info":"The Vendor this Franchise Group prefers to source this Item from. Must reference a Vendor that is present in Item.vendors[].vendor (VendorItemValue).","name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"}]},{"name":"StockLimitItemValue","schema":"schemas/item/StockLimitItemValue.ts","properties":[{"name":"maxStockLimit","type":"decimal"},{"name":"minStockLimit","type":"decimal"},{"name":"stockLimitGroup","type":"entityDetail","required":true,"relatedEntity":"Stock Limit Group"},{"name":"stockLimitLocation","type":"entityDetail","required":true,"relatedEntity":"Location"},{"info":"Time period for stock limit evaluation (e.g. Weekly, Monthly). Not a persisted entity — a code + name label pair representing the replenishment cycle.","name":"stockLimitPeriod","type":"nonIdentifiableEntityDetail","required":true}]},{"name":"SalesChannelItemValue","schema":"schemas/item/SalesChannelItemValue.ts","properties":[{"name":"isPublished","type":"boolean","required":true},{"name":"salesChannel","type":"entityDetail","required":true,"relatedEntity":"Sales Channel"}]},{"name":"VendorOptionCostModifier","schema":"schemas/product-common/VendorOptionCostModifier.ts","properties":[{"info":"A +/- difference the option value applies to the vendor cost. This is a relative modifier, not a transactional adjustment — does not write to the Cost Ledger.","name":"costModifier","type":"decimal","required":true},{"name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"}]}],"inheritance":{"parentEntity":"Product","overridableProperties":["basePrice","dropshipEligibility","measurements","prices","preferredVendors"]}},{"name":"Item Stock","class":"Operational","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Current-state inventory projection per Item × Location. A mutable, continuously-updated snapshot of stock quantities (on_hand, committed, incoming, reserved, safety_stock, damaged, QC) derived from Stock Ledger entries or synced from an external inventory management system. Not an immutable record — recalculated as movements flow in.","status":"reviewed","properties":[{"c":true,"n":"baseTotalCost","t":"decimal","info":"totalCost converted to the Company's base/reporting currency. Null if currencyCode already equals the Company's base currency. Used for cross-location consolidated valuation reports. Cached read from the Stock Ledger Service."},{"n":"costingMethod","r":true,"t":"enumeration","v":["FIFO","LIFO","WAC"],"info":"Effective inventory costing method for this Item × Location. On creation, inherits from Company.defaultCostingMethod; may be overridden per the Stock Ledger Service PRD. Changing this value after posting entries requires an offline replay job — it is not a hot-path edit."},{"n":"currencyCode","r":true,"t":"string","info":"ISO 4217 currency code for unitCost and totalCost. Typically matches the Company's baseCurrencyCode but may differ for locations operating in a different currency. Mirrors Stock Ledger InventoryPosition.currencyCode."},{"c":true,"n":"firstOrderedAt","t":"datetime","info":"Earliest timestamp a purchase order line was placed for this Item × Location. Derived from PurchaseOrderLine — PO is upstream of the Stock Ledger, so this is aggregated in CONNECT rather than read-through from the Stock Ledger Service. Null until the first PO line is created. Item-level firstOrderedAt = MIN across Item Stock rows for the Item."},{"c":true,"n":"firstReceivedAt","t":"datetime","info":"Earliest timestamp this Item was received at this Location. Read-through projection from Stock Ledger Service (receipt-type movements: PO receipt, transfer-in, return-to-stock). Null until the first receipt posts. Item-level firstReceivedAt = MIN across Item Stock rows for the Item (per read-through convention)."},{"c":true,"n":"firstSoldAt","t":"datetime","info":"Earliest timestamp this Item was sold at this Location. Read-through projection from Stock Ledger Service (sale-type movements: POS sale, e-com fulfilment originating at this Location). Null until the first sale posts. Introduction-date / sell-through analytics. Item-level firstSoldAt = MIN across Item Stock rows for the Item."},{"n":"itemNo","r":true,"t":"integer"},{"c":true,"n":"lastOrderedAt","t":"datetime","info":"Most recent timestamp a purchase order line was placed for this Item × Location. Derived from PurchaseOrderLine (PO upstream of Ledger; aggregated in CONNECT, not read-through from Stock Ledger Service). Used for replenishment recency and open-to-buy. Item-level lastOrderedAt = MAX across Item Stock rows for the Item."},{"c":true,"n":"lastReceivedAt","t":"datetime","info":"Most recent timestamp this Item was received at this Location. Read-through projection from Stock Ledger Service (receipt-type movements: PO receipt, transfer-in, return-to-stock). Drives replenishment cadence and aged-inbound reporting. Item-level lastReceivedAt = MAX across Item Stock rows for the Item."},{"c":true,"n":"lastSoldAt","t":"datetime","info":"Most recent timestamp this Item was sold at this Location. Read-through projection from Stock Ledger Service (sale-type movements: POS sale, e-com fulfilment originating at this Location). Primary signal for slow-mover / aged-stock reporting. Item-level lastSoldAt = MAX across Item Stock rows for the Item."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"locationQtys","r":true,"t":"schema","info":"Map of location IDs to stock quantity breakdowns. Each entry contains on-hand, committed, incoming, reserved, and other quantity dimensions."},{"n":"productCode","r":true,"t":"string","info":"Product code for the item."},{"n":"stockBin","t":"entityRef","re":"StockBin"},{"c":true,"n":"totalCost","t":"decimal","info":"Total cost of on-hand inventory for this Item × Location under the configured costingMethod. Sum across remaining lots under FIFO/LIFO; qtyOnHand × running-average under WAC. Cached read from the Stock Ledger Service's InventoryPosition. Basis for inventory valuation reports."},{"c":true,"n":"unitCost","t":"decimal","info":"Current per-unit inventory cost under the configured costingMethod. FIFO = unit cost of the oldest remaining lot; LIFO = unit cost of the newest remaining lot; WAC = totalCost / qtyOnHand. Cached read from the Stock Ledger Service's InventoryPosition; the Stock Ledger is the source of truth. Updated via InventoryPositionChanged events."}],"shopify":"InventoryLevel resource","notes":"Sourcing for the six computed datetime fields on Item Stock (firstReceivedAt, lastReceivedAt, firstOrderedAt, lastOrderedAt, firstSoldAt, lastSoldAt) splits across two upstreams. Received/Sold pairs (4 of 6) are read-through projections from the Stock Ledger Service, updated via InventoryPositionChanged — consistent with the existing cost-field pattern. The Ordered pair is sourced from PurchaseOrderLine in CONNECT, NOT the Stock Ledger Service: the ledger sees receipts, not PO creation, and expanding the Stock Ledger Service to consume PO events would breach its movement-of-inventory scope boundary from PRD v1.0. All six aggregate up to the identically-named Item-level fields via MIN (first*) / MAX (last*) per the product-read-through-must-aggregate-item convention. Renamed from ...Date to ...At on 2026-04-21 to conform to the existing Item/Product convention; the initial draft used ...Date suffix before the naming clash was caught.","related":["Item","Location","StockBin","Stock Ledger"],"bv":{"rules":[{"rule":"SOH (Stock on Hand) must not go negative unless Company settings allow negative inventory","when":"always","field":"Quantity","severity":"error"}],"lifecycle":null,"calculations":[{"name":"Available","formula":"SOH - Allocated - Reserved","trigger":"On stock movement or allocation change"},{"name":"SOH","formula":"Sum of Stock Ledger entries for Item + Location","trigger":"On any stock movement"},{"info":"Per-unit inventory cost for this Item × Location under the configured costingMethod. Cached read from the Stock Ledger Service's InventoryPosition.unitCost — not natively computed by CONNECT. Method dispatch happens inside the Stock Ledger Service: FIFO=unit cost of oldest remaining LedgerCost layer, LIFO=newest remaining layer, WAC=totalCost/qtyOnHand running average. Updated whenever the Stock Ledger publishes an InventoryPositionChanged or CostRecalculated event for this Item × Location.","name":"unitCost","formula":"read-through from Stock Ledger Service: InventoryPosition.unitCost WHERE item = self.item AND location = self.location (method-dispatched inside the service)","trigger":"event: InventoryPositionChanged or CostRecalculated from Stock Ledger Service"},{"info":"Total cost of on-hand inventory for this Item × Location under the configured costingMethod. Cached read from the Stock Ledger Service's InventoryPosition.totalCost. FIFO/LIFO: sum across remaining LedgerCost layers (qty × unitCost per layer). WAC: qtyOnHand × running-average unit cost. Source of truth is the Stock Ledger Service.","name":"totalCost","formula":"read-through from Stock Ledger Service: InventoryPosition.totalCost WHERE item = self.item AND location = self.location","trigger":"event: InventoryPositionChanged or CostRecalculated from Stock Ledger Service"},{"info":"totalCost converted to the Company's base/reporting currency for cross-location consolidated valuation. Cached read from the Stock Ledger Service's InventoryPosition.baseTotalCost. Null when currencyCode already equals Company.baseCurrencyCode. The Stock Ledger Service performs the FX conversion using the rate captured at the time of each LedgerEntry.","name":"baseTotalCost","formula":"read-through from Stock Ledger Service: InventoryPosition.baseTotalCost WHERE item = self.item AND location = self.location (null if currency = base)","trigger":"event: InventoryPositionChanged or CostRecalculated from Stock Ledger Service"},{"info":"Earliest timestamp this Item was received at this Location. Read-through projection from Stock Ledger Service, sourced from receipt-type ledger movements: PO receipt, transfer-in, return-to-stock. Follows the cost-field pattern (cached read, updated via InventoryPositionChanged). Write-once semantics per Item × Location. Aggregates up to Item.firstReceivedAt via MIN per the product-read-through-must-aggregate-item convention.","name":"firstReceivedAt","formula":"MIN(LedgerEntry.postedAt) WHERE item = self.item AND location = self.location AND movementType IN ('POReceipt','TransferIn','ReturnToStock')","trigger":"event: InventoryPositionChanged from Stock Ledger Service (first receipt)"},{"info":"Most recent timestamp this Item was received at this Location. Read-through projection from Stock Ledger Service (receipt-type ledger movements). Drives replenishment cadence and aged-inbound reporting. Aggregates up to Item.lastReceivedAt via MAX.","name":"lastReceivedAt","formula":"MAX(LedgerEntry.postedAt) WHERE item = self.item AND location = self.location AND movementType IN ('POReceipt','TransferIn','ReturnToStock')","trigger":"event: InventoryPositionChanged from Stock Ledger Service on any receipt-type movement"},{"info":"Earliest timestamp a purchase order line was placed for this Item × Location. Sourced from PurchaseOrderLine.orderedAt — NOT a read-through from the Stock Ledger Service. The ledger sees receipts, not PO creation; POs are upstream. CONNECT owns this aggregation. Aggregates up to Item.firstOrderedAt via MIN.","name":"firstOrderedAt","formula":"MIN(PurchaseOrderLine.orderedAt) WHERE item = self.item AND deliverTo = self.location","trigger":"event: PurchaseOrderLineCreated (write-once semantics per Item × Location)"},{"info":"Most recent timestamp a purchase order line was placed for this Item × Location. Sourced from PurchaseOrderLine.orderedAt (not Stock Ledger). Used for replenishment recency, open-to-buy, and reorder-gap analysis. Aggregates up to Item.lastOrderedAt via MAX.","name":"lastOrderedAt","formula":"MAX(PurchaseOrderLine.orderedAt) WHERE item = self.item AND deliverTo = self.location","trigger":"event: PurchaseOrderLineCreated or PurchaseOrderLineUpdated"},{"info":"Earliest timestamp this Item was sold at this Location. Read-through projection from Stock Ledger Service (sale-type movements: POS sale, e-com fulfilment originating at this Location). Introduction-date / sell-through analytics. Write-once per Item × Location. Aggregates up to Item.firstSoldAt via MIN.","name":"firstSoldAt","formula":"MIN(LedgerEntry.postedAt) WHERE item = self.item AND location = self.location AND movementType IN ('Sale','EcomFulfilment')","trigger":"event: InventoryPositionChanged from Stock Ledger Service (first sale)"},{"info":"Most recent timestamp this Item was sold at this Location. Read-through projection from Stock Ledger Service (sale-type movements). Primary signal for slow-mover / aged-stock reporting. Aggregates up to Item.lastSoldAt via MAX.","name":"lastSoldAt","formula":"MAX(LedgerEntry.postedAt) WHERE item = self.item AND location = self.location AND movementType IN ('Sale','EcomFulfilment')","trigger":"event: InventoryPositionChanged from Stock Ledger Service on any sale-type movement"}],"crossEntityConstraints":[{"rule":"Must reference a valid Item","entity":"Item"},{"rule":"Must reference a valid Location","entity":"Location"},{"rule":"SOH must reconcile with Stock Ledger running total for the Item/Location","entity":"Stock Ledger"},{"rule":"firstReceivedAt, lastReceivedAt, firstOrderedAt, lastOrderedAt, firstSoldAt, lastSoldAt must roll up to the parent Item's same-named fields (MIN for first*, MAX for last*) per the product-read-through-must-aggregate-item convention","entity":"Item"}]},"inlineSchemas":[{"name":"StockQuantities","extends":"OperationalSubDocument","properties":[{"info":"Available to Sell.","name":"ats","type":"integer","required":true},{"info":"Quantity available for backorder.","name":"availableForBackorder","type":"integer","required":true},{"info":"Quantity committed to open orders.","name":"committed","type":"integer","required":true},{"info":"Quantity available for e-commerce channels.","name":"ecommerceAvailable","type":"integer","required":true},{"info":"Quantity on hold.","name":"held","type":"integer","required":true},{"info":"Quantity expected from inbound transfers and purchase orders.","name":"incoming","type":"integer","required":true},{"info":"Last modification timestamp for this location's quantities.","name":"modifiedDate","type":"datetime"},{"info":"Next date when out-of-stock items become available.","name":"nextAvailableDate","type":"datetime"},{"info":"Quantity not available for sale (damaged, QC, etc.).","name":"notSellable","type":"integer","required":true},{"info":"Physical on-hand quantity at the location.","name":"onHand","type":"integer","required":true},{"info":"Quantity reserved for specific purposes.","name":"reserved","type":"integer","required":true}]}]},{"name":"Item Stock Group","class":"Dictionary","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Classification group for inventory items that share common stocking rules, replenishment strategies, or allocation behaviour.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"name","r":true,"t":"string"}],"ext":"LookupEntity","related":["Item"]},{"name":"Locale","class":"Dictionary","subsystem":"ALLPOINT","area":"Organization","desc":"IETF BCP 47 language-region definition. Determines available translations, content localization, and display formatting across the platform. Referenced by Market.localization to define supported languages per market.","status":"draft","properties":[{"n":"language","r":true,"t":"string","info":"ISO 639-1 two-letter language code (e.g. en, fr, es, de, ja, zh)."},{"n":"region","t":"entityDetail","re":"Country","info":"ISO 3166-1 country/region associated with this locale. Null for language-only locales (e.g. 'fr' without a region)."},{"n":"script","t":"string","info":"ISO 15924 script code for languages with multiple writing systems (e.g. Latn, Hans, Hant, Cyrl)."},{"n":"direction","r":true,"t":"enumeration","v":["LTR","RTL"],"info":"Text directionality. LTR for most languages, RTL for Arabic, Hebrew, etc."},{"n":"nativeName","r":true,"t":"string","info":"The locale's self-referential display name in its own language (e.g. Français, Español, 日本語)."}],"ext":"LookupEntity","related":["Market","Country"]},{"name":"Location","class":"Operational","subsystem":"CONNECT","area":"Organization","desc":"Physical or virtual point of presence (store, warehouse, online). The atomic unit for inventory and sales.","status":"draft","properties":[{"n":"baseCurrency","t":"string","info":"Default currency for transactions at this location."},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Location's configuration record in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Resolved at runtime by services that need location-scoped configuration (POS behavior, fulfillment rules, pricing overrides)."},{"n":"contacts","r":true,"t":"array","info":"Array of LocationContact sub-documents."},{"n":"emails","r":true,"t":"array","info":"Email addresses associated with this location."},{"n":"fulfillmentMethods","r":true,"t":"array","v":["LocalDelivery","ShipToCustomer","StorePickup"],"info":"Supported fulfillment methods at this location."},{"n":"groups","r":true,"t":"array","info":"Location group memberships for reporting and operations."},{"n":"locationNo","r":true,"t":"string"},{"n":"marketId","t":"string","re":"Market","info":"Reference to the Market this location belongs to."},{"n":"name","r":true,"t":"string"},{"n":"phones","r":true,"t":"array","info":"Phone numbers associated with this location."},{"n":"postalAddresses","r":true,"t":"array","info":"Physical postal addresses for this location."},{"n":"priceLevel","t":"entityDetail","re":"Price Level","info":"Default pricing tier for this location."},{"n":"schedule","r":true,"t":"schema","info":"Operating schedule with regular hours and exception dates."},{"n":"shipToAddresses","r":true,"t":"array","info":"Ship-to addresses for receiving inventory at this location."},{"n":"status","r":true,"t":"schema","info":"LocationStatus inline schema capturing current document status with audit trail."},{"n":"stockBins","r":true,"t":"array","re":"StockBin","info":"One-to-many: a Location can have many StockBins; each StockBin belongs to exactly one Location."},{"n":"taxArea","t":"string","info":"Tax jurisdiction code for this location."},{"n":"timeZone","t":"string","info":"IANA time zone identifier (e.g. America/New_York)."},{"n":"type","r":true,"t":"enumeration","v":["Office","Store","Virtual","Warehouse"],"info":"Physical or logical type of the location."},{"n":"website","t":"string","info":"Location-specific website URL."}],"ext":"OperationalDocument","shopify":"Location resource","related":["Market","Franchise Group","Item Stock","StockBin"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"always","field":"Name","severity":"error"},{"rule":"operationalStatus may only be Open when documentStatus is Active; Draft and Archived Locations must have operationalStatus = Closed","when":"on save","field":"status.operationalStatus","severity":"error"}],"lifecycle":{"states":["Draft","Active","Archived"],"transitions":[{"to":"Active","from":"Draft","conditions":["Address is complete","At least one Market assigned"]},{"to":"Archived","from":"Active","conditions":["All stock transferred out","No pending transactions"]},{"to":"Active","from":"Archived","conditions":["Address is complete","At least one Market assigned","Name and locationNo do not collide with another Active Location in the Company"]}],"initialState":"Draft"},"calculations":[{"name":"stockBinCount","formula":"COUNT(StockBin WHERE location = this)","trigger":"query-time"},{"name":"employeeCount","formula":"COUNT(Employee WHERE location = this)","trigger":"query-time"},{"name":"itemStockCount","formula":"COUNT(Item Stock WHERE location = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot archive Location with non-zero inventory balances","entity":"Item Stock"},{"rule":"Must belong to at least one Market when Active","entity":"Market"}]},"inlineSchemas":[{"name":"LocationStatus","extends":"OperationalSubDocument","properties":[{"info":"Document lifecycle state of the Location. Drives lifecycle transitions (Draft -> Active -> Archived, with Archived -> Active reactivation).","name":"documentStatus","type":"enumeration","values":["Active","Archived","Draft"],"required":true},{"info":"Operational state independent of document lifecycle. Allows an Active Location to be temporarily Closed (e.g. holiday, remodel, weather) without archiving it.","name":"operationalStatus","type":"enumeration","values":["Closed","Open"],"required":true}]},{"name":"LocationSchedule","extends":"OperationalSubDocument","properties":[{"info":"Exception dates overriding the regular schedule (holidays, special hours).","name":"exceptionDates","type":"array","required":true},{"info":"Regular weekly operating hours per day.","name":"regularHours","type":"array","required":true},{"info":"IANA time zone for schedule interpretation.","name":"timeZone","type":"string"}]}]},{"name":"Loyalty Program","class":"Dictionary","subsystem":"CONNECT","area":"Sales & Orders","desc":"A customer loyalty or rewards program. Customers may be enrolled in one or more programs that influence pricing, promotions, or point accrual.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Customer"]},{"name":"Market","class":"Operational","subsystem":"CONNECT","area":"Organization","desc":"Defines fiscal rules and hierarchy. Drives currency, tax treatment, catalogs, and price/cost levels. Supports parent-child nesting for regions.","status":"reviewed","properties":[{"n":"baseCurrency","r":true,"t":"entityDetail","re":"Currency","info":"The canonical accounting currency for all prices, costs, and monetary amounts within this market."},{"n":"catalogs","r":true,"t":"array","re":"Catalog"},{"n":"defaultCostLevel","t":"entityDetail","re":"Cost Level"},{"n":"defaultPriceLevel","t":"entityDetail","re":"Price Level"},{"n":"duties","t":"decimal"},{"n":"localization","r":true,"t":"schema","info":"Localization settings for this market — default locale, supported locales, and display formatting preferences."},{"n":"marketNo","r":true,"t":"integer"},{"n":"name","r":true,"t":"string"},{"n":"parentMarketId","t":"entityRef","re":"Market"},{"n":"salesTax","t":"decimal"}],"related":["Location","Catalog","Currency","Locale","Price Level","Cost Level","Business Entity"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"always","field":"Name","severity":"error"}],"lifecycle":null,"calculations":[{"name":"locationCount","formula":"COUNT(Location WHERE market = this)","trigger":"query-time"},{"name":"catalogCount","formula":"COUNT(catalogs)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot delete a Market with assigned Locations","entity":"Location"},{"rule":"Removing a Market may orphan Price Level assignments","entity":"Price Level"}]},"inlineSchemas":[{"name":"LocalizationSettings","desc":"Display and formatting preferences for a market's locale configuration.","properties":[{"n":"defaultLocale","r":true,"t":"entityDetail","re":"Locale","info":"The primary locale for this market. Used as the fallback when no translation exists for a requested locale."},{"n":"supportedLocales","r":true,"t":"array","re":"Locale","info":"All locales available for content and UI in this market."},{"n":"dateFormat","r":true,"t":"enumeration","v":["MM/DD/YYYY","DD/MM/YYYY","YYYY-MM-DD"],"info":"Date display format for this market."},{"n":"timeFormat","r":true,"t":"enumeration","v":["12h","24h"],"info":"Time display format — 12-hour (AM/PM) or 24-hour clock."},{"n":"decimalSeparator","r":true,"t":"enumeration","v":[".",","],"info":"Character used as the decimal point in numeric display (period for US/UK, comma for EU)."},{"n":"thousandsSeparator","r":true,"t":"enumeration","v":[",","."," ",""],"info":"Character used as the thousands grouping separator in numeric display."},{"n":"measurementSystem","r":true,"t":"enumeration","v":["Imperial","Metric"],"info":"Default measurement system for weights, dimensions, and distances."},{"n":"defaultTimezone","r":true,"t":"string","info":"IANA timezone identifier (e.g. America/New_York, Europe/London). Used for date/time display and scheduling defaults."}]}],"inheritance":{"childEntity":"Market","parentEntity":"Market","overridableDefaults":["defaultCostLevel","defaultPriceLevel"]}},{"name":"Matched Invoice Set","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Three-way match aggregate linking a Purchase Order, its Goods Receipts, and the corresponding Vendor Invoice for AP reconciliation.","status":"stub","properties":[{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"purchaseReceipts","r":true,"t":"array","re":"Goods Receipt"},{"n":"vendorInvoice","r":true,"t":"entityRef","re":"Vendor Invoice"}],"related":["Purchase Order","Goods Receipt","Vendor Invoice"]},{"name":"Media","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"A media asset (image or video) stored in the platform's media library. Tracks upload lifecycle, processing status, and original source metadata. Referenced by Product, Item, and Product Group via their media property (ProductMedia inline schema).","status":"draft","properties":[{"n":"alt","r":true,"t":"string","info":"Alt text for accessibility and SEO."},{"n":"fileErrors","t":"array<string>","info":"Error messages from file upload or processing failures."},{"n":"fileStatus","r":true,"t":"enumeration","v":["Queued","Uploading","Uploaded","Processing","Ready","Failed"],"info":"Upload and processing lifecycle state of the underlying file."},{"n":"isHostedExternal","t":"boolean","info":"Whether the media is hosted on an external CDN rather than the platform's storage. Only applicable to Image type."},{"n":"mediaErrors","t":"array<string>","info":"Errors encountered during media-specific processing (e.g. thumbnail generation, transcoding)."},{"n":"mediaStatus","r":true,"t":"schema","info":"Processing status of the media asset. Tracks whether the media is ready for use."},{"n":"mediaType","r":true,"t":"enumeration","v":["Image","Video"],"info":"Whether this asset is an image or video."},{"n":"mediaWarnings","t":"array<string>","info":"Non-fatal warnings from media processing (e.g. suboptimal resolution, missing metadata)."},{"n":"mimeType","r":true,"t":"string","info":"MIME type of the media file (e.g. image/jpeg, video/mp4)."},{"n":"originalMediaSource","r":true,"t":"schema","info":"Original source metadata including dimensions, file size, format, and source URL."},{"n":"previewUrl","t":"string","info":"URL of a lower-resolution preview image. Only applicable to Image type."},{"n":"thumbHash","t":"string","info":"ThumbHash-encoded placeholder for progressive image loading. Only applicable to Image type."},{"n":"url","r":true,"t":"string","info":"Primary URL of the media asset."}],"ext":"Identifiable","related":["Product","Item","Product Group"],"bv":{"rules":[{"rule":"Alt text is required for accessibility compliance","when":"always","field":"alt","severity":"error"},{"rule":"Must be Image or Video","when":"create","field":"mediaType","severity":"error"}],"lifecycle":{"states":["Pending","Processing","Ready","Failed"],"transitions":[{"to":"Processing","from":"Pending","conditions":["File upload completed"]},{"to":"Ready","from":"Processing","conditions":["Thumbnails generated, optimized versions created"]},{"to":"Failed","from":"Processing","conditions":["Processing error (corrupt file, unsupported format)"]},{"to":"Pending","from":"Failed","conditions":["Re-upload initiated"]}],"initialState":"Pending"},"calculations":[],"crossEntityConstraints":[{"rule":"Deleting media referenced by a Product requires confirmation","entity":"Product"},{"rule":"Deleting media referenced by an Item requires confirmation","entity":"Item"}]},"inlineSchemas":[{"name":"MediaSource","schema":"schemas/media/MediaSource.ts","properties":[{"info":"Original filename as uploaded.","name":"filename","type":"string"},{"info":"File size in bytes.","name":"fileSize","type":"integer","required":true},{"info":"File format (e.g. jpeg, png, mp4, webm).","name":"format","type":"string","required":true},{"info":"Height in pixels.","name":"height","type":"integer","required":true},{"info":"MIME type of the original file.","name":"mimeType","type":"string","required":true},{"info":"URL of the original uploaded file before any processing.","name":"url","type":"string","required":true},{"info":"Width in pixels.","name":"width","type":"integer","required":true}]},{"name":"MediaStatus","schema":"schemas/media/MediaStatus.ts","properties":[{"info":"Current processing state of the media asset.","name":"status","type":"enumeration","values":["Pending","Processing","Ready","Failed"],"required":true},{"info":"User or system actor who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Option","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"A configurable choice on a product (e.g. Engraving, Gift Wrap). OptionValues on an Item carry relative price/cost adjustment deltas that modify line-level pricing at time of sale/purchase — these are NOT transactional and do not write to Price Ledger or Cost Ledger.","status":"draft","properties":[{"n":"alias","t":"string"},{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"group","t":"string","info":"Logical grouping label for related options."},{"n":"name","r":true,"t":"string","u":true},{"n":"vendorCode","t":"string"},{"n":"optionValues","t":"array<OptionValue>","info":"The set of selectable values for this option (e.g. for a 'Color' option: Red, Blue, Green)."}],"ext":"LookupEntity","related":["Product","Item"],"bv":{"rules":[],"lifecycle":null,"calculations":[{"name":"productCount","formula":"COUNT(Product WHERE options CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[]},"inlineSchemas":[{"name":"OptionValue","desc":"A single selectable value within an Option's value set. Extends LookupEntityValue — inherits id, identifiers, code, name, aliases, isActive, isDeleted, isDefault, sequence, audit fields, and customData.","schema":"schemas/product-common/OptionValue.ts","extends":"LookupEntityValue","properties":[{"info":"A +/- difference the option value applies to the line-level price. This is a relative modifier, not a transactional adjustment — does not write to the Price Ledger.","name":"priceModifier","type":"decimal"},{"name":"vendorCostModifiers","type":"array<VendorOptionCostModifier>"}]},{"name":"VendorOptionCostModifier","schema":"schemas/product-common/VendorOptionCostModifier.ts","properties":[{"info":"A +/- difference the option value applies to the vendor cost. This is a relative modifier, not a transactional adjustment — does not write to the Cost Ledger.","name":"costModifier","type":"decimal","required":true},{"name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"}]}]},{"name":"Organization","class":"Core","subsystem":"ALLPOINT","area":"Organization","desc":"Top-level SaaS account entity. The root container for Companies, Business Entities, and platform-wide configuration. An Organization represents the subscriber — the entity that holds a contract with All Point. Multi-tenancy is enforced at the Company level, not the Organization level — and so deploymentModel (Shared/Dedicated) is a Company property, not an Organization property. An Organization can hold multiple Companies, and in principle different Companies under the same Organization can sit on different Clients with different deployment models. Supports parent/child self-referencing to model franchise relationships — a Franchisor Organization is the parent of its Franchisee Organizations, enabling cross-org catalog distribution, reporting, and shared product masters while maintaining full data isolation per tenant.","status":"stub","properties":[{"n":"children","r":true,"t":"array","re":"Organization","info":"Child Organizations in a franchise hierarchy. A Franchisor Org has Franchisee Orgs as children. Empty for standalone or leaf organizations."},{"n":"companies","r":true,"t":"array","re":"Company","info":"One-to-many. An Organization has many Companies; a Company belongs to exactly one Organization."},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Organization's configuration record in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Holds org-wide platform settings inherited by child Companies unless overridden."},{"k":true,"n":"Id","r":true,"t":"string","info":"Primary identifier (surrogate key)"},{"n":"name","r":true,"t":"string"},{"n":"organizationNo","r":true,"t":"string","u":true,"info":"Human-readable business identifier"},{"n":"parentOrganization","t":"entityRef","re":"Organization","info":"Self-referencing parent Organization. Null for root organizations (e.g. a standalone brand or a Franchisor). Set to the Franchisor Organization for Franchisee Organizations. Enables franchise hierarchy without conflating the business relationship with SaaS tenancy."},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the organization. Tracks current state and who/when it was last changed."},{"n":"type","t":"enumeration","v":["Standard","Franchisor","Franchisee"],"info":"Discriminator for organizational role. Standard: independent brand. Franchisor: parent organization that licenses to franchisees. Franchisee: operates under a franchisor's brand and catalog."}],"related":["Company","Business Entity"],"inlineSchemas":[{"name":"OrganizationStatus","schema":"schemas/organization/OrganizationStatus.ts","properties":[{"info":"Current lifecycle state of the organization.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Permission","class":"Dictionary","subsystem":"ACCESS","area":"Security & Permissions","desc":"An atomic capability claim (e.g. 'inventory:read', 'orders:write'). Grouped into Areas, bundled into Scopes, and assigned to Roles.","status":"draft","properties":[{"n":"area","r":true,"t":"entityDetail","re":"Area"},{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"permissionId","r":true,"t":"string"}],"service":"APR Access","shopify":"Access scopes (read_products, write_orders)","related":["Area","Scope","Role"],"bv":{"rules":[{"rule":"Must be unique and follow resource:action format","when":"create","field":"Key","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Permissions may be narrowed by Scope","entity":"Scope"}]}},{"name":"Price Adjustment","class":"Transactional","subsystem":"CONNECT","area":"Products & Pricing","desc":"Transactional document recording a price change applied to items, reflecting markdowns, markups, or promotional pricing. Writes entries to the Price Ledger. Distinct from option-level priceModifier deltas on OptionValues which are relative and non-transactional.","status":"stub","properties":[{"n":"adjustmentId","r":true,"t":"string"},{"n":"item","r":true,"t":"entityRef","re":"Item"},{"n":"newPrice","r":true,"t":"decimal"},{"n":"oldPrice","r":true,"t":"decimal"},{"n":"priceLevel","t":"entityDetail","re":"Price Level"},{"n":"reason","t":"string"}],"ext":"TransactionalDocument","related":["Item","Price Level","Price Ledger"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid Price Level","entity":"Price Level"},{"rule":"Must reference a valid active Item or Product","entity":"Item"}]}},{"name":"Price Ledger","class":"Ledger","subsystem":"CONNECT","area":"Products & Pricing","desc":"Immutable chronological audit log of all price changes for items across time.","status":"stub","properties":[{"n":"item","r":true,"t":"entityRef","re":"Item"},{"c":true,"n":"ledgerLine","r":true,"t":"integer"},{"n":"price","r":true,"t":"decimal"},{"n":"priceLevel","t":"entityDetail","re":"Price Level"}],"ext":"LedgerEntry","related":["Item","Price Level","Price Adjustment"],"bv":{"rules":[{"rule":"Append-only — existing entries must not be modified or deleted","when":"always","field":"LedgerLine","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Price Level","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Named pricing tier or schedule defining different prices for different customer groups, channels, or regions. Extends LookupEntity — no additional fields beyond the base.","status":"stub","properties":[],"ext":"LookupEntity","shopify":"Market-specific pricing and B2B catalogs","related":["Market","Product","Item","Price Rule"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Should be associated with at least one Market","entity":"Market"}]}},{"name":"Price Rule","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Conditional logic defining when and how prices are calculated or discounts applied.","status":"stub","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"conditions","t":"schema"},{"n":"name","r":true,"t":"string","u":true},{"n":"priceRuleId","r":true,"t":"string"}],"shopify":"PriceRule resource","related":["Price Level","Promotion","Discount"],"bv":{"rules":[{"rule":"Must resolve deterministically when multiple rules overlap","when":"always","field":"Priority","severity":"warning"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid Price Level","entity":"Price Level"}]}},{"name":"Product","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"Master product record (style/SKU group). Defines classification, attributes, options, pricing, vendors, and channel availability. Contains child Items.","status":"draft","properties":[{"n":"approval","t":"schema","info":"Approval workflow state: status (Pending Review / In Review / Approved / Rejected), approvedBy, approvedDate, reason."},{"n":"attributes","t":"array","info":"Array of ProductAttribute sub-documents. Each entry references an Attribute and records its selection position on the Product. Nullish — not required at creation time."},{"n":"brand","t":"entityDetail","re":"Brand"},{"n":"catalogs","t":"array","re":"Catalog","info":"Array of Catalog IDs the product is assigned to."},{"n":"class","r":true,"t":"enumeration","v":["Style","Single","Service","Digital","Wallet"],"info":"Determines product behavior. Style = physical, 2+ Items, requires ≥1 Attribute, inventory optionally tracked. Single = physical, 1 Item, Attributes optional, inventory optionally tracked. Service = non-physical, 1 Item, Attributes N/A, inventory cannot be tracked. Digital = non-physical/non-service, 1 Item, inventory optionally tracked. Wallet = stored-value (e.g. gift cards), may be physical, 1 Item, inventory not tracked, creates a liability on sale."},{"n":"classification","r":true,"t":"entityDetail","re":"Classification"},{"n":"code","r":true,"t":"string"},{"n":"countryOfOrigin","t":"entityDetail","re":"Country"},{"n":"defaultBasePrice","t":"decimal","info":"Sticker price before price-level overrides. Inherited by child Items unless Item.BasePrice is set."},{"n":"defaultDropshipEligibility","t":"enumeration","v":["Available","Required","Unavailable"]},{"n":"defaultMeasurements","t":"schema","info":"Default measurements (height/length/width/weight). Inherited by child Items unless Item.measurements is set. Shape defined by the ProductMeasurements inline schema."},{"n":"defaultPrices","t":"array","re":"Price Level","info":"Array of ProductPrice objects ({ price: decimal, priceLevel: EntityDetail→Price Level }). One entry per Price Level. Inherited by child Items unless overridden at Item.prices. Nullish in Zod — not required at creation time."},{"n":"description","t":"string"},{"c":true,"n":"firstOrderedAt","t":"datetime","info":"Earliest timestamp this Product appeared on a purchase order across all variants. Roll-up (MIN) of Item.firstOrderedAt across all Items belonging to this Product. Item is the immediate source; the cascade is PO subsystem → Item Stock → Item → Product. Null if never ordered."},{"c":true,"n":"firstReceivedAt","t":"datetime","info":"Earliest timestamp this Product was received into any location across all variants. Roll-up (MIN) of Item.firstReceivedAt across all Items belonging to this Product. Item is the immediate source; the cascade is Stock Ledger Service → Item Stock → Item → Product. Null if never received."},{"c":true,"n":"firstSoldAt","t":"datetime","info":"Earliest timestamp this Product was sold at any location across all variants. Roll-up (MIN) of Item.firstSoldAt across all Items belonging to this Product. Item is the immediate source; the cascade is Stock Ledger Service → Item Stock → Item → Product. Null if never sold."},{"n":"hasSerialNumber","r":true,"t":"boolean"},{"n":"hsCode","t":"entityDetail","re":"Hs Code","info":"Harmonized System tariff code for customs and duty classification."},{"n":"items","r":true,"t":"array","re":"Item"},{"c":true,"n":"lastOrderedAt","t":"datetime","info":"Most recent timestamp this Product appeared on a purchase order across all variants. Roll-up (MAX) of Item.lastOrderedAt across all Items belonging to this Product. Item is the immediate source; the cascade is PO subsystem → Item Stock → Item → Product. Null if never ordered."},{"c":true,"n":"lastReceivedAt","t":"datetime","info":"Most recent timestamp this Product was received into any location across all variants. Roll-up (MAX) of Item.lastReceivedAt across all Items belonging to this Product. Item is the immediate source; the cascade is Stock Ledger Service → Item Stock → Item → Product. Null if never received."},{"c":true,"n":"lastSoldAt","t":"datetime","info":"Most recent timestamp this Product was sold at any location across all variants. Roll-up (MAX) of Item.lastSoldAt across all Items belonging to this Product. Item is the immediate source; the cascade is Stock Ledger Service → Item Stock → Item → Product. Null if never sold."},{"n":"media","t":"array","info":"Array of ProductMedia inline schema objects. Each entry represents a media asset (image, thumbnail, or video) associated with the product."},{"n":"menus","r":true,"t":"array","re":"Product Menu"},{"n":"name","r":true,"t":"string"},{"n":"options","t":"array","re":"Option","info":"Nullish in Zod — not required at creation time."},{"n":"preferredVendors","r":true,"t":"array","info":"Array of ProductPreferredVendor inline schema objects. One entry per Franchise Group, designating the Vendor that group prefers to source this Product from. The preferred vendor may differ from ProductVendor.isPrimary (the tenant-wide primary). Inherited by child Items for the same Franchise Group unless overridden at Item.preferredVendors. Referenced Vendor must already exist in Product.vendors[]. At most one preferred vendor per Franchise Group. Nullish — not required at creation time."},{"n":"productGroups","t":"array","re":"Product Group","info":"Nullish in Zod — not required at creation time."},{"n":"productNo","r":true,"t":"string"},{"n":"salesChannels","r":true,"t":"array","re":"Sales Channel"},{"n":"seasons","t":"array","re":"Season","info":"One or more merchandising seasons, with a primary flag. Nullish in Zod — not required at creation time."},{"n":"shortName","t":"string"},{"n":"slug","t":"string","u":true,"info":"URL-friendly identifier for storefront routing and public API lookups. Equivalent to Shopify's handle property. Auto-generated from product name if not provided. Must be unique across all products."},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the product. Tracks current state and who/when it was last changed."},{"n":"stockLimitGroups","t":"array","re":"Stock Limit Group","info":"Nullish in Zod — not required at creation time."},{"n":"taxClass","r":true,"t":"entityDetail","re":"Tax Class"},{"n":"trackInventory","r":true,"t":"boolean","info":"Whether inventory quantities are tracked for this product. Optional for Style, Single, and Digital. Must be false for Service and Wallet products."},{"n":"type","t":"entityDetail","re":"Product Type"},{"n":"vendors","r":true,"t":"array","info":"Array of ProductVendor inline schema objects. Each entry links a Vendor to the product with optional primary designation and cost-level pricing. Product-level cost baseline per Vendor × Cost Level, inherited by Items unless overridden at VendorItemValues."},{"n":"weeksOfSupply","t":"integer","info":"Default weeks of supply for this product. Serves as the default value for newly created Items — Items inherit this value but can override it at the Item level."}],"ext":"OperationalDocument","shopify":"Product resource","related":["Item","Classification","Tax Class","Season","Brand","Vendor","Sales Channel","Product Menu","Product Group","Stock Limit Group","Catalog","Price Level","Franchise Group"],"bv":{"rules":[{"rule":"Must be unique across the Company","when":"create","field":"ProductNo","severity":"error"},{"rule":"Must be unique across the Company if provided","when":"always","field":"ProductCode","severity":"error"},{"rule":"The combination of attributeValues across Items must be unique within the Product — no two Items may share the same attribute value set","when":"always","field":"items","severity":"error"},{"rule":"Cannot add an Item until at least one Vendor is selected. For Style products, at least one Attribute must also be selected.","when":"item-create","field":"items","severity":"error"},{"rule":"Cannot deselect or change an Attribute if at least one child Item has a value for that Attribute","when":"update","field":"attributes","severity":"error"},{"rule":"Style products must have 2 or more Items","when":"always","field":"class","severity":"error"},{"rule":"Single, Service, Digital, and Wallet products can have at most 1 Item","when":"always","field":"class","severity":"error"},{"rule":"Attributes are not relevant to Service products","when":"always","field":"class","severity":"info"},{"rule":"Service and Wallet products cannot have trackInventory set to true","when":"always","field":"trackInventory","severity":"error"},{"rule":"Wallet products create a stored value / liability on sale","when":"always","field":"class","severity":"info"},{"rule":"Each preferredVendors[].vendor must reference a Vendor that is present in Product.vendors[].vendor","when":"always","field":"preferredVendors","severity":"error"},{"rule":"franchiseGroup must be unique within preferredVendors — at most one preferred vendor per Franchise Group","when":"always","field":"preferredVendors","severity":"error"}],"lifecycle":{"states":["Draft","Active","Archived"],"disallowed":[{"to":"Draft","from":"Active","reason":"Products cannot revert to Draft once activated"},{"to":"Draft","from":"Archived","reason":"Products cannot revert to Draft once activated"}],"transitions":[{"to":"Active","from":"Draft","conditions":["At least one Item exists","Base price is set"]},{"to":"Archived","from":"Active","conditions":["No open Sales Orders referencing active Items","Total qty on hand across all Items is zero"]},{"to":"Active","from":"Archived","conditions":[]}],"initialState":"Draft","terminalExits":["Draft"]},"calculations":[{"name":"itemCount","formula":"COUNT(items)","trigger":"query-time"},{"name":"vendorCount","formula":"COUNT(DISTINCT vendor via Item.vendors)","trigger":"query-time"},{"name":"salesChannelCount","formula":"COUNT(salesChannels)","trigger":"query-time"},{"name":"optionCount","formula":"COUNT(options)","trigger":"query-time"},{"name":"attributeCount","formula":"COUNT(attributes)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot archive Product if any child Items are Active","when":"archive","entity":"Item"},{"rule":"Cannot archive Product if total qty on hand across child Items is greater than zero","when":"archive","entity":"Item Stock"},{"rule":"Must reference a valid Classification hierarchy","when":"always","entity":"Classification"},{"rule":"preferredVendors[].vendor must resolve to an Active Vendor within the Company","when":"always","entity":"Vendor"}]},"inlineSchemas":[{"name":"VendorCost","schema":"schemas/product-common/VendorCost.ts","properties":[{"name":"cost","type":"decimal","required":true},{"name":"costLevel","type":"entityDetail","required":true,"relatedEntity":"Cost Level"}]},{"name":"ProductMedia","schema":"schemas/product/ProductMedia.ts","properties":[{"info":"Product image assets.","name":"images","type":"array","relatedEntity":"Media"},{"info":"Thumbnail image assets.","name":"thumbnails","type":"array","relatedEntity":"Media"},{"info":"Video assets.","name":"videos","type":"array","relatedEntity":"Media"}]},{"name":"ProductPrice","schema":"schemas/product-common/ProductPrice.ts","properties":[{"name":"price","type":"decimal","required":true},{"name":"priceLevel","type":"entityDetail","required":true,"relatedEntity":"Price Level"}]},{"name":"ProductSeason","schema":"schemas/product/ProductSeason.ts","properties":[{"name":"isPrimary","type":"boolean","required":true},{"name":"seasons","type":"array<entityDetail>","required":true,"relatedEntity":"Season"}]},{"name":"ProductStatus","schema":"schemas/product/ProductStatus.ts","properties":[{"info":"Current lifecycle state of the product.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]},{"name":"ProductVendor","schema":"schemas/product/ProductVendor.ts","properties":[{"info":"Reference to the Vendor entity.","name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"},{"info":"Whether this is the primary/default vendor for the product.","name":"isPrimary","type":"boolean"},{"info":"Cost per Cost Level for this vendor. Inherited by Items unless overridden.","name":"costs","type":"array<VendorCost>"}]},{"name":"AttributeValue","schema":"schemas/product-common/AttributeValue.ts","properties":[{"info":"Reference to the parent Attribute dictionary entity this value belongs to.","name":"attribute","type":"entityDetail","required":true,"relatedEntity":"Attribute"},{"name":"code","type":"string","required":true},{"name":"name","type":"string"},{"info":"Ordinal position of this value within the parent Attribute (e.g. 1 = first colour, 2 = second colour).","name":"sequence","type":"integer"},{"name":"aliases","type":"array<string>"}]},{"name":"ProductApproval","schema":"schemas/product/ProductApproval.ts","properties":[{"name":"status","type":"enumeration","values":["Pending Review","In Review","Approved","Rejected"],"required":true},{"name":"approvedBy","type":"string"},{"name":"approvedDate","type":"datetime"},{"name":"reason","type":"string"}]},{"name":"ProductAttribute","schema":"schemas/product/ProductAttribute.ts","properties":[{"info":"Reference to the selected Attribute dictionary entity (e.g. Color, Size).","name":"attribute","type":"entityDetail","required":true,"relatedEntity":"Attribute"},{"info":"The ordinal position of this attribute on the product (e.g. 1 = Attribute 1, 2 = Attribute 2).","name":"position","type":"integer","required":true}]},{"name":"ProductMeasurements","schema":"schemas/product/ProductMeasurements.ts","properties":[{"name":"height","type":"string"},{"name":"length","type":"string"},{"name":"weight","type":"string"},{"name":"width","type":"string"}]},{"name":"ProductSalesChannel","schema":"schemas/product/ProductSalesChannel.ts","properties":[{"name":"code","type":"string","required":true},{"name":"isPublished","type":"boolean","required":true},{"name":"name","type":"string"}]},{"name":"ProductPreferredVendor","info":"Per-franchise-group preferred vendor override for this Product. Each entry maps one Franchise Group to the Vendor that group prefers to source this Product from, which may differ from ProductVendor.isPrimary (the tenant-wide primary). The referenced Vendor MUST already exist in Product.vendors[].vendor — preferred vendor cannot be an un-linked vendor. At most one entry per Franchise Group (unique constraint on franchiseGroup within Product.preferredVendors).","schema":"schemas/product/ProductPreferredVendor.ts","extends":"OperationalSubDocument","properties":[{"info":"The Franchise Group this preferred vendor applies to.","name":"franchiseGroup","type":"entityDetail","required":true,"relatedEntity":"Franchise Group"},{"info":"The Vendor this Franchise Group prefers to source this Product from. Must reference a Vendor that is present in Product.vendors[].vendor.","name":"vendor","type":"entityDetail","required":true,"relatedEntity":"Vendor"}]}],"inheritance":{"childEntity":"Item","overridableDefaults":["defaultBasePrice","defaultDropshipEligibility","defaultMeasurements","defaultPrices","preferredVendors"],"nonOverridableProperties":["brand","class","classification","countryOfOrigin","hasSerialNumber","hsCode","menus","options","productGroups","salesChannels","seasons","stockLimitGroups","taxClass","trackInventory","type"]}},{"name":"Product Category","class":"Taxonomy","subsystem":"CONNECT","area":"Products & Pricing","desc":"Hierarchical product classification tree. Supports unlimited nesting depth for organizing products into browsable categories. Products can belong to multiple categories. Used for storefront navigation, reporting rollups, and merchandising rules.","status":"draft","properties":[{"n":"categoryAttributes","t":"array","info":"Attributes associated with this category. When a product is assigned to this category, these attributes are suggested or required on the product. Enables attribute inheritance from taxonomy to product."},{"n":"image","t":"entityRef","re":"Media","info":"Optional category image for storefront display."},{"n":"slug","t":"string","u":true,"info":"URL-friendly identifier for storefront routing. Auto-generated from name if not provided."}],"ext":"TaxonomyEntity","notes":"Category values follow the Google Product Taxonomy standard. This ensures consistent, industry-recognized classification across sales channels and simplifies feed generation for Google Shopping, Meta, and other marketplace integrations.","related":["Sales Channel","Media","Attribute"]},{"name":"Product Group","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"Logical grouping of products for merchandising, promotions, channel publishing, or reporting. Maps to Shopify Collection. Can be Manual (hand-picked products) or Smart (rule-driven automatic membership).","status":"draft","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"URL-friendly identifier. Maps to Shopify handle. Used as EntityDetail.code when referenced from Product."},{"n":"description","t":"string","info":"Rich text or HTML description of the group. Maps to Shopify body_html."},{"n":"disjunctive","r":true,"t":"boolean","info":"Rule matching logic: true = product matches ANY rule (OR), false = product must match ALL rules (AND). Only applicable when Type = Smart."},{"n":"displayOrder","t":"enumeration","v":["Manual","AlphaAsc","AlphaDesc","BestSelling","CreatedAsc","CreatedDesc","PriceAsc","PriceDesc"],"info":"Controls product display ordering within the group. Maps directly to Shopify sort_order."},{"n":"media","t":"schema","info":"ProductGroupMedia inline schema — images, thumbnails, and videos referencing the Media entity."},{"n":"name","r":true,"t":"string","info":"Display name. Maps to Shopify Collection title."},{"n":"products","r":true,"t":"array","re":"Product","info":"Explicit product membership (Manual type) or computed result (Smart type)."},{"n":"rules","t":"schema","info":"Smart collection rules. Array of { column, relation, condition } objects. Only applicable when Type = Smart. Maps to Shopify SmartCollection rules."},{"n":"salesChannels","r":true,"t":"array","re":"Sales Channel","info":"Which channels this group is published to. Maps to Shopify publication/published_scope."},{"n":"seo","t":"schema","info":"SEO title and description overrides for search engines. Maps to Shopify Collection SEO fields."},{"n":"sequence","t":"integer","info":"Display ordering among groups. Aligns with EntityDetail.sequence pattern on Product."},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the product group. Tracks current state and who/when it was last changed."},{"n":"type","r":true,"t":"enumeration","v":["Manual","Smart"],"info":"Manual = hand-picked product list. Smart = rule-driven automatic membership. Maps to Shopify CustomCollection vs SmartCollection."}],"shopify":"Collection resource (CustomCollection + SmartCollection)","related":["Product","Sales Channel","Promotion","Product Menu"],"bv":{"rules":["Rules array is required when Type = Smart, ignored when Type = Manual","Disjunctive is only applicable when Type = Smart","Products array is manually managed when Type = Manual, computed when Type = Smart"],"lifecycle":"Draft → Active → Archived","calculations":[{"name":"productCount","formula":"COUNT(products)","trigger":"query-time"},{"name":"salesChannelCount","formula":"COUNT(salesChannels)","trigger":"query-time"}],"crossEntityConstraints":[]},"inlineSchemas":[{"name":"ProductGroupMedia","properties":[{"n":"images","t":"array","re":"Media","info":"Product group image assets."},{"n":"thumbnails","t":"array","re":"Media","info":"Thumbnail image assets."},{"n":"videos","t":"array","re":"Media","info":"Video assets."}]},{"name":"ProductGroupStatus","schema":"schemas/product-group/ProductGroupStatus.ts","properties":[{"info":"Draft = unpublished, Active = published and visible, Archived = hidden/retired.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Product Menu","class":"Operational","subsystem":"CONNECT","area":"Products & Pricing","desc":"Curated product assortment or navigation structure for specific contexts (in-store menus, kiosk displays).","status":"stub","properties":[{"n":"menuId","r":true,"t":"string"},{"n":"name","r":true,"t":"string"},{"n":"productGroups","r":true,"t":"array","re":"Product Group"},{"n":"products","r":true,"t":"array","re":"Product"},{"n":"salesChannels","r":true,"t":"array","re":"Sales Channel"}],"related":["Product","Product Group","Sales Channel"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Product Type","class":"Taxonomy","subsystem":"CONNECT","area":"Products & Pricing","desc":"Hierarchical product type classification (e.g. Physical → Apparel, Digital → Subscription). Determines processing rules for inventory, fulfillment, and taxation. Supports unlimited nesting depth.","status":"draft","properties":[],"ext":"TaxonomyEntity","related":["Product"]},{"name":"Promotion","class":"Operational","subsystem":"CONNECT","area":"Promotions","desc":"A marketing campaign applying one or more Discounts under defined eligibility rules.","status":"stub","properties":[{"n":"discounts","r":true,"t":"array","re":"Discount"},{"n":"eligibility","t":"schema"},{"n":"endDate","t":"datetime"},{"n":"name","r":true,"t":"string"},{"n":"promotionId","r":true,"t":"string"},{"n":"startDate","t":"datetime"}],"shopify":"DiscountAutomaticNode / DiscountCodeNode","related":["Discount","Coupon","Sales Order"],"bv":{"rules":[{"rule":"StartDate must be before EndDate","when":"always","field":"DateRange","severity":"error"}],"lifecycle":{"states":["Draft","Scheduled","Active","Expired","Archived"],"transitions":[{"to":"Scheduled","from":"Draft","conditions":["Valid date range and at least one rule defined"]},{"to":"Active","from":"Scheduled","conditions":["Start date reached"]},{"to":"Expired","from":"Active","conditions":["End date passed"]},{"to":"Archived","from":"Active","conditions":[]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"May reference one or more Discount definitions","entity":"Discount"}]}},{"name":"Purchase","class":"Transactional","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"System-generated settlement record produced when the three-way match (Purchase Order + Goods Receipt + Vendor Invoice) reconciles successfully. Not independently created — represents the completed financial fact of a procurement cycle.","status":"stub","properties":[{"n":"amount","r":true,"t":"decimal","info":"Reconciled purchase amount from the matched invoice"},{"n":"date","r":true,"t":"datetime","info":"Date the three-way match was reconciled"},{"n":"goodsReceipt","r":true,"t":"entityRef","re":"Goods Receipt"},{"c":true,"n":"purchaseId","r":true,"t":"string","info":"System-generated identifier"},{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"},{"n":"vendorInvoice","r":true,"t":"entityRef","re":"Vendor Invoice"}],"ext":"TransactionalDocument","notes":"Buy-side counterpart to Sale. Automatically generated upon successful three-way match and payment reconciliation.","related":["Vendor","Purchase Order","Goods Receipt","Vendor Invoice"],"bv":{"rules":[{"rule":"System-generated — cannot be manually created or edited","when":"always","field":"PurchaseId","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a fully or partially received PO","entity":"Purchase Order"},{"rule":"Must reference a posted Goods Receipt linked to the PO","entity":"Goods Receipt"},{"rule":"Must reference a matched and approved Vendor Invoice for the same PO","entity":"Vendor Invoice"}]}},{"name":"Purchase Order","class":"Order","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Authorization to buy goods from a Vendor. Header discounts/fees for invoice matching; line discounts/fees affect item cost.","status":"draft","properties":[{"n":"actualArrivalDate","t":"datetime","info":"Actual arrival date at the ship-to location. Populated when the Goods Receipt is posted."},{"n":"actualShipDate","t":"datetime","info":"Actual ship date from the vendor's facility. Populated from the Advanced Shipping Notice or Goods Receipt."},{"n":"buyer","t":"entityRef","re":"Employee","info":"The purchasing agent responsible for this order. References an Employee whose Functions includes 'Buyer'."},{"n":"cancelReason","t":"string","info":"Reason the purchase order was cancelled, if applicable."},{"n":"currency","t":"entityDetail","re":"Currency","info":"Order currency. Defaults from the Vendor's orderCurrency."},{"n":"discountAmount","t":"decimal","info":"Header-level discount amount. Below-the-line — used for invoice matching only, does not affect item cost."},{"n":"discounts","r":true,"t":"array","info":"Header-level discount entries. Below-the-line — used for invoice matching only."},{"n":"cancelIfNotShippedByDate","t":"datetime","info":"If goods have not shipped by this date, the order may be automatically cancelled per vendor agreement."},{"n":"expectedArrivalDate","t":"datetime","info":"Expected arrival date at the ship-to location. Defaults from vendor leadTimeDays + orderDate."},{"n":"discounts","r":true,"t":"array","info":"Array of PurchaseOrderDiscount sub-documents. Header-level discounts applied to the purchase order."},{"n":"expectedShipDate","t":"datetime","info":"Expected ship date from the vendor's facility."},{"n":"fees","r":true,"t":"array","info":"Array of PurchaseOrderFee sub-documents. Header-level fees (freight, handling, duties). Below-the-line — used for invoice matching only."},{"n":"isArchived","r":true,"t":"boolean","info":"Soft archive flag. Archived POs are excluded from active views."},{"n":"lines","r":true,"t":"array","info":"Array of PurchaseOrderLine sub-documents. Each line specifies an Item, quantity, and cost for the order."},{"n":"orderDate","r":true,"t":"datetime","info":"Date the purchase order was placed."},{"n":"paymentTerms","t":"entityDetail","re":"Vendor Payment Term","info":"Payment terms for this order. Defaults from the Vendor's defaultPaymentTerms for the applicable franchise group."},{"n":"purchaseOrderNo","r":true,"t":"integer"},{"n":"shipToLocation","r":true,"t":"entityDetail","re":"Location","info":"Receiving location where goods will be delivered."},{"n":"status","r":true,"t":"schema","info":"PurchaseOrderStatus inline schema capturing current document status."},{"n":"type","r":true,"t":"enumeration","v":["Standard","Blanket","Drop Ship","Special Order"],"info":"Classification of the purchase order by purpose."},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"},{"n":"vendorReferenceNo","t":"string","info":"Vendor's own reference or confirmation number for this order."}],"ext":"OperationalDocument","shopify":"Shopify PO (Stocky)","notes":"Header Discounts/Fees are below-the-line (invoice matching only). Line Discounts/Fees affect item cost.","related":["Vendor","Employee","Goods Receipt","Purchase","Vendor Invoice","Advanced Shipping Notice","Location","Vendor Payment Term","Purchasing Fee"],"bv":{"rules":[{"rule":"Must have at least one line item before submitting","when":"submit","field":"Lines","severity":"error"},{"rule":"Defaults from latest vendor unit cost for the item × cost level when a line is added; can be overridden per PO line without changing the vendor's unit cost","when":"create","field":"LineUnitCost","severity":"info"},{"rule":"Only Style, Single, and Service products can be added to a Purchase Order","when":"line-add","field":"lines","severity":"error"},{"rule":"Must be an active Location that can receive inventory","when":"submit","field":"shipToLocation","severity":"error"},{"rule":"Defaults from Vendor orderCurrency on creation; cannot be changed after lines exist","when":"edit","field":"currency","severity":"error"}],"lifecycle":{"states":["Draft","Open","PartiallyReceived","Complete","Cancelled"],"transitions":[{"to":"Open","from":"Draft","conditions":["At least one line item exists","Vendor is Active","ShipToLocation is valid"]},{"to":"Cancelled","from":"Draft","conditions":[]},{"to":"PartiallyReceived","from":"Open","conditions":["At least one line has received qty > 0"]},{"to":"Complete","from":"Open","conditions":["All lines fully received"]},{"to":"Cancelled","from":"Open","conditions":["No Goods Receipts posted against this PO"]},{"to":"Complete","from":"PartiallyReceived","conditions":["All lines fully received or cancelled"]}],"initialState":"Draft"},"calculations":[{"name":"AmountOrdered","formula":"Sum of line (qty × unitCost)","trigger":"On line add/edit/remove"},{"name":"AmountReceived","formula":"Sum of line receivedQty × unitCost","trigger":"On receipt posting"},{"name":"AmountDue","formula":"AmountOrdered - AmountReceived","trigger":"On receipt posting"},{"name":"TotalLines","formula":"Sum of line extCost","trigger":"On line add/edit/remove"},{"name":"TotalFees","formula":"Sum of header fee amounts + sum of all line fee amounts","trigger":"On fee change"},{"name":"TotalDiscountAmount","formula":"Header discountAmount + sum of line discountAmounts","trigger":"On discount change"},{"name":"TotalAmount","formula":"TotalLines + TotalFees - TotalDiscountAmount","trigger":"On line or fee change"},{"name":"DiscountPercentage","formula":"(TotalDiscountAmount / TotalLines) × 100","trigger":"On discount change"},{"name":"QuantityOrdered","formula":"Sum of line quantities","trigger":"On line change"},{"name":"QuantityReceived","formula":"Sum of line received quantities","trigger":"On receipt posting"},{"name":"QuantityDue","formula":"QuantityOrdered - QuantityReceived","trigger":"On receipt posting"},{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"receiptCount","formula":"COUNT(Goods Receipt WHERE purchaseOrder = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Must reference a valid active Vendor","entity":"Vendor"},{"rule":"ShipToLocation must be a valid active Location with receiving capability","entity":"Location"},{"rule":"Receiving creates Goods Receipt documents","entity":"Goods Receipt"},{"rule":"Invoice matching validates against PO lines and receipts","entity":"Vendor Invoice"},{"rule":"If specified, must be valid for the selected Vendor","entity":"Vendor Payment Term"}]},"inlineSchemas":[{"name":"PurchaseOrderFee","extends":"OperationalSubDocument","properties":[{"info":"Fee amount.","name":"amount","type":"decimal","required":true},{"info":"Description of this fee.","name":"description","type":"string"},{"info":"Reference to the Purchasing Fee type.","name":"feeType","type":"entityDetail","relatedEntity":"Purchasing Fee"}]},{"name":"PurchaseOrderLine","extends":"OperationalSubDocument","properties":[{"info":"Line-level discount amount. Affects item cost.","name":"discountAmount","type":"decimal"},{"info":"Line-level expected delivery date override.","name":"expectedDate","type":"datetime"},{"info":"Extended cost (qty × unitCost − discountAmount).","name":"extCost","type":"decimal","calculated":true},{"info":"Array of PurchaseOrderFee sub-documents. Line-level fees (e.g. per-item freight, duties). Affect item cost.","name":"fees","type":"array"},{"info":"The Item being ordered.","name":"item","type":"entityRef","required":true,"relatedEntity":"Item"},{"info":"Line number within the purchase order.","name":"lineNo","type":"integer","required":true},{"info":"Ordered quantity.","name":"qty","type":"decimal","required":true},{"info":"Quantity cancelled from this line.","name":"qtyCancelled","type":"decimal"},{"info":"Quantity received against this line via Goods Receipts.","name":"qtyReceived","type":"decimal"},{"info":"Unit cost per item. Defaults from vendor unit cost at the applicable cost level.","name":"unitCost","type":"decimal","required":true}]},{"name":"PurchaseOrderStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status of the purchase order.","name":"documentStatus","type":"enumeration","values":["Draft","Open","PartiallyReceived","Complete","Cancelled"],"required":true},{"info":"Operational status indicating whether the purchase order is actively being processed.","name":"operationalStatus","type":"enumeration","values":["Open","Closed"],"required":true}]},{"name":"PurchaseOrderDiscount","extends":"OperationalSubDocument","properties":[{"info":"Discount amount.","name":"amount","type":"decimal","required":true},{"info":"Description of this discount.","name":"description","type":"string"},{"info":"Whether the discount is a percentage or fixed amount.","name":"discountType","type":"enumeration","values":["Percentage","Fixed"],"required":true},{"info":"Discount percentage. Applicable when discountType is 'Percentage'.","name":"percentage","type":"decimal"}]}]},{"name":"Purchase Order Acknowledgement","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Vendor's confirmation of a Purchase Order — indicates acceptance, changes, backorders, or cancellation at header and line level. Key EDI document (855).","status":"stub","properties":[{"n":"ackDate","r":true,"t":"datetime"},{"n":"controlNumber","t":"string","info":"EDI control number for cross-referencing."},{"n":"lines","r":true,"t":"array","info":"Array of PurchaseOrderAcknowledgementLine sub-documents. Each line confirms the vendor's acceptance of a PO line."},{"n":"purchaseOrder","r":true,"t":"entityRef","re":"Purchase Order"},{"n":"status","r":true,"t":"schema","info":"Acknowledgement status from the vendor. Tracks current state and who/when it was last changed."}],"related":["Purchase Order","Vendor"],"inlineSchemas":[{"name":"POAcknowledgementStatus","schema":"schemas/purchase-order-acknowledgement/POAcknowledgementStatus.ts","properties":[{"info":"Vendor's acknowledgement response to the purchase order.","name":"status","type":"enumeration","values":["Accepted","Accepted with Changes","Backordered","Cancelled"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Purchasing Fee","class":"Dictionary","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"A fee type applied to purchase orders (e.g. freight, handling, duties). May apply globally or at the item level.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"isGlobalFee","r":true,"t":"boolean","info":"When true the fee applies to the entire PO rather than individual lines."},{"n":"isItemFee","r":true,"t":"boolean","info":"When true the fee applies at the line-item level."},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Purchase Order"]},{"name":"RFM Group","class":"Dictionary","subsystem":"CONNECT","area":"Customers","desc":"Customer segmentation classification derived from RFM (Recency, Frequency, Monetary) analysis. Groups customers by purchase behavior — typical segments include Champions, Loyal Customers, Potential Loyalists, At Risk, Hibernating, and Lost. Used to drive targeted marketing, retention campaigns, and service tiering.","status":"draft","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key for the RFM segment (e.g. CHAMPIONS, AT_RISK, HIBERNATING). Unique within the Company."},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this RFM Group belongs to. Required for tenant isolation."},{"n":"description","t":"string","info":"Description of the segment definition and criteria — e.g. 'Customers who purchased within the last 30 days with high frequency and spend'."},{"n":"frequencyScore","t":"integer","info":"Frequency score (typically 1–5) representing how often customers in this segment purchase."},{"n":"monetaryScore","t":"integer","info":"Monetary score (typically 1–5) representing the spend tier of customers in this segment."},{"n":"name","r":true,"t":"string","u":true,"info":"Display name of the segment (e.g. 'Champions', 'At Risk')."},{"n":"recencyScore","t":"integer","info":"Recency score (typically 1–5) representing how recently customers in this segment last purchased."}],"ext":"LookupEntity","related":["Customer","Company"]},{"name":"Report","class":"Core","subsystem":"CONNECT","area":"Analytics","desc":"A configured analytics view — either internal or via Looker — categorized by domain.","status":"draft","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"name","r":true,"t":"string","u":true}],"ext":"BaseDocument","shopify":"Reports API","bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Role","class":"Dictionary","subsystem":"ACCESS","area":"Security & Permissions","desc":"A named set of Permissions assigned to Users. Roles provide coarse-grained access control scoped to a Client, Application, or Environment.","status":"draft","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"name","r":true,"t":"string","u":true},{"n":"permissions","r":true,"t":"array","re":"Permission"},{"n":"roleId","r":true,"t":"string"}],"service":"APR Access","shopify":"Staff roles and collaborator permissions","notes":"Role scope targets are: Client, Application, Environment.","related":["Permission","User"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Name","severity":"error"}],"lifecycle":null,"calculations":[{"name":"permissionCount","formula":"COUNT(permissions)","trigger":"query-time"},{"name":"userCount","formula":"COUNT(User WHERE roles CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Must have at least one Permission assigned","entity":"Permission"}]}},{"name":"Sale","class":"Transactional","subsystem":"CONNECT","area":"Sales & Orders","desc":"The completed revenue transaction. Records final quantities, prices, taxes, and payment. Triggers inventory decrement. Can exist independently (e.g. POS cash-and-carry) or originate from an Order. A single Order may produce multiple Sales when fulfilled in separate shipments or pickups.","status":"draft","properties":[{"n":"associate","t":"entityDetail","re":"Employee","info":"Sales associate who initiated this sale."},{"n":"billCustomer","t":"entityRef","re":"Customer","info":"Billing customer."},{"n":"cashier","t":"entityRef","re":"Employee","info":"The employee who processed this sale. References an Employee whose Functions includes 'Cashier'."},{"n":"channel","r":true,"t":"entityDetail","re":"Sales Channel"},{"n":"charges","r":true,"t":"array","info":"Customer charges (store credit, gift card, house charge)."},{"n":"coupons","r":true,"t":"array","info":"Coupons applied to this sale."},{"n":"customer","t":"entityRef","re":"Customer","info":"The customer making the purchase."},{"n":"destTaxArea","t":"string","info":"Destination tax area for tax calculation."},{"n":"deviceNo","t":"string","info":"POS device number where the sale was processed."},{"n":"discounts","r":true,"t":"array","info":"Sale-level discounts applied."},{"n":"drawerMemoNo","t":"string","info":"Cash drawer memo number for reconciliation."},{"n":"fees","r":true,"t":"array","info":"Sale-level fees (e.g. restocking, shipping)."},{"n":"fillFromLocation","t":"entityDetail","re":"Location","info":"Location fulfilling the order, if different from sale location."},{"n":"fiscalDate","r":true,"t":"string","info":"Fiscal date for accounting period assignment."},{"n":"lines","r":true,"t":"array","info":"Array of SaleLine sub-documents. Each line records a product sold in the transaction."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"payments","r":true,"t":"array"},{"n":"salesOrder","t":"entityRef","re":"Sales Order","info":"Optional — null for standalone POS sales; references the originating Sales Order when sale is part of order fulfillment"},{"n":"salesOrderNo","t":"string","info":"Reference to originating sales order number."},{"n":"salesPersons","r":true,"t":"array","re":"Employee","info":"One or more sales associates credited on this transaction. References Employees whose Functions includes 'SalesPerson'."},{"n":"salesReceiptNo","r":true,"t":"string"},{"n":"saleType","r":true,"t":"enumeration","v":["DEPOSIT","MIXED","RETURN","SALE"],"info":"Transaction type classification."},{"n":"sourceTaxArea","t":"string","info":"Source tax area for tax calculation."},{"n":"status","r":true,"t":"schema","info":"SaleStatus inline schema capturing current document status."},{"n":"taxes","r":true,"t":"array"},{"c":true,"n":"totalAmount","r":true,"t":"decimal"}],"ext":"TransactionalDocument","shopify":"Order (POS source)","related":["Sales Order","Location","Sales Channel","Employee","Stock Ledger"],"bv":{"rules":[{"rule":"Must equal sum of line totals + taxes - discounts","when":"always","field":"TotalAmount","severity":"error"},{"rule":"Sum of payment amounts must equal TotalAmount (balanced tender)","when":"post","field":"Payments","severity":"error"},{"rule":"Optional — Sale can exist without a Sales Order (standalone POS transaction)","when":"always","field":"SalesOrder","severity":"info"},{"rule":"All product classes (Style, Single, Service, Digital, Wallet) can be added","when":"line-add","field":"lines","severity":"info"}],"lifecycle":{"states":["Held","Posted"],"transitions":[{"to":"Posted","from":"Held","conditions":["Payment tendered and balanced","Stock Ledger entries written"]}],"initialState":"Held"},"calculations":[{"name":"TotalAmount","formula":"Sum(LineTotals) + Sum(Taxes) - Sum(Discounts)","trigger":"On line or payment change"},{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"paymentCount","formula":"COUNT(payments)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"One Sales Order may produce multiple Sales (e.g. partial shipments). Each Sale references the originating Sales Order when applicable.","entity":"Sales Order"},{"rule":"Posting writes Stock Ledger debit entries per item/location","entity":"Stock Ledger"},{"rule":"Posting decrements SOH at the sale Location","entity":"Item Stock"},{"rule":"If customer-linked, updates purchase history","entity":"Customer"}]},"inlineSchemas":[{"name":"SaleStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document status of the sale.","name":"value","type":"enumeration","values":["HELD","POSTED"],"required":true}]}]},{"name":"Sales Channel","class":"Operational","subsystem":"CONNECT","area":"Sales & Orders","desc":"Distribution channel through which products are sold. Controls inventory publication and product visibility.","status":"reviewed","properties":[{"n":"autoPublish","r":true,"t":"boolean","info":"When true, newly created products are automatically published to this channel. When false, products must be explicitly assigned. Defaults to false."},{"n":"channelType","r":true,"t":"enumeration","v":["Online","PointOfSale","Marketplace","Social"],"info":"Classification of the sales channel. Determines channel-specific behaviour such as checkout flow and fulfilment routing."},{"n":"configuration","r":true,"t":"valueType","info":"Reference to this Sales Channel's configuration record in the CONFIG subsystem. Uses the ConfigurationRef value type (config: entityDetail → Config, templateCode: string). Holds channel-specific behavior — catalog scope, pricing strategy, fulfillment routing — consumed at order-capture time."},{"n":"connector","t":"string","info":"Name of the external connector that powers this channel (e.g. 'shopify', 'teamwork'). Null for native/internal channels."},{"n":"items","r":true,"t":"array","re":"Item","info":"Array of Item IDs published to this sales channel. Derived from Items whose Product is published to this channel and whose salesChannels indicate isPublished = true."},{"n":"locations","r":true,"t":"array","re":"Location","info":"Array of Location IDs available in this sales channel. Determines which locations can fulfil orders and hold inventory for this channel."},{"n":"name","r":true,"t":"string"},{"n":"products","r":true,"t":"array","re":"Product","info":"Array of Product IDs published to this sales channel. A Product is published when its salesChannels array contains an entry for this channel with isPublished = true."},{"n":"salesChannelNo","r":true,"t":"integer"},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the sales channel. Tracks current state and who/when it was last changed."}],"ext":"OperationalDocument","shopify":"Channel and Publication resources","related":["Item","Location","Product","Sales Order"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"salesChannelNo","severity":"error"}],"lifecycle":{"states":["Draft","Active","Archived"],"disallowed":[{"to":"Draft","from":"Active","reason":"Sales Channels cannot revert to Draft once activated"},{"to":"Draft","from":"Archived","reason":"Sales Channels cannot revert to Draft once activated"}],"transitions":[{"to":"Active","from":"Draft","conditions":["At least one Location is assigned","Name is set"]},{"to":"Archived","from":"Active","conditions":["No open Sales Orders referencing this channel","No Products are published to this channel"]},{"to":"Active","from":"Archived","conditions":[]}],"initialState":"Draft","terminalExits":["Draft"]},"calculations":[{"name":"productCount","formula":"COUNT(Product WHERE salesChannels CONTAINS this)","trigger":"query-time"},{"name":"itemCount","formula":"COUNT(Item via Product WHERE salesChannels CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot delete or archive a Sales Channel while any Products are published to it","when":"delete, archive","entity":"Product"},{"rule":"Cannot delete or archive a Sales Channel while any Items are published to it","when":"delete, archive","entity":"Item"}]},"inlineSchemas":[{"name":"SalesChannelStatus","schema":"schemas/sales-channel/SalesChannelStatus.ts","properties":[{"info":"Current lifecycle state of the sales channel.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Sales Order","class":"Order","subsystem":"CONNECT","area":"Sales & Orders","desc":"Sales intent document capturing items, pricing, promotions, and fulfillment instructions before completion. A single Sales Order may result in multiple Sales when fulfilled in separate shipments or pickups.","status":"draft","properties":[{"n":"associate","t":"string","info":"Sales associate assigned to this order."},{"n":"billCustomer","t":"entityRef","re":"Customer","info":"Billing customer, if different from the ordering customer."},{"n":"canOnlyShipOnce","r":true,"t":"boolean","info":"If true, all items must ship in a single fulfillment."},{"n":"canShipPartial","r":true,"t":"boolean","info":"Whether partial shipments are allowed."},{"n":"createLocation","t":"string","info":"Location where the order was created."},{"n":"customer","t":"entityRef","re":"Customer"},{"n":"customerServiceNotes","r":true,"t":"array","info":"Array of customer service notes."},{"n":"defaultShipMethod","t":"entityDetail","re":"Shipping Method","info":"Default shipping method for the order."},{"n":"deliveryInfo","t":"schema","info":"Delivery scheduling information including date, time window, and destination."},{"n":"discounts","r":true,"t":"array","info":"Order-level discounts applied."},{"n":"estimatedArrivalDate","t":"datetime","info":"Estimated delivery date to the customer."},{"n":"estimatedShipDate","t":"datetime","info":"Estimated ship date from the fulfillment location."},{"n":"fees","r":true,"t":"array","info":"Order-level fees (shipping, handling, etc.)."},{"n":"fillLocation","r":true,"t":"string","info":"Primary fulfillment location for this order."},{"n":"fulfillmentMethod","r":true,"t":"enumeration","v":["ShipToCustomer","StorePickup","ShipToStore","SameDay","Mixed"],"info":"How the order will be fulfilled."},{"n":"isArchived","r":true,"t":"boolean","info":"Soft archive flag."},{"n":"isFillLocationLocked","r":true,"t":"boolean","info":"If true, the fill location cannot be changed."},{"n":"isGuestCheckout","r":true,"t":"boolean","info":"Whether this is a guest checkout without customer account."},{"n":"isTaxExempt","r":true,"t":"boolean","info":"Whether the order is tax exempt."},{"n":"lines","r":true,"t":"array","info":"Array of SalesOrderLine sub-documents. Each line represents a product ordered by the customer."},{"n":"orderDate","r":true,"t":"datetime","info":"Date the order was placed."},{"n":"payments","r":true,"t":"array","info":"Payment methods and amounts applied to this order."},{"n":"promotions","r":true,"t":"array","re":"Promotion"},{"n":"salesChannel","t":"string","info":"Sales channel code where the order originated."},{"n":"salesOrderNo","r":true,"t":"string"},{"n":"salesReceiptId","t":"string","info":"Reference to the associated Sales Receipt (Sale)."},{"n":"shipCustomer","t":"entityRef","re":"Customer","info":"Ship-to customer, if different from the ordering customer."},{"n":"shipments","r":true,"t":"array","info":"Array of shipment references with tracking information."},{"n":"status","r":true,"t":"schema","info":"SalesOrderStatus inline schema capturing current document status."},{"n":"type","r":true,"t":"enumeration","v":["Customer Order","Online Order","Pre-Order","Special Order","Store Order"],"info":"Classification of the sales order by origin or purpose."}],"ext":"OperationalDocument","shopify":"Order / DraftOrder resource","related":["Customer","Sale","Fulfillment Order","Ship Order","Sales Channel"],"bv":{"rules":[{"rule":"Must have at least one order line","when":"create","field":"Lines","severity":"error"},{"rule":"Must reference a valid active Customer","when":"create","field":"Customer","severity":"error"},{"rule":"All product classes (Style, Single, Service, Digital, Wallet) can be added","when":"line-add","field":"lines","severity":"info"}],"lifecycle":{"states":["Accepted","Processing","Reviewing","OnHold","DeliveryPending","PickUpReady","Completed","Cancelled","Mixed"],"transitions":[{"to":"Processing","from":"Accepted","conditions":["Payment authorized or COD"]},{"to":"DeliveryPending","from":"Processing","conditions":["All items shipped"]},{"to":"PickUpReady","from":"Processing","conditions":["All items picked and staged"]},{"to":"Mixed","from":"Processing","conditions":["Lines are in multiple states"]},{"to":"Reviewing","from":"Processing","conditions":["Fraud or review flag triggered"]},{"to":"Processing","from":"Reviewing","conditions":["Review cleared"]},{"to":"Cancelled","from":"Reviewing","conditions":["Review rejected"]},{"to":"OnHold","from":"Processing","conditions":["Manual or system hold"]},{"to":"Processing","from":"OnHold","conditions":["Hold released"]},{"to":"Completed","from":"DeliveryPending","conditions":["Delivery confirmed"]},{"to":"Completed","from":"PickUpReady","conditions":["Customer picked up"]},{"to":"Cancelled","from":"Accepted","conditions":["Customer request before processing"]}],"initialState":"Accepted"},"calculations":[{"name":"QuantityOrdered","formula":"Sum of line quantities","trigger":"On line change"},{"name":"QuantityFilled","formula":"Sum of line filled quantities","trigger":"On fulfillment update"},{"name":"QuantityDue","formula":"QuantityOrdered - QuantityFilled - QuantityCancelled","trigger":"On fulfillment or cancellation"},{"name":"QuantityCancelled","formula":"Sum of line cancelled quantities","trigger":"On cancellation"},{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"fulfillmentOrderCount","formula":"COUNT(Fulfillment Order WHERE salesOrder = this)","trigger":"query-time"},{"name":"saleCount","formula":"COUNT(Sale WHERE salesOrder = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"One Order may produce multiple Sales (e.g. partial shipments). Each Sale references the originating Order.","entity":"Sale"},{"rule":"Generates Fulfillment Orders for shipment/pickup","entity":"Fulfillment Order"},{"rule":"Shipment creation updates Order line status","entity":"Shipment"}]},"inlineSchemas":[{"name":"SalesOrderStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document status of the sales order.","name":"value","type":"enumeration","values":["Accepted","Cancelled","Completed","DeliveryPending","Mixed","OnHold","PickUpReady","Processing","Reviewing"],"required":true}]}]},{"name":"Scope","class":"Dictionary","subsystem":"ACCESS","area":"Security & Permissions","desc":"An OAuth2 scope string that maps to one or more Areas or Permissions. Presented during authorization to define the access surface of a token.","status":"draft","properties":[{"n":"areas","r":true,"t":"array","re":"Area"},{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true},{"n":"permissions","r":true,"t":"array","re":"Permission"},{"n":"scopeId","r":true,"t":"string"}],"service":"APR Access","related":["Area","Permission","Client"],"bv":{"rules":[{"rule":"Must be unique within the permission context","when":"create","field":"Key","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Narrows the applicability of a Permission to a resource subset","entity":"Permission"}]}},{"name":"Season","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Time-bound merchandising period defining when products are available or relevant (e.g. Spring 2026, Holiday).","status":"draft","properties":[{"n":"code","r":true,"t":"string","u":true,"info":"Human-readable key. Unique within scope."},{"n":"endDate","t":"date"},{"n":"months","r":true,"t":"array","v":["January","February","March","April","May","June","July","August","September","October","November","December"],"info":"Calendar months included in this season."},{"n":"name","r":true,"t":"string","u":true},{"n":"seasonId","r":true,"t":"string"},{"n":"startDate","t":"date"}],"ext":"LookupEntity","related":["Product"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[{"name":"productCount","formula":"COUNT(Product WHERE seasons CONTAINS this)","trigger":"query-time"}],"crossEntityConstraints":[]}},{"name":"Secret","class":"Core","subsystem":"CONFIG","area":"Configuration","desc":"An encrypted sensitive value (API key, connection string, certificate). Referenced by Configs; never stored in plain text.","status":"draft","properties":[{"n":"actor","r":true,"t":"entityRef","re":"Actor"},{"n":"encryptedValue","r":true,"t":"encrypted","info":"AES-256 encrypted secret value. Decrypted only at point of use."},{"n":"environment","r":true,"t":"entityDetail","re":"Environment"},{"n":"expiresAt","t":"datetime"},{"n":"name","r":true,"t":"string"},{"n":"rotationPolicy","t":"schema"},{"n":"secretId","r":true,"t":"string"}],"service":"APR Config","shopify":"API keys and access tokens","related":["Actor","Environment","Config"],"bv":{"rules":[{"rule":"Must be stored encrypted at rest (AES-256 or equivalent)","when":"always","field":"Value","severity":"error"},{"rule":"Must never appear in logs, API responses, or error messages","when":"always","field":"Value","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Scoped to a specific Environment","entity":"Environment"}]}},{"name":"Ship Order","class":"Order","subsystem":"CONNECT","area":"Sales & Orders","desc":"Fulfillment instruction derived from an Order; directs picking, packing, and shipping from a specific location.","status":"stub","properties":[{"n":"fulfillmentOrder","t":"entityRef","re":"Fulfillment Order"},{"n":"lines","r":true,"t":"array","info":"Array of ShipOrderLine sub-documents. Each line specifies a quantity to ship for an item."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"rejectReason","t":"entityDetail","re":"Ship Reject Reason"},{"n":"salesOrder","r":true,"t":"entityRef","re":"Sales Order"},{"n":"shipOrderId","r":true,"t":"string"}],"ext":"OperationalDocument","shopify":"FulfillmentOrder → Fulfillment workflow","related":["Sales Order","Fulfillment Order","Shipment","Location"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid Fulfillment Order","entity":"Fulfillment Order"}]}},{"name":"Ship Reject Reason","class":"Dictionary","subsystem":"CONNECT","area":"Sales & Orders","desc":"Codified reason for rejecting or canceling a ship order (out of stock, address issue, customer request).","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Ship Order"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Shipment","class":"Operational","subsystem":"CONNECT","area":"Sales & Orders","desc":"Physical dispatch of goods against a Ship Order, broken into Cartons with carrier tracking.","status":"draft","properties":[{"n":"canShipPartial","r":true,"t":"boolean","info":"Whether this shipment allows partial delivery."},{"n":"carrier","t":"string"},{"n":"cartons","r":true,"t":"array","re":"Shipment Carton"},{"n":"deliveredDate","t":"datetime"},{"n":"deliveryInfo","t":"schema","info":"Delivery scheduling and routing information."},{"n":"fillLocation","r":true,"t":"entityDetail","re":"Location","info":"Location fulfilling this shipment."},{"n":"fulfillmentMethod","r":true,"t":"enumeration","v":["ShipToCustomer","StorePickup","ShipToStore","SameDay"],"info":"How this shipment will be delivered."},{"n":"isArchived","r":true,"t":"boolean","info":"Soft archive flag."},{"n":"isDropShip","r":true,"t":"boolean","info":"Whether this is a drop-ship directly from vendor."},{"n":"lines","r":true,"t":"array","info":"Shipment line items with quantities and status."},{"n":"saleId","t":"string","info":"Reference to the associated Sale."},{"n":"salesOrderId","r":true,"t":"string","info":"Reference to the originating Sales Order."},{"n":"shipmentId","r":true,"t":"string"},{"n":"shipMethod","t":"entityDetail","re":"Shipping Method","info":"Shipping method used."},{"n":"shipOrder","r":true,"t":"entityRef","re":"Ship Order"},{"n":"shipToAddress","r":true,"t":"schema","info":"Destination address for the shipment."},{"n":"shipToCustomerId","r":true,"t":"string","info":"Customer receiving the shipment."},{"n":"shippedDate","t":"datetime"},{"n":"status","r":true,"t":"schema","info":"ShipmentStatus inline schema with documentStatus and operationalStatus."},{"n":"trackingNo","t":"string"}],"ext":"OperationalDocument","shopify":"Fulfillment resource with tracking","related":["Ship Order","Shipment Carton"],"bv":{"rules":[],"lifecycle":{"states":["Open","Rejected","Completed"],"transitions":[{"to":"Completed","from":"Open","conditions":["Delivery confirmed or picked up"]},{"to":"Rejected","from":"Open","conditions":["Shipment refused by customer"]}],"initialState":"Open"},"calculations":[],"operationalStates":["PrepareShipment","ReadyToShip","Shipped","ReadyForPickup","PickedUp","ReadyForDropShip","DropShipComplete","PartiallyRejected","PreparePickup","Processing"],"crossEntityConstraints":[{"rule":"Completion updates parent Sales Order line status","entity":"Sales Order"},{"rule":"Must reference a valid Fulfillment Order","entity":"Fulfillment Order"}]},"inlineSchemas":[{"name":"ShipLineStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Status of this shipment line.","name":"documentStatus","type":"enumeration","values":["Open","Completed","Cancelled"],"required":true}]},{"name":"ShipmentStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status of the shipment.","name":"documentStatus","type":"enumeration","values":["Open","Rejected","Completed"],"required":true},{"info":"Operational sub-status for workflow tracking.","name":"operationalStatus","type":"enumeration","values":["PrepareShipment","ReadyToShip","Shipped","ReadyForPickup","PickedUp","ReadyForDropShip","DropShipComplete","PartiallyRejected","PreparePickup","Processing"]}]}]},{"name":"Shipment Carton","class":"Operational","subsystem":"CONNECT","area":"Sales & Orders","desc":"Individual carton or package within a multi-package shipment, tracking contents at box level.","status":"stub","properties":[{"n":"cartonId","r":true,"t":"string"},{"n":"cartonNo","t":"string"},{"n":"lines","r":true,"t":"array","info":"Array of ShipmentLine sub-documents. Each line records items packed into this carton."},{"n":"shipment","r":true,"t":"entityRef","re":"Shipment"},{"n":"trackingNo","t":"string"},{"n":"weight","t":"decimal"}],"ext":"OperationalSubDocument","related":["Shipment"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Shipping Method","class":"Dictionary","subsystem":"CONNECT","area":"Sales & Orders","desc":"Carrier service or delivery method available for fulfilment (e.g. Standard Ground, Express, Click & Collect).","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"daysInTransit","t":"integer","info":"Estimated transit time in business days."},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Ship Order","Sales Order"]},{"name":"Stock Adjustment","class":"Transactional","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Records an inventory correction with a reason code (shrinkage, receiving error, etc.).","status":"stub","properties":[{"n":"adjustmentAction","r":true,"t":"enumeration","v":["Adjust","Restate"],"info":"Adjust (delta change) or Restate (absolute override)."},{"n":"adjustmentNo","r":true,"t":"string","info":"Human-readable adjustment number / identifier."},{"n":"effectiveDate","t":"datetime","info":"Date the adjustment takes effect for reporting purposes. When different from inherited transactionDate, used for fiscal period alignment."},{"n":"fiscalDate","t":"datetime","info":"Fiscal period date for financial reporting."},{"n":"lines","r":true,"t":"array","info":"Array of StockAdjustmentLine sub-documents."},{"n":"location","r":true,"t":"entityDetail","re":"Location","info":"The location (store/warehouse) where inventory is being adjusted."},{"n":"reason","t":"entityDetail","re":"Stock Adjustment Reason","info":"Reason code for the adjustment (shrinkage, damage, correction, etc.)."},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the stock adjustment. Tracks current state and who/when it was last changed."},{"n":"stockBin","t":"entityRef","re":"StockBin","info":"The specific bin within the location where inventory is being adjusted."},{"n":"stockCountId","t":"string","info":"Reference to the originating Stock Take if this adjustment was generated from a count."},{"n":"totalCost","t":"decimal","info":"Calculated: sum of all line extended costs."},{"n":"totalLines","t":"decimal","info":"Calculated: count of lines on the adjustment."},{"n":"totalQty","t":"decimal","info":"Calculated: sum of all line quantities."}],"ext":"TransactionalDocument","shopify":"InventoryAdjustment operations","related":["Location","StockBin","Stock Adjustment Reason","Stock Ledger","Item Stock","Stock Take"],"bv":{"rules":[{"rule":"Must reference a valid Reason Code","when":"always","field":"reason","severity":"error"},{"rule":"Must be Adjust or Restate","when":"always","field":"adjustmentAction","severity":"error"},{"rule":"Only physical products (Style or Single class) can be added to a Stock Adjustment","when":"line-add","field":"lines","severity":"error"}],"lifecycle":{"states":["Draft","Processing","Posted"],"transitions":[{"to":"Processing","from":"Draft","conditions":["At least one line exists","Reason code is set"]},{"to":"Posted","from":"Processing","conditions":["Stock Ledger entries written","Item Stock updated"]}],"initialState":"Draft"},"calculations":[{"name":"totalCost","formula":"Sum of line extCost values","trigger":"On line add/edit/remove"},{"name":"totalLines","formula":"Count of lines","trigger":"On line add/remove"},{"name":"totalQty","formula":"Sum of line qty values","trigger":"On line add/edit/remove"}],"crossEntityConstraints":[{"rule":"Posting writes one Stock Ledger entry per line","entity":"Stock Ledger"},{"rule":"Posting updates Item Stock SOH","entity":"Item Stock"}]},"inlineSchemas":[{"name":"StockAdjustmentStatus","schema":"schemas/stock-adjustment/StockAdjustmentStatus.ts","properties":[{"info":"Current lifecycle state of the adjustment.","name":"status","type":"enumeration","values":["Draft","Processing","Posted"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Stock Adjustment Reason","class":"Dictionary","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Codified reason for inventory adjustments (e.g. damage, theft, correction). Required for audit trails.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"isShrinkage","r":true,"t":"boolean"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Stock Adjustment"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Stock Ledger","class":"Ledger","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Immutable audit trail of all inventory quantity and cost changes. Each entry records a quantity movement and cost impact for an Item at a Location, with a running balance. Written by: Sale, Stock Transfer, Stock Adjustment, and Goods Receipt (Purchase) transactions.","status":"stub","properties":[{"n":"costingMethod","r":true,"t":"enumeration","v":["FIFO","WeightedAverage","LIFO"],"info":"Inventory costing method used to value this movement and calculate COGS"},{"c":true,"n":"extendedCost","t":"decimal","info":"Qty × UnitCost — total cost impact of this movement"},{"n":"item","r":true,"t":"entityRef","re":"Item"},{"c":true,"n":"ledgerLine","r":true,"t":"integer"},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"movementType","r":true,"t":"enumeration","v":["Sale","Receipt","Adjustment","Transfer","Return"],"info":"Categorizes the type of inventory movement. The inherited sourceEntityType identifies the specific entity class (e.g. 'Sale', 'Stock Transfer'); movementType provides a higher-level category for reporting."},{"n":"qty","r":true,"t":"integer","info":"Signed quantity change (positive = stock in, negative = stock out)"},{"n":"unitCost","t":"decimal","info":"Unit cost at the time of the movement, used for COGS and inventory valuation"}],"ext":"LedgerEntry","related":["Item","Location","Item Stock","Sale","Stock Transfer","Stock Adjustment","Goods Receipt"],"bv":{"rules":[{"rule":"Append-only — entries must never be modified or deleted (immutable audit trail)","when":"always","field":"LedgerLine","severity":"error"},{"rule":"Must be non-zero","when":"create","field":"Qty","severity":"error"}],"lifecycle":null,"calculations":[{"name":"ExtendedCost","formula":"Qty × UnitCost","trigger":"On ledger entry creation"}],"crossEntityConstraints":[{"rule":"Running quantity sum must match corresponding Item Stock on-hand balance","entity":"Item Stock"},{"rule":"Sale posting creates a negative-qty ledger entry per line item","entity":"Sale"},{"rule":"Goods Receipt posting creates a positive-qty ledger entry per received item","entity":"Goods Receipt"},{"rule":"Transfer creates paired entries: negative at source, positive at destination","entity":"Stock Transfer"},{"rule":"Adjustment creates a signed entry per adjusted item with reason code","entity":"Stock Adjustment"}]}},{"name":"Stock Limit Group","class":"Dictionary","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Defines minimum/maximum stock thresholds and reorder parameters for a set of items or locations.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Item Stock"]},{"name":"Stock Take","class":"Operational","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"A physical count cycle counting event against one or more locations.","status":"stub","properties":[{"n":"countedQty","t":"integer"},{"n":"lines","r":true,"t":"array","info":"Array of StockTakeLine sub-documents. Each line records the expected vs. counted quantity for one Item at the count location."},{"n":"location","r":true,"t":"entityDetail","re":"Location"},{"n":"stockTakeId","r":true,"t":"string"}],"ext":"OperationalDocument","related":["Item","Location","Stock Adjustment"],"bv":{"rules":[],"lifecycle":{"states":["Draft","InProgress","Completed","Posted"],"transitions":[{"to":"InProgress","from":"Draft","conditions":["At least one count line exists"]},{"to":"Completed","from":"InProgress","conditions":["All lines have been counted"]},{"to":"Posted","from":"Completed","conditions":["Variance review approved"]}],"initialState":"Draft"},"calculations":[{"name":"Variance","formula":"CountedQty - ExpectedQty per line","trigger":"On count entry"},{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"varianceLineCount","formula":"COUNT(lines WHERE countedQty != expectedQty)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Posting a Stock Take generates Stock Adjustments for variances","entity":"Stock Adjustment"},{"rule":"Must reference a valid active Location","entity":"Location"}]}},{"name":"Stock Transfer","class":"Transactional","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Records the actual movement of stock between locations (fulfills a Transfer Order).","status":"draft","properties":[{"n":"appliedDiscrepancyRule","t":"enumeration","v":["UseInQty","UseOutQty"],"info":"Corrective action applied when in/out quantities don't match."},{"n":"cartons","r":true,"t":"array","re":"Stock Transfer Carton"},{"n":"destinationLocation","r":true,"t":"entityDetail","re":"Location","info":"The destination location receiving the transferred stock."},{"n":"fiscalDate","t":"datetime","info":"Fiscal date for accounting period assignment."},{"n":"hasDiscrepancy","r":true,"t":"boolean","info":"Whether there is a quantity discrepancy between out and in."},{"n":"isReviewed","r":true,"t":"boolean","info":"Whether discrepancies have been reviewed."},{"n":"lines","r":true,"t":"array","info":"Array of StockTransferLine sub-documents. Each line records an Item, quantity, and cost for the transfer movement."},{"n":"originLocation","r":true,"t":"entityDetail","re":"Location","info":"The origin location sending the transferred stock."},{"n":"postedInDate","t":"datetime","info":"Date the receiving side was posted."},{"n":"postedOutDate","t":"datetime","info":"Date the sending side was posted."},{"n":"purchaseOrderId","t":"string","info":"Associated purchase order, if transfer is PO-driven."},{"n":"reason","t":"entityDetail","re":"Stock Transfer Reason","info":"Reason for the transfer."},{"n":"receivedDate","t":"datetime"},{"n":"reversedStockTransferId","t":"string","info":"ID of the stock transfer this reverses."},{"n":"reversingStockTransferId","t":"string","info":"ID of the stock transfer that reverses this one."},{"n":"shippedDate","t":"datetime"},{"n":"status","r":true,"t":"schema","info":"StockTransferStatus inline schema with documentStatus and operationalStatus."},{"n":"stockTransferNo","r":true,"t":"string"},{"n":"transferDate","r":true,"t":"datetime","info":"Date the transfer was initiated."},{"n":"transferOrder","r":true,"t":"entityRef","re":"Transfer Order"}],"ext":"TransactionalDocument","shopify":"Transfer resource","related":["Transfer Order","Location","Stock Transfer Carton","Stock Ledger"],"bv":{"notes":"Supports reversal via Reversed/Reversal operational status","rules":[{"rule":"Only physical products (Style or Single class) can be added to a Stock Transfer","when":"line-add","field":"lines","severity":"error"}],"lifecycle":{"states":["Draft","InTransit","Processing","Posted","Cancelled"],"transitions":[{"to":"InTransit","from":"Draft","conditions":["Items picked and dispatched from source"]},{"to":"Processing","from":"InTransit","conditions":["Received at destination"]},{"to":"Posted","from":"Processing","conditions":["Stock Ledger entries written for both locations"]},{"to":"Cancelled","from":"Draft","conditions":[]},{"to":"Cancelled","from":"InTransit","conditions":["Items returned to source location"]}],"initialState":"Draft"},"calculations":[{"name":"lineCount","formula":"COUNT(lines)","trigger":"query-time"},{"name":"cartonCount","formula":"COUNT(cartons)","trigger":"query-time"},{"name":"qtyDifference","formula":"SUM(lines.qtyOut) - SUM(lines.qtyIn)","trigger":"On line quantity change"},{"name":"qtyIn","formula":"SUM(lines.qtyIn)","trigger":"On line quantity change"},{"name":"qtyInTransit","formula":"SUM(lines.qtyOut) - SUM(lines.qtyIn)","trigger":"On line quantity change"},{"name":"qtyOut","formula":"SUM(lines.qtyOrdered)","trigger":"On line quantity change"},{"name":"taxAmount","formula":"SUM(lines.taxAmount)","trigger":"On line tax change"},{"name":"totalAmount","formula":"SUM(lines.totalAmount)","trigger":"On line total change"},{"name":"totalCartons","formula":"COUNT(cartons)","trigger":"query-time"},{"name":"totalCost","formula":"SUM(lines.extCost)","trigger":"On line cost change"},{"name":"totalLines","formula":"COUNT(lines)","trigger":"query-time"},{"name":"totalQty","formula":"SUM(lines.qty)","trigger":"On line quantity change"}],"crossEntityConstraints":[{"rule":"Must reference a valid Transfer Order","entity":"Transfer Order"},{"rule":"Posting writes debit entry at source and credit entry at destination","entity":"Stock Ledger"},{"rule":"Posting decrements source and increments destination SOH","entity":"Item Stock"}]},"inlineSchemas":[{"name":"ShipLineStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Status of this transfer line.","name":"documentStatus","type":"enumeration","values":["Open","Completed","Cancelled"],"required":true}]},{"name":"StockTransferStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status.","name":"documentStatus","type":"enumeration","values":["Draft","InTransit","Processing","Posted","Cancelled"],"required":true},{"info":"Operational sub-status for reversal tracking.","name":"operationalStatus","type":"enumeration","values":["Reversed","Complete","Reversal"]}]}]},{"name":"Stock Transfer Carton","class":"Operational","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Physical shipping container associated with a stock transfer, tracking items packed per container.","status":"stub","properties":[{"n":"cartonId","r":true,"t":"string"},{"n":"cartonNo","t":"string"},{"n":"lines","r":true,"t":"array","info":"Array of StockTransferLine sub-documents within this carton."},{"n":"stockTransfer","r":true,"t":"entityRef","re":"Stock Transfer"},{"n":"weight","t":"decimal"}],"ext":"OperationalSubDocument","related":["Stock Transfer"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Stock Transfer Reason","class":"Dictionary","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Codified reason for initiating inventory transfers (rebalancing, replenishment, consolidation).","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Transfer Order"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"Stock Transfer Reject Reason","class":"Dictionary","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Codified reason for rejecting a stock transfer at the receiving location.","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"name","r":true,"t":"string","u":true}],"ext":"LookupEntity","related":["Stock Transfer"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}},{"name":"StockBin","class":"Operational","subsystem":"CONNECT","area":"Organization","desc":"A specific storage position within a Location (e.g. aisle-rack-shelf-bin). Inventory transactions reference bins for put-away, picking, counting, and replenishment. Modeled as an independent entity following SAP EWM / Dynamics 365 / NetSuite conventions.","status":"draft","properties":[{"n":"binId","r":true,"t":"string"},{"n":"binType","t":"enumeration","v":["Shelf","Pallet","Bulk Floor","Case Flow","Tote"],"info":"Physical form factor of the bin. Drives capacity rules and putaway logic. Aligned with SAP EWM storage bin types."},{"n":"code","r":true,"t":"string","info":"Human-readable coordinate label encoding the physical position (e.g. 'A-03-02'). Follows a Location-level naming convention of aisle–rack–shelf–position."},{"n":"description","t":"string"},{"n":"isMixable","r":true,"t":"boolean","info":"Whether the bin can hold multiple SKUs or lots simultaneously. When false, only one SKU/lot per bin (common for high-value or regulated items)."},{"n":"location","r":true,"t":"entityDetail","re":"Location","info":"Parent Location. A StockBin always belongs to exactly one Location."},{"n":"maxVolume","t":"decimal","info":"Maximum volumetric capacity. Enforced during putaway to prevent overfilling."},{"n":"maxWeight","t":"decimal","info":"Maximum weight capacity. Enforced during putaway to prevent overloading."},{"n":"name","t":"string","info":"Display name for the bin (e.g. 'Aisle A – Shelf 3 – Bin 2')."},{"n":"operationalStatus","t":"enumeration","v":["Available","Hold","Quarantine","Damaged","Blocked"],"info":"Operational status controlling whether inventory can be placed or picked. Distinct from Status which represents the lifecycle state."},{"n":"sequence","t":"integer","info":"Sort/pick order within a zone or location. Controls the sequence in which pickers visit bins."},{"n":"status","r":true,"t":"schema","info":"Lifecycle status of the bin. Tracks current state and who/when it was last changed."},{"n":"zone","t":"string","info":"Functional area the bin belongs to (e.g. Receiving, Forward Pick, Reserve, Staging, Quarantine). Controls putaway and picking strategy selection."}],"related":["Location","Item Stock"],"bv":{"rules":[{"rule":"Must be unique within the Location","when":"create","field":"BinId","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid active Location","entity":"Location"},{"rule":"Cannot delete a bin that holds non-zero stock","entity":"Item Stock"}]},"inlineSchemas":[{"name":"StockBinStatus","schema":"schemas/stock-bin/StockBinStatus.ts","properties":[{"info":"Current lifecycle state of the bin.","name":"status","type":"enumeration","values":["Draft","Active","Archived"],"required":true},{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"}]}]},{"name":"Tax Class","class":"Dictionary","subsystem":"CONNECT","area":"Products & Pricing","desc":"Tax classification assigned to products determining applicable tax rates and rules. Pure LookupEntity — no additional fields beyond the base.","status":"stub","properties":[],"ext":"LookupEntity","shopify":"tax_code on product variants","related":["Product","Classification"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"Code","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Cannot delete a Tax Class assigned to active Products","entity":"Product"}]}},{"name":"Transfer Order","class":"Order","subsystem":"CONNECT","area":"Inventory & Allocation","desc":"Authorization to move stock between locations before the physical movement occurs.","status":"stub","properties":[{"n":"fromLocation","r":true,"t":"entityDetail","re":"Location"},{"n":"lines","r":true,"t":"array","info":"Array of TransferOrderLine sub-documents. Each line specifies an Item and quantity to transfer between locations."},{"n":"reason","t":"entityDetail","re":"Stock Transfer Reason"},{"n":"toLocation","r":true,"t":"entityDetail","re":"Location"},{"n":"transferOrderId","r":true,"t":"string"}],"ext":"OperationalDocument","shopify":"Transfer (draft status)","related":["Location","Stock Transfer","Stock Transfer Reason"],"bv":{"rules":[{"rule":"Must differ from ToLocation","when":"always","field":"FromLocation","severity":"error"},{"rule":"Only physical products (Style or Single class) can be added to a Transfer Order","when":"line-add","field":"lines","severity":"error"}],"lifecycle":{"states":["Draft","Processing","Open","Complete","Cancelled"],"transitions":[{"to":"Processing","from":"Draft","conditions":["At least one item line exists"]},{"to":"Cancelled","from":"Draft","conditions":[]},{"to":"Open","from":"Processing","conditions":["Stock Transfer created for shipment"]},{"to":"Complete","from":"Open","conditions":["All lines received at destination"]},{"to":"Cancelled","from":"Open","conditions":["No Stock Transfers in transit"]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"Generates one or more Stock Transfers for fulfillment","entity":"Stock Transfer"},{"rule":"Both FromLocation and ToLocation must be valid active Locations","entity":"Location"}]}},{"name":"User","class":"Core","subsystem":"ACCESS","area":"Security & Permissions","desc":"A human identity within the platform — employee, admin, or external partner. Carries credentials, Roles, and Franchise Group assignments. The User's franchiseGroups property drives data sanitization — queries and API responses are filtered to return only documents tagged with the User's assigned Franchise Groups.","status":"draft","properties":[{"n":"applications","r":true,"t":"array","re":"Application","info":"Applications this User is allowed to access. Controls which platform applications (POS, eComm, Admin, etc.) the User can authenticate into. Enforced at login — the User's token is scoped to the intersection of their Roles and allowed Applications."},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this user belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export."},{"n":"email","r":true,"t":"string","u":true},{"n":"firstName","r":true,"t":"string"},{"n":"franchiseGroups","r":true,"t":"array","re":"Franchise Group","info":"Franchise Groups this User is assigned to. Drives data sanitization — the platform filters all query results and API responses to return only documents whose franchiseGroups overlap with the User's assignments. An empty array means no franchise-level filtering is applied (user sees all data within the Company tenant). This is the sub-tenant data segmentation mechanism within the Company boundary."},{"n":"lastName","r":true,"t":"string"},{"n":"roles","r":true,"t":"array","re":"Role"},{"n":"userId","r":true,"t":"string"},{"n":"userTier","r":true,"t":"schema","info":"The User's position within the franchise hierarchy. Drives UI scoping, agent tool RBAC, and default Franchise Group assignment behavior. Audited (UserTier inline schema) because tier transitions cross trust boundaries — promoting from Store to Franchise grants cross-location visibility, and from Franchise to Corporate grants cross-franchise visibility. Orthogonal to roles (permissions) and franchiseGroups (data sanitization scope). System / service identities are represented via the Actor entity, not via a tier value on User."}],"service":"APR Access","shopify":"Staff and User resources","related":["Application","Role","Company","Employee","Franchise Group"],"bv":{"rules":[{"rule":"Must be unique within the Company and valid email format","when":"always","field":"Email","severity":"error"}],"lifecycle":null,"calculations":[],"crossEntityConstraints":[{"rule":"Must have at least one Role assigned","entity":"Role"},{"rule":"Must belong to a valid Company","entity":"Company"}]},"inlineSchemas":[{"name":"UserTier","schema":"schemas/user/UserTier.ts","properties":[{"info":"Current tier classification within the franchise hierarchy. Corporate = corporate / franchisor staff. Franchise = regional or franchise-owner / multi-unit operator. Store = store-level staff working at a single location.","name":"tier","type":"enumeration","values":["Corporate","Franchise","Store"],"required":true},{"info":"User ID who last changed the tier.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last tier change.","name":"changedDate","type":"datetime"}]}]},{"name":"Vendor","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"A supplier of goods. Has terms, item-level cost structures, and payment conditions.","status":"draft","properties":[{"n":"accountNos","r":true,"t":"array","info":"Vendor account numbers, one per franchise group with primary flag."},{"n":"contacts","r":true,"t":"array","info":"Vendor contacts with position/title."},{"n":"defaultPaymentTerms","r":true,"t":"array","info":"Default payment terms per franchise group."},{"n":"emails","r":true,"t":"array","info":"Email addresses associated with this vendor."},{"n":"leadTimeDays","t":"integer","info":"Default lead time in days for orders from this vendor."},{"n":"minimumPurchaseAmount","t":"decimal","info":"Minimum purchase amount for orders to this vendor."},{"n":"name","r":true,"t":"string"},{"n":"orderCurrency","t":"entityDetail","re":"Currency","info":"Default currency for purchase orders to this vendor."},{"n":"phones","r":true,"t":"array","info":"Phone numbers associated with this vendor."},{"n":"physicalAddress","t":"valueType","vt":"Address","info":"Vendor's physical/business address."},{"n":"referenceNo","t":"string","info":"External reference number for the vendor."},{"n":"shippingAddress","t":"valueType","vt":"Address","info":"Vendor's shipping/returns address."},{"n":"status","r":true,"t":"schema","info":"VendorStatus inline schema capturing current document status."},{"n":"vendorNo","r":true,"t":"integer"},{"n":"vendorWebsiteUrl","t":"string","info":"Vendor's website URL."}],"ext":"OperationalDocument","related":["Purchase Order","Vendor Invoice","Vendor Payment Term","Item"],"bv":{"rules":[{"rule":"Must be unique within the Company","when":"create","field":"VendorNo","severity":"error"}],"lifecycle":{"states":["Draft","Active","Inactive","Archived"],"transitions":[{"to":"Active","from":"Draft","conditions":[]},{"to":"Inactive","from":"Active","conditions":["No open POs"]},{"to":"Active","from":"Inactive","conditions":[]},{"to":"Archived","from":"Inactive","conditions":["No outstanding balance"]}],"initialState":"Draft"},"calculations":[{"name":"productCount","formula":"COUNT(DISTINCT Product via VendorItemValue.item.product)","trigger":"query-time"},{"name":"itemCount","formula":"COUNT(DISTINCT Item via VendorItemValue.item)","trigger":"query-time"},{"name":"purchaseOrderCount","formula":"COUNT(Purchase Order WHERE vendor = this)","trigger":"query-time"}],"crossEntityConstraints":[{"rule":"Cannot archive Vendor with open Purchase Orders","entity":"Purchase Order"}]},"inlineSchemas":[{"name":"VendorStatus","extends":"OperationalSubDocument","properties":[{"info":"User ID who last changed the status.","name":"changedBy","type":"string"},{"info":"ISO 8601 timestamp of the last status change.","name":"changedDate","type":"datetime"},{"info":"Current document lifecycle status of the vendor.","name":"documentStatus","type":"enumeration","values":["Draft","Active","Archived"],"required":true}]},{"name":"VendorAccountNo","extends":"OperationalSubDocument","properties":[{"info":"Account number assigned by this vendor.","name":"accountNo","type":"string","required":true},{"info":"Franchise group this account number applies to.","name":"franchiseGroupId","type":"string"},{"info":"Whether this is the primary account number.","name":"isPrimary","type":"boolean","required":true}]},{"name":"VendorDefaultPaymentTerms","extends":"OperationalSubDocument","properties":[{"info":"Franchise group these payment terms apply to.","name":"franchiseGroupId","type":"string"},{"info":"Default payment terms for this franchise group.","name":"paymentTerms","type":"entityDetail","relatedEntity":"Vendor Payment Term"}]}]},{"name":"Vendor Credit","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Standalone credit memo received from a Vendor — reduces an outstanding payable. Matched against the original Vendor Invoice or Purchase Order and produces a Bill of type 'credit' when approved. Parallel to Vendor Invoice but represents money owed back to the buyer.","status":"draft","properties":[{"n":"creditNo","r":true,"t":"string","info":"Vendor-assigned credit memo number."},{"n":"lines","r":true,"t":"array","info":"Array of VendorCreditLine sub-documents. Each line records a credited Item, quantity, and cost for matching against the original invoice or PO."},{"n":"reason","t":"string","info":"Reason for the credit — e.g. return, pricing dispute, damaged goods, vendor goodwill."},{"n":"sourceInvoice","t":"entityRef","re":"Vendor Invoice","info":"Optional reference to the originating Vendor Invoice. Null for standalone credits (e.g. rebates, goodwill)."},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"}],"ext":"OperationalDocument","notes":"Vendor Credits are external input documents (like Vendor Invoices), not system-generated results. They go through their own matching and approval workflow before producing a credit-type Bill.","related":["Vendor","Vendor Invoice","Purchase Order","Bill"],"bv":{"rules":[{"rule":"If linked to a source invoice, credit total must not exceed original invoice total","when":"match","field":"CreditTotal","severity":"error"}],"lifecycle":{"states":["Draft","Matched","Approved","Posted","Disputed"],"transitions":[{"to":"Matched","from":"Draft","conditions":["Matched against source invoice, PO, or standalone approval"]},{"to":"Approved","from":"Matched","conditions":["Approval workflow complete"]},{"to":"Posted","from":"Approved","conditions":["Credit-type Bill generated"]},{"to":"Disputed","from":"Draft","conditions":["Credit amount or line items contested"]},{"to":"Draft","from":"Disputed","conditions":["Dispute resolved, credit corrected"]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"Must reference a valid active Vendor","entity":"Vendor"},{"rule":"When linked, line items should correspond to the original invoice lines","entity":"Vendor Invoice"},{"rule":"Produces a Bill with type 'credit' upon posting","entity":"Bill"}]}},{"name":"Vendor Invoice","class":"Operational","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Vendor's billing document matched against POs and Goods Receipts. Header/line discounts and fees parallel the PO structure.","status":"draft","properties":[{"n":"invoiceNo","r":true,"t":"string"},{"n":"lines","r":true,"t":"array","info":"Array of VendorInvoiceLine sub-documents. Each line records an invoiced Item, quantity, and cost for three-way matching."},{"n":"vendor","r":true,"t":"entityRef","re":"Vendor"}],"ext":"OperationalDocument","notes":"Header Discounts/Fees are below-the-line. Line Discounts/Fees affect line cost.","related":["Vendor","Purchase Order","Goods Receipt","Purchase"],"bv":{"rules":[{"rule":"Must match PO/Receipt totals within configured tolerance","when":"match","field":"InvoiceTotal","severity":"warning"}],"lifecycle":{"states":["Draft","Matched","Approved","Posted","Disputed"],"transitions":[{"to":"Matched","from":"Draft","conditions":["Three-way match: PO, Receipt, Invoice within tolerance"]},{"to":"Approved","from":"Matched","conditions":["Approval workflow complete"]},{"to":"Posted","from":"Approved","conditions":["Payment scheduled"]},{"to":"Disputed","from":"Draft","conditions":["Variance exceeds tolerance"]},{"to":"Draft","from":"Disputed","conditions":["Dispute resolved, invoice corrected"]}],"initialState":"Draft"},"calculations":[],"crossEntityConstraints":[{"rule":"Three-way match against PO and Purchase","entity":"Purchase Order"},{"rule":"Line quantities must reconcile with received quantities","entity":"Goods Receipt"}]}},{"name":"Vendor Payment Term","class":"Dictionary","subsystem":"CONNECT","area":"Purchasing & Receiving","desc":"Negotiated payment conditions with a vendor (e.g. Net 30, 2/10 Net 30).","status":"stub","properties":[{"n":"code","r":true,"t":"string"},{"n":"description","t":"string"},{"n":"discountDays","t":"integer"},{"n":"discountPercent","t":"decimal"},{"n":"name","r":true,"t":"string","u":true},{"n":"netDays","t":"integer"}],"ext":"LookupEntity","related":["Vendor"],"bv":{"rules":[],"lifecycle":null,"calculations":[],"crossEntityConstraints":[]}}],"baseSchemas":[{"name":"Identifiable","desc":"Root base schema. Provides a UUID primary key. All persisted entities extend this, either directly or via BaseDocument / OperationalDocument / OperationalSubDocument / TransactionalDocument / LedgerEntry.","provides":["id"],"properties":[{"n":"id","r":true,"t":"string","info":"UUID v4 primary key."}],"extendedBy":["Attribute Set","Brand","Classification","Franchise Group","Sales Channel","Vendor Dictionary","Advanced Shipping Notice","Advanced Shipping Notice Item","Bill","Bill Item","Delivery Notification","Purchase Order Acknowledgement Line","Ship Notification","Vendor Credit","Vendor Credit Item","Vendor Invoice"]},{"name":"BaseDocument","desc":"Standard document base for non-operational entities (e.g. reports, configurations). Adds audit trail, soft-delete, custom data, and tagging.","provides":["id","recentActions","createdBy","createdDate","customData","franchiseGroups","isDeleted","modifiedBy","modifiedDate","tags","uniqueValues"],"properties":[{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this document belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export. Paired with franchiseGroups which provides sub-tenant segmentation within this Company."},{"n":"createdBy","t":"string","info":"User ID who created the document."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"customData","r":true,"t":"array","info":"Custom fields with label, fieldType, value, and sequence. Supports text, decimal, integer, date, flag, multiselect, lookup, and longtext."},{"n":"franchiseGroups","r":true,"t":"array","info":"EntityDetail references (code, name, alias, sequence) linking the document to franchise groups."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the document."},{"n":"modifiedDate","r":true,"t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"recentActions","r":true,"t":"array","info":"Denormalized snapshot of the most recent actions performed on this document (capped at the last 5 entries). The Entity Action Log is the system of record for the full audit trail. Each entry follows the Action inline schema: actionDate, actionedBy, code, label, actionType (FieldChange | Operation), and optional change detail."},{"n":"tags","r":true,"t":"array","info":"Free-form string tags for categorization."},{"n":"uniqueValues","r":true,"t":"array","info":"Alternative identifiers — array of Identifier (isPrimary, label, name, value)."}],"ext":"Identifiable","inlineSchemas":[{"name":"Action","schema":"schemas/common/Action.ts","properties":[{"info":"ISO 8601 timestamp when the action occurred.","name":"actionDate","type":"datetime","required":true},{"info":"User ID who performed the action.","name":"actionedBy","type":"string","required":true},{"info":"Discriminator: FieldChange for property-level mutations, Operation for domain events (e.g. status transition, approval).","name":"actionType","type":"enumeration","values":["FieldChange","Operation"],"required":true},{"info":"Field-level changes that occurred. Each entry is an ActionChange (fieldName, previousValue, newValue). Empty for Operation actions with no field-level side effects.","name":"changes","type":"array","required":true},{"info":"Stable, machine-readable action identifier (e.g. 'status.transition', 'price.update', 'approve', 'line.add'). Provides an enumerable key for reports, dashboards, and automation triggers. While actionType captures the category, code captures the semantic intent of the action.","name":"code","type":"string","required":true},{"info":"Human-readable summary of what happened (e.g. 'Status changed from Draft to Active').","name":"description","type":"string","required":true}]}]},{"name":"OperationalDocument","desc":"Extended document base for operational entities (Location, Vendor, Employee, etc.) and order-lifecycle entities (Sales Order, Purchase Order, etc.). Adds integration identifiers and an idempotency key on top of BaseDocument fields. Transactional entities extend this indirectly via TransactionalDocument.","provides":["id","recentActions","createdBy","createdDate","customData","franchiseGroups","identifiers","idmpKey","isDeleted","modifiedBy","modifiedDate","notes","tags","uniqueValues"],"properties":[{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this document belongs to. Defines the hard isolation boundary for queries, permissions, replication, and export. Paired with franchiseGroups which provides sub-tenant segmentation within this Company."},{"n":"createdBy","t":"string","info":"User ID who created the document."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"customData","r":true,"t":"array","info":"Custom fields with label, fieldType, value, and sequence. Supports text, decimal, integer, date, flag, multiselect, lookup, and longtext."},{"n":"franchiseGroups","r":true,"t":"array","info":"EntityDetail references (code, name, alias, sequence) linking the document to franchise groups."},{"n":"identifiers","r":true,"t":"array","info":"OperationalIdentifier array — extends Identifier with originatingSystemName for cross-system integration."},{"n":"idmpKey","r":true,"t":"string","info":"Idempotency / integration key for data-management deduplication."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the document."},{"n":"modifiedDate","r":true,"t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"notes","t":"string","info":"Free-text notes on this document."},{"n":"recentActions","r":true,"t":"array","info":"Denormalized snapshot of the most recent actions performed on this document (capped at the last 5 entries). The Entity Action Log is the system of record for the full audit trail. Each entry follows the Action inline schema defined on BaseDocument."},{"n":"tags","r":true,"t":"array","info":"Free-form string tags for categorization."},{"n":"uniqueValues","r":true,"t":"array","info":"Alternative identifiers — array of Identifier (isPrimary, label, name, value)."}],"ext":"Identifiable","extendedBy":["Product","Location","Employee","Vendor","Style","Sales Order","Purchase Order","Transfer Order","Shipment","Fulfillment Order","Ship Order","Catalog","Stock Take","Advanced Shipping Notice","Vendor Invoice","Vendor Credit","Customer","TransactionalDocument"]},{"name":"OperationalSubDocument","desc":"Lightweight operational base for line-items and child documents. Similar to OperationalDocument but without idmpKey or franchiseGroups. Used for entities that live within a parent document context.","provides":["id","recentActions","createdBy","createdDate","customData","identifiers","isDeleted","modifiedBy","modifiedDate","notes","tags","uniqueValues"],"properties":[{"n":"recentActions","r":true,"t":"array","info":"Denormalized snapshot of the most recent actions performed on this sub-document (capped at the last 5 entries). The Entity Action Log is the system of record for the full audit trail. Each entry follows the Action inline schema defined on BaseDocument."},{"n":"createdBy","t":"string","info":"User ID who created the sub-document."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"customData","r":true,"t":"array","info":"Custom fields with label, fieldType, value, and sequence."},{"n":"identifiers","r":true,"t":"array","info":"OperationalIdentifier array — extends Identifier with originatingSystemName."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the sub-document."},{"n":"modifiedDate","r":true,"t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"notes","t":"string","info":"Free-text notes on this sub-document."},{"n":"tags","r":true,"t":"array","info":"Free-form string tags for categorization."},{"n":"uniqueValues","r":true,"t":"array","info":"Alternative identifiers — array of Identifier (isPrimary, label, name, value)."}],"ext":"Identifiable","extendedBy":["Item","Advanced Shipping Notice Carton","Shipment Carton","Stock Transfer Carton"],"usedAsLinesBy":["Stock Adjustment","Stock Take","Stock Transfer","Transfer Order","Purchase Order","Goods Receipt","Vendor Invoice","Bill","Sales Order","Fulfillment Order","Ship Order","Fulfillment","Shipment","Sale","Advanced Shipping Notice Carton","Shipment Carton","Stock Transfer Carton","Purchase Order Acknowledgement"]},{"name":"TransactionalSubDocument","desc":"Lightweight transactional base for line-items and child documents within transactional entities. Extends OperationalSubDocument with transactionDate, fiscalDate, postedDate, and isVoided semantics. Used for sub-documents that participate in transactional workflows and may write to ledgers upon posting.","provides":["id","recentActions","createdBy","createdDate","customData","fiscalDate","identifiers","isDeleted","isVoided","modifiedBy","modifiedDate","notes","postedDate","tags","transactionDate","uniqueValues"],"properties":[{"n":"transactionDate","r":true,"t":"datetime","info":"The business date/time when the line-level transaction occurred. Typically inherited from the parent document but can be overridden for split-date scenarios."},{"n":"fiscalDate","r":true,"t":"datetime","info":"The fiscal calendar date assigned to this line. Used for period-based reporting. Typically inherited from the parent document."},{"n":"postedDate","t":"datetime","info":"Timestamp when this line was finalized and committed to its target ledger(s). Null while in a pre-posted state."},{"n":"isVoided","r":true,"t":"boolean","info":"Whether this line has been voided or reversed. Defaults to false. Voided lines remain for audit but are excluded from active reporting."}],"ext":"OperationalSubDocument","extendedBy":[]},{"name":"LookupEntity","desc":"Abstract base schema for all reference-data / dictionary entities. Provides the standard shape: code, name, alias, franchise-group scoping, active/default/deleted/readOnly flags, audit fields, and custom-data support. Not instantiated directly.","provides":["id","code","name","alias","franchiseGroups","idmpKey","isActive","isDefault","isDeleted","isReadOnly","sequence","createdBy","createdDate","modifiedBy","modifiedDate","customData"],"properties":[{"n":"alias","t":"schema","info":"Optional label/value pair for alternate display text (LookupEntityAlias)."},{"n":"code","r":true,"t":"string","info":"Human-readable key. Unique within scope."},{"n":"company","t":"entityDetail","re":"Company","info":"The Company tenant this lookup value belongs to. OPTIONAL on this base schema because a small set of dictionaries are platform-global (Currency, Locale, Country, Environment) and must have company null. All other Dictionary entities must declare company: required per the tenant-scoped-dictionary-declares-company convention."},{"n":"createdBy","t":"string","info":"User ID who created the record."},{"n":"createdDate","t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"customData","r":true,"t":"array","info":"Extensible key/value pairs for tenant-specific metadata (DocumentCustomData)."},{"n":"franchiseGroups","r":true,"t":"array","info":"EntityDetail references scoping this lookup value to one or more franchise groups."},{"n":"idmpKey","r":true,"t":"string","info":"Idempotency / integration key for data-management deduplication."},{"n":"isActive","r":true,"t":"boolean","info":"Whether this lookup value is active. Defaults to true."},{"n":"isDefault","r":true,"t":"boolean","info":"Whether this is the default selection. Defaults to false."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag. Defaults to false."},{"n":"isReadOnly","r":true,"t":"boolean","info":"Whether this lookup value is system-managed and not editable. Defaults to false."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the record."},{"n":"modifiedDate","t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"name","r":true,"t":"string","info":"Display name."},{"n":"sequence","t":"integer","info":"Display ordering hint."}],"ext":"Identifiable","extendedBy":["Currency","Locale","Tax Class","Price Level","Cost Level","Item Stock Group","Stock Limit Group","Purchasing Fee","Shipping Method","Loyalty Program"]},{"name":"LookupEntityValue","desc":"Base schema for inline value schemas within LookupEntity entities. Analogous to OperationalSubDocument for OperationalDocument — provides a lightweight identity and audit shape for nested value objects that exist only within the context of their parent LookupEntity. Carries its own id, identifiers, code, name, aliases, and audit trail.","provides":["id","identifiers","code","name","aliases","isActive","isDeleted","isDefault","sequence","createdBy","createdDate","modifiedBy","modifiedDate","customData"],"properties":[{"n":"identifiers","r":true,"t":"array","info":"OperationalIdentifier array — extends Identifier with originatingSystemName for cross-system integration."},{"n":"code","r":true,"t":"string","info":"Human-readable key. Unique within the parent entity's value collection."},{"n":"name","r":true,"t":"string","info":"Display name of the value."},{"n":"aliases","t":"array","info":"Alternative display names or label/value pairs for this value."},{"n":"isActive","r":true,"t":"boolean","info":"Whether this value is active. Defaults to true."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag. Defaults to false."},{"n":"isDefault","r":true,"t":"boolean","info":"Whether this is the default selection within the parent entity's value collection. Defaults to false."},{"n":"sequence","t":"integer","info":"Display ordering hint within the parent entity's value collection."},{"n":"createdBy","t":"string","info":"User ID who created the value."},{"n":"createdDate","t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the value."},{"n":"modifiedDate","t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"customData","r":true,"t":"array","info":"Extensible key/value pairs for tenant-specific metadata (DocumentCustomData)."}],"ext":"Identifiable"},{"name":"TransactionalDocument","desc":"Base schema for Transactional-class entities that record business events (sales, adjustments, receipts, transfers). Extends OperationalDocument with a standardized transaction date, posted date, and void/reversal semantics. Every TransactionalDocument writes to at least one Ledger upon posting.","provides":["id","recentActions","createdBy","createdDate","customData","fiscalDate","franchiseGroups","identifiers","idmpKey","isDeleted","isVoided","modifiedBy","modifiedDate","notes","postedDate","tags","transactionDate","uniqueValues"],"properties":[{"n":"transactionDate","r":true,"t":"datetime","info":"The business date/time when the transaction occurred. Distinct from createdDate (when the record was persisted) and postedDate (when it was finalized to ledgers). Maps to entity-specific names like Sale.date, StockAdjustment.adjustmentDate, Bill.billDate, GoodsReceipt.receivedDate, PriceAdjustment.effectiveDate, etc."},{"n":"fiscalDate","r":true,"t":"datetime","info":"The fiscal calendar date assigned to this transaction. Used for period-based reporting and accounting period assignment. May differ from transactionDate when transactions are recorded near period boundaries or when fiscal calendars do not align with calendar dates."},{"n":"postedDate","t":"datetime","info":"Timestamp when the transaction was finalized and committed to its target ledger(s). Null while the transaction is in a pre-posted state (e.g. Draft, Processing). Once set, the transaction is considered immutable for accounting purposes."},{"n":"isVoided","r":true,"t":"boolean","info":"Whether this transaction has been voided or reversed. Defaults to false. Voided transactions remain in the system for audit purposes but are excluded from active reporting. The void action writes a corresponding reversal entry to the relevant ledger(s)."}],"ext":"OperationalDocument","extendedBy":["Sale","Stock Adjustment","Stock Transfer","Goods Receipt","Purchase","Bill","Fulfillment","Price Adjustment","Cost Adjustment"]},{"name":"LedgerEntry","desc":"Base schema for Ledger-class entities — immutable, append-only audit records. Extends Identifiable directly (not OperationalDocument) because ledger entries must not be modified or deleted. Provides source-entity traceability and creation audit fields only. Individual ledger entities add domain-specific properties (e.g. ledgerLine, qty, amounts) on top.","provides":["id","entryDate","sourceEntityType","sourceEntityId","createdBy","createdDate"],"properties":[{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this ledger entry belongs to. Required at write time — ledger entries are immutable, so there is no opportunity to backfill company later. Also serves as the tenant partition key for ledger storage and per-tenant retention policies."},{"n":"createdBy","t":"string","info":"User ID or system principal that wrote this ledger entry."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 system timestamp when the entry was persisted. Always system-generated, never back-dated (unlike entryDate which may reflect the business event date)."},{"n":"entryDate","r":true,"t":"datetime","info":"Chronological timestamp of the ledger entry — the business date/time the recorded event occurred. May differ from createdDate when entries are back-dated or batch-processed."},{"n":"sourceEntityId","r":true,"t":"string","info":"UUID of the specific entity instance that triggered this ledger entry. Together with sourceEntityType, provides a complete back-reference to the originating transaction or event."},{"n":"sourceEntityType","r":true,"t":"string","info":"Entity class name that triggered this ledger entry (e.g. 'Sale', 'Stock Adjustment', 'Price Adjustment'). Used as a partition/index key alongside sourceEntityId for traceability queries."}],"ext":"Identifiable","extendedBy":["Stock Ledger","Price Ledger","Cost Ledger","Email Log","Entity Action Log"]},{"name":"TaxonomyEntity","desc":"Base schema for hierarchical classification entities that form tree structures (categories, departments, classes). Extends Identifiable with parent/child relationships, depth tracking, and path materialization for efficient tree traversal. Not instantiated directly — concrete taxonomy entities (ProductCategory, etc.) extend this.","provides":["id","ancestorIds","code","name","fullName","parent","children","depth","path","isLeaf","isRoot","sequence","isActive","isDeleted","createdBy","createdDate","modifiedBy","modifiedDate"],"properties":[{"n":"ancestorIds","r":true,"t":"array","info":"Ordered array of ancestor node IDs from root to immediate parent. Enables fast breadcrumb rendering and subtree queries without recursive lookups. Empty array for root nodes."},{"n":"children","t":"array","info":"Child nodes in the taxonomy tree."},{"n":"code","r":true,"t":"string","info":"Human-readable identifier. Unique within the taxonomy."},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this taxonomy tree belongs to. Product categories and types are always tenant-specific."},{"n":"createdBy","t":"string","info":"User ID who created the node."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"depth","r":true,"t":"integer","info":"Zero-based depth in the tree. Root nodes have depth 0."},{"n":"fullName","t":"string","info":"Calculated field. The fully qualified name built from the materialized path, concatenating ancestor names from root to this node (e.g. 'Apparel > Men > Outerwear')."},{"n":"isActive","r":true,"t":"boolean","info":"Whether this taxonomy node is active. Defaults to true."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag. Defaults to false."},{"n":"isLeaf","r":true,"t":"boolean","info":"Whether this node has no children. Computed from children array. Leaf nodes are selectable for entity assignment; branch nodes are for navigation only."},{"n":"isRoot","r":true,"t":"boolean","info":"Whether this is a top-level node with no parent. Computed from depth (depth === 0)."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the node."},{"n":"modifiedDate","r":true,"t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"name","r":true,"t":"string","info":"Display name of the taxonomy node."},{"n":"parent","t":"entityRef","info":"Self-referencing parent node. Null for root nodes."},{"n":"path","r":true,"t":"string","info":"Materialized path for efficient ancestor/descendant queries (e.g. '/root/parent/this'). Enables tree traversal without recursive queries."},{"n":"sequence","t":"integer","info":"Display ordering hint among siblings at the same depth."}],"ext":"Identifiable","extendedBy":["Product Category","Product Type"]},{"name":"TaxonomyEntityNode","desc":"Base schema for individual nodes within a taxonomy hierarchy (e.g. Classification Department, Classification Class, Classification Subclass). Extends Identifiable with the common properties shared by all taxonomy node entities — code, name, sequence, and audit fields. Simpler than TaxonomyEntity which represents the full tree structure; TaxonomyEntityNode represents a single level/node within that tree.","provides":["id","code","name","sequence","isActive","isDeleted","createdBy","createdDate","modifiedBy","modifiedDate"],"properties":[{"n":"code","r":true,"t":"string","info":"Human-readable identifier. Unique within the node type."},{"n":"company","r":true,"t":"entityDetail","re":"Company","info":"The Company tenant this taxonomy node belongs to. Classification Department/Class/Subclass are always tenant-specific."},{"n":"createdBy","t":"string","info":"User ID who created the node."},{"n":"createdDate","r":true,"t":"datetime","info":"ISO 8601 creation timestamp."},{"n":"isActive","r":true,"t":"boolean","info":"Whether this node is active. Defaults to true."},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag. Defaults to false."},{"n":"modifiedBy","t":"string","info":"User ID who last modified the node."},{"n":"modifiedDate","r":true,"t":"datetime","info":"ISO 8601 last-modification timestamp."},{"n":"name","r":true,"t":"string","info":"Display name of the taxonomy node."},{"n":"sequence","t":"integer","info":"Display ordering hint among sibling nodes."}],"ext":"Identifiable","extendedBy":["Classification Department","Classification Class","Classification Subclass"]}],"valueTypes":[{"name":"BasicAddress","desc":"Core postal address fields. Base type for all address structures.","properties":[{"n":"city","r":true,"t":"string"},{"n":"countryCode","r":true,"t":"string","info":"ISO 3166-1 alpha-2"},{"n":"line1","r":true,"t":"string"},{"n":"line2","t":"string"},{"n":"line3","t":"string"},{"n":"organization","t":"string"},{"n":"postalCode","r":true,"t":"string"},{"n":"state","t":"string"}]},{"name":"Address","desc":"Extended address with contact details and labeling. Used for entity mailing/billing addresses.","properties":[{"n":"email","t":"string"},{"n":"label","t":"string","info":"e.g. 'Headquarters', 'Billing', 'Shipping'"},{"n":"name","t":"string","info":"Addressee name"},{"n":"notes","t":"string"},{"n":"phone","t":"string"}],"ext":"BasicAddress","usedBy":["Business Entity.Address","Franchise Group.PostalAddress","Franchise Group.BillingAddress","Vendor.Address","Customer.Address"]},{"name":"AddressBook","desc":"Ordered collection of addresses with primary flag and identifiers. Used when an entity maintains multiple addresses.","properties":[{"n":"addressNo","t":"integer","info":"Sequence number within the book"},{"n":"identifiers","r":true,"t":"array","info":"Array of Identifier value objects"},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag"},{"n":"isPrimary","r":true,"t":"boolean"}],"ext":"Address"},{"name":"Phone","desc":"A phone number entry with label and primary flag.","properties":[{"n":"isPrimary","r":true,"t":"boolean"},{"n":"label","t":"string","info":"e.g. 'Mobile', 'Work', 'Fax'"},{"n":"phoneNumber","r":true,"t":"string"}]},{"name":"Email","desc":"An email address entry with label and primary flag.","properties":[{"n":"email","r":true,"t":"string"},{"n":"isPrimary","r":true,"t":"boolean"},{"n":"label","t":"string","info":"e.g. 'Work', 'Personal'"}]},{"name":"PersonName","desc":"Structured person name with title and middle name support.","properties":[{"n":"firstName","r":true,"t":"string"},{"n":"lastName","r":true,"t":"string"},{"n":"middleName","t":"string"},{"n":"title","t":"string","info":"e.g. 'Mr', 'Ms', 'Dr'"}]},{"name":"Contact","desc":"A full contact record combining name, phones, emails, address, and custom data. Used for vendor contacts, customer contacts, etc.","properties":[{"n":"address","t":"valueType","info":"Address value type"},{"n":"contactNo","t":"integer","info":"Sequence number"},{"n":"customData","t":"schema","info":"Extensible key-value data"},{"n":"emails","r":true,"t":"array","info":"Array of Email value objects"},{"n":"franchiseGroups","r":true,"t":"array","info":"Associated Franchise Group codes"},{"n":"isActive","r":true,"t":"boolean"},{"n":"isDeleted","r":true,"t":"boolean","info":"Soft-delete flag"},{"n":"isPrimary","r":true,"t":"boolean"},{"n":"name","t":"valueType","info":"PersonName value type"},{"n":"phones","r":true,"t":"array","info":"Array of Phone value objects"}]},{"name":"EntityDetail","desc":"Denormalized snapshot of a referenced entity's identity fields (id + code + name + alias + sequence). Embedded inline on the parent document to avoid a separate query for basic display information. Extends Identifiable (adds UUID id). Used for Location and Dictionary/Lookup entity references.","properties":[{"n":"alias","t":"string"},{"n":"code","r":true,"t":"string"},{"n":"name","r":true,"t":"string"},{"n":"sequence","t":"integer"}]},{"name":"Identifier","desc":"A labeled identifier value (e.g. tax ID, loyalty number, external system reference).","properties":[{"n":"isPrimary","r":true,"t":"boolean"},{"n":"label","t":"string"},{"n":"name","r":true,"t":"string","info":"Identifier type label"},{"n":"value","r":true,"t":"string"}]},{"name":"Payment","desc":"A payment tender line within a transaction — captures method, amount, and change.","properties":[{"n":"accountNo","t":"string"},{"n":"accountType","t":"string"},{"n":"amount","r":true,"t":"decimal"},{"n":"changeAmount","t":"decimal"},{"n":"code","r":true,"t":"string","info":"Payment method code"},{"n":"name","r":true,"t":"string","info":"Payment method display name"},{"n":"paymentCardType","t":"string","info":"e.g. Visa, Mastercard, AMEX"},{"n":"paymentDate","t":"datetime"},{"n":"sequence","t":"integer"}]},{"name":"Money","desc":"Amount with currency code. Used wherever a monetary value needs explicit currency context.","properties":[{"n":"amount","r":true,"t":"decimal"},{"n":"currencyCode","r":true,"t":"string","info":"ISO 4217 currency code"}]},{"name":"ConfigurationRef","desc":"Embedded reference from a configurable entity to its configuration record in the CONFIG subsystem. The `config` field carries a denormalized snapshot of the Config entity (id, code, name) so runtime services can resolve configuration without an extra round-trip; `templateCode` optionally names the Config Template the config was derived from, which lets consumers validate expected shape and discover available keys. This value type is the canonical shape of every configurable entity's link to CONFIG — do not declare ad-hoc configId strings on entities. Consumers that need richer linkage (environment scope, version pinning, override chain) should add fields here rather than on each entity.","properties":[{"n":"config","r":true,"t":"entityDetail","re":"Config","info":"Denormalized snapshot of the referenced Config record (id, code, name). Follows the standard entityDetail pattern so display never requires a lookup. The Config itself holds Actor, Environment, and resolved values."},{"n":"templateCode","r":false,"t":"string","info":"Code of the Config Template the referenced Config was derived from. Optional, but recommended so consumers can validate against the expected schema and discover which keys are available."}],"usedBy":["Location","Organization","Company","Connector","Sales Channel"]}],"conventions":[{"id":"array-must-be-required","scope":"property","severity":"error","when":"type === 'array'","expect":"required === true","reason":"Array properties must be required. An empty array [] is the minimum default; null/undefined arrays cause runtime errors in iteration and spread operations.","active":true},{"id":"boolean-must-be-required","scope":"property","severity":"error","when":"type === 'boolean'","expect":"required === true","reason":"Boolean properties must be required with a default of false. undefined/null booleans cause subtle bugs: `if (!flag)` is true for both false and undefined, masking missing data as intentional 'off'.","active":true},{"id":"datetime-stored-as-utc","scope":"property","severity":"error","when":"type === 'datetime'","expect":"value is stored as ISO 8601 UTC string (Z suffix). Zod schema uses z.coerce.date().","reason":"All datetime values must be persisted in UTC (e.g. 2024-01-15T14:30:00.000Z). Display conversion to the device timezone is a presentation-layer concern handled by Intl.DateTimeFormat or date-fns-tz.","active":true},{"id":"date-is-calendar-only","scope":"property","severity":"error","when":"type === 'date'","expect":"value is stored as ISO 8601 date string (YYYY-MM-DD) with no time or timezone component. Zod schema uses z.string().date().","reason":"Date properties represent calendar dates (e.g. birthDate, effectiveDate) with no point-in-time semantics. Storing a bare YYYY-MM-DD string avoids timezone-shift bugs where a UTC midnight rolls to the previous day in western timezones.","active":true},{"id":"decimal-monetary-inherits-currency","scope":"property","severity":"warning","when":"type === 'decimal' and property represents a monetary amount (price, cost, total, fee, amount)","expect":"currency context is provided by the parent entity's Market baseCurrency (for single-currency operations) or the Money value type is used (for cross-currency transactions). Financial documents that cross currency boundaries should capture exchangeRate and exchangeRateCurrency at transaction time.","reason":"Bare decimal amounts without currency context are ambiguous in multi-market operations. The Market.baseCurrency defines the implicit currency for all prices and costs within that market. Cross-currency values (e.g. vendor invoices in a foreign currency) must use the Money value type to pair amount with ISO 4217 currencyCode. Display conversion to the user's local currency is a presentation-layer concern.","active":true},{"id":"entity-detail-needs-related-entity","scope":"property","severity":"error","when":"type === 'entityDetail'","expect":"relatedEntity is defined","reason":"entityDetail properties must specify which entity they denormalize via relatedEntity.","active":true},{"id":"entity-detail-requires-id-code-name","scope":"property","severity":"error","when":"type === 'entityDetail'","expect":"the denormalized snapshot always includes id, code, and name fields from the referenced entity","reason":"entityDetail properties embed a denormalized snapshot following the EntityDetailSchema shape (id + code + name + alias? + sequence?). The three mandatory fields — id for foreign-key integrity, code for human-readable lookups, and name for display — must always be present so consumers never need a separate round-trip for basic identification or rendering.","active":true},{"id":"entity-ref-needs-related-entity","scope":"property","severity":"error","when":"type === 'entityRef'","expect":"relatedEntity is defined","reason":"entityRef properties must specify the target entity via relatedEntity.","active":true},{"id":"enumeration-needs-values","scope":"property","severity":"error","when":"type === 'enumeration'","expect":"values is defined and non-empty","reason":"Enumeration properties must list their allowed values for schema generation and UI dropdowns.","active":true},{"id":"value-type-needs-name","scope":"property","severity":"warning","when":"type === 'valueType'","expect":"valueTypeName is defined OR info mentions the value type name","reason":"valueType properties should reference a specific ValueObjectDef by name for traceability.","active":true},{"id":"encrypted-needs-description","scope":"property","severity":"warning","when":"type === 'encrypted'","expect":"info is defined and non-empty","reason":"Encrypted properties should describe what is stored to aid security audits.","active":true},{"id":"property-names-unique","scope":"entity","severity":"error","when":"always","expect":"no duplicate property names within the same entity","reason":"Duplicate property names cause schema conflicts and ambiguous data access.","active":true},{"id":"properties-alphabetical-order","scope":"entity","severity":"warning","when":"entity has two or more own properties","expect":"properties are sorted alphabetically by name (a → z)","reason":"Alphabetical property ordering makes entities scannable, eliminates merge conflicts from arbitrary insertion, and ensures consistency across the registry.","active":true},{"id":"entity-needs-description","scope":"entity","severity":"error","when":"always","expect":"desc is defined and non-empty","reason":"Every entity must have a description for documentation and developer onboarding.","active":true},{"id":"entity-needs-at-least-one-property","scope":"entity","severity":"warning","when":"always","expect":"properties array has at least one entry","reason":"Entities with zero properties provide no schema value. At minimum, define the primary identifier.","active":true},{"id":"operational-document-declares-inherited","scope":"entity","severity":"warning","when":"extends === 'OperationalDocument'","expect":"inherited field is defined and lists base schema fields","reason":"Entities extending OperationalDocument should declare their inherited fields for audit completeness.","active":true},{"id":"transactional-document-declares-inherited","scope":"entity","severity":"warning","when":"extends === 'TransactionalDocument'","expect":"inherited field is defined and lists base schema fields (including transactionDate, fiscalDate, postedDate, isVoided from TransactionalDocument)","reason":"Entities extending TransactionalDocument should declare their inherited fields for audit completeness.","active":true},{"id":"ledger-entry-declares-inherited","scope":"entity","severity":"warning","when":"extends === 'LedgerEntry'","expect":"inherited field is defined and lists base schema fields (entryDate, sourceEntityType, sourceEntityId, createdBy, createdDate)","reason":"Entities extending LedgerEntry should declare their inherited fields for audit completeness.","active":true},{"id":"ledger-entry-immutability","scope":"entity","severity":"error","when":"extends === 'LedgerEntry'","expect":"entity does not declare modifiedBy, modifiedDate, or isDeleted properties","reason":"Ledger entries are immutable and append-only. Corrections must be made via new compensating entries, not by modifying or deleting existing records.","active":true},{"id":"operational-subdocument-declares-inherited","scope":"entity","severity":"warning","when":"extends === 'OperationalSubDocument'","expect":"inherited field is defined and lists base schema fields","reason":"Entities extending OperationalSubDocument should declare their inherited fields.","active":true},{"id":"related-entities-exist-in-registry","scope":"entity","severity":"error","when":"relatedEntities is defined","expect":"every name in relatedEntities matches an entity name in the registry","reason":"Dangling relatedEntities references create broken links in the entity graph.","active":true},{"id":"entity-ref-target-exists","scope":"property","severity":"error","when":"type === 'entityRef' or type === 'entityDetail'","expect":"relatedEntity matches an entity name in the registry","reason":"Entity reference properties must point to a valid entity in the registry.","active":true},{"id":"dictionary-ref-uses-entity-detail","scope":"property","severity":"warning","when":"relatedEntity points to a Dictionary-class entity","expect":"type === 'entityDetail'","reason":"References to Dictionary/Lookup entities should use entityDetail to embed display fields (code, name, alias) and avoid unnecessary lookups.","active":true},{"id":"location-ref-uses-entity-detail","scope":"property","severity":"warning","when":"relatedEntity === 'Location'","expect":"type === 'entityDetail'","reason":"Location references should use entityDetail (confirmed from Zod schemas) since location name/code is frequently displayed.","active":true},{"id":"line-entities-are-inline-schemas","scope":"entity","severity":"error","when":"entity name contains 'Line' and represents a child row of a parent document (e.g. PO Line, Sales Order Line, Transfer Order Line)","expect":"modeled as an inline schema (type: 'schema' or type: 'array' with inline properties) on the parent entity — NOT as an independent entity in the registry","reason":"Line entities exist only within the context of their parent document. They do not have their own idmpKey, independent lifecycle, or standalone persistence. A PO Line cannot exist without a PO. Modeling them as independent entities creates orphaned references and misrepresents the domain. Use OperationalSubDocument-based inline schemas on the parent entity's line-item array property instead.","active":true},{"id":"inline-schema-has-properties","scope":"inlineSchema","severity":"error","when":"property has extends (inline line schema)","expect":"properties array is defined and non-empty","reason":"Inline line schemas must define their own properties; an empty extension of the base schema adds no domain value.","active":true},{"id":"inline-schema-registered","scope":"inlineSchema","severity":"warning","when":"property has extends on an array property","expect":"parent entity + property name appears in OperationalSubDocument.inlineSchemas","reason":"All inline line schemas should be registered in the OperationalSubDocument.inlineSchemas list for discoverability.","active":true},{"id":"property-name-camel-case","scope":"property","severity":"error","when":"any property","expect":"name is camelCase (first letter lowercase, no underscores/hyphens/spaces)","reason":"All property names must use camelCase for consistency with TypeScript/JavaScript conventions and Zod schema field names.","active":true},{"id":"entity-name-title-case","scope":"entity","severity":"error","when":"any entity","expect":"name is Title Case (each word capitalized, spaces between words, e.g. 'Purchase Order', 'Sales Channel')","reason":"Entity names are human-readable domain terms used in documentation, UI, and the entity graph. Title Case ensures consistency and readability. Code identifiers (variable names, file names) derive from the entity name programmatically.","active":true},{"id":"array-name-plural","scope":"property","severity":"warning","when":"property type is array","expect":"property name is plural (ends with 's', 'es', 'ies', etc.)","reason":"Array properties represent collections and should use plural names for clarity.","active":true},{"id":"entity-uuid-id","scope":"entity","severity":"error","when":"entity class is Core, Operational, Transactional, Dictionary, Order, Ledger, or Balance","expect":"entity has an 'id' property of type UUID (inherited from a base schema or declared directly)","reason":"Every entity must have a universally unique identifier (UUID) for cross-system referencing, replication, and foreign-key integrity. The id field is the primary key across all entity classes.","active":true},{"id":"dictionary-code-property","scope":"entity","severity":"error","when":"entity class === 'Dictionary'","expect":"entity has a 'code' property of type string that is required and unique — serving as the human-readable identifier","reason":"Dictionary entities are reference/lookup data (e.g. Season, Brand, Tax Class). A short, human-readable 'code' property provides a stable, memorable identifier for use in imports, API filters, and UI dropdowns. Using 'code' consistently across all Dictionary entities enables generic lookup patterns.","active":true},{"id":"entity-no-property","scope":"entity","severity":"error","when":"entity class is Core, Operational, Transactional, Order, or Balance","expect":"entity has a human-readable identifier property named '{entityName}No' in camelCase (e.g. productNo, itemNo, purchaseOrderNo, salesChannelNo). The property should be required and unique.","reason":"A human-readable number property provides a business-friendly identifier for use in documents, labels, search, and customer communication. The {entity}No naming convention ensures consistency across all non-Dictionary entity classes and makes the identifier predictable for API consumers and UI generation.","active":true},{"id":"calculated-count-naming","scope":"property","severity":"error","when":"calculated === true and field represents a count","expect":"name follows {relatedEntity}Count pattern in camelCase (e.g. vendorCount, salesChannelCount). Scoped counts add a qualifier prefix (e.g. publishedSalesChannelCount, activeItemCount). Type is always integer.","reason":"Consistent naming for count fields enables predictable API responses, automated dashboard generation, and clear developer expectations. The {entity}Count pattern mirrors industry conventions (SQL COUNT, GraphQL connection counts).","active":true},{"id":"calculated-field-documented","scope":"entity","severity":"warning","when":"entity has array properties referencing other entities or significant cross-entity relationships","expect":"businessValidation.calculations includes derived count fields with formula and trigger","reason":"Calculated fields should be documented in the entity registry so the query layer, API consumers, and documentation all agree on what derived fields are available. The calculations array serves as the contract between schema documentation and runtime implementation.","active":true},{"id":"deprecated-property-not-required","scope":"property","severity":"error","when":"property is marked deprecated","expect":"required is false or undefined","reason":"Deprecated properties must not be required — consumers need to stop depending on them before removal. Making a deprecated property optional is the first step in the deprecation lifecycle.","active":true},{"id":"deprecated-needs-replacement","scope":"property","severity":"error","when":"property is marked deprecated","expect":"deprecation annotation includes reason and either replacedBy (property or entity name) or an explicit migration note","reason":"Deprecated properties must tell consumers what to use instead. A bare deprecation flag without guidance leaves consumers stranded. See Schema Evolution in the glossary for the full lifecycle.","active":true},{"id":"deprecated-needs-sunset-date","scope":"property","severity":"warning","when":"property is marked deprecated","expect":"deprecation annotation includes a sunset date (YYYY-MM format)","reason":"A sunset date sets expectations for consumers and enables automated compliance checks. Internal schemas: minimum 2 release cycles. Webhook payloads: 3 months. Public API: 6 months.","active":true},{"id":"overridable-default-prefix","scope":"property","severity":"error","when":"entity declares inheritance.childEntity and property is listed in inheritance.overridableDefaults","expect":"property name starts with 'default' (e.g. defaultBasePrice, defaultPrices)","reason":"The default* prefix signals that this value serves as a fallback for child entities. Children override by defining the same property without the prefix. Resolution: effectiveValue = child.{name} ?? parent.default{Name}.","active":true},{"id":"child-override-matches-parent","scope":"property","severity":"error","when":"entity declares inheritance.parentEntity and property is listed in inheritance.overridableProperties","expect":"property name matches the parent's default* property with the 'default' prefix removed and first letter lowercased (e.g. Product.defaultBasePrice → Item.basePrice)","reason":"Consistent naming between parent defaults and child overrides enables automatic effective-value resolution and makes the inheritance chain self-documenting.","active":true},{"id":"company-scoping-required","scope":"entity","severity":"error","when":"entity class is Operational, Transactional, Dictionary, Ledger, Taxonomy, or Balance AND entity name is NOT in the control-plane exemption set (Organization, Client, Company, Environment, Scope, Application)","expect":"entity has a 'company' property of type entityDetail pointing to Company, OR inherits one from a base schema (BaseDocument, OperationalDocument, TaxonomyEntity, TaxonomyEntityNode, LedgerEntry). For tenant-plane Dictionary/LookupEntity entities, the company property is required; for platform-global dictionaries (Currency, Locale, Country, Environment), it is absent — see tenant-scoped-dictionary-declares-company.","reason":"Every tenant-plane entity must carry a Company reference to define the hard isolation boundary for queries, permissions, replication, and export. Control-plane entities (Organization, Client, Company itself, Environment, Scope, Application) are exempt because they describe the deployed infrastructure, not tenant data.","active":true},{"id":"tenant-scoped-dictionary-declares-company","scope":"entity","severity":"error","when":"entity extends LookupEntity or LookupEntityValue AND entity name is NOT in the platform-global dictionary exemption set (Currency, Locale, Country, Environment)","expect":"entity declares a required 'company' property of type entityDetail → Company. LookupEntity's base-schema company property is optional by design so platform-global dictionaries can omit it; tenant-scoped dictionaries must override by declaring it required.","reason":"LookupEntity is shared between tenant-scoped dictionaries (Tax Class, Brand, Season) and platform-global dictionaries (Currency, Locale, Country, Environment). Because the base schema leaves company optional, each tenant-scoped dictionary must explicitly declare company required. Platform-global dictionaries are exempt and must NOT declare company.","active":true},{"id":"subdoc-tenant-inheritance","scope":"entity","severity":"warning","when":"entity extends OperationalSubDocument or TransactionalSubDocument","expect":"entity does NOT declare its own 'company' property. Sub-documents inherit their tenant boundary from the parent document and must not duplicate the reference — this prevents drift between parent and sub-doc company values.","reason":"Sub-documents (line items, status records, nested schedules) exist only within the context of a parent Operational or Transactional Document, which already carries the Company reference. Declaring company on the sub-document creates redundant state that can drift from the parent and bloats denormalized snapshots.","active":true},{"id":"configurable-entity-declares-configuration","scope":"entity","severity":"error","when":"entity is in the configurable entity set (Location, Organization, Company, Connector, Sales Channel, Document Type) — i.e. entities whose runtime behavior is shaped by a Config record in the CONFIG subsystem, including Document Type which acts as the policy anchor for all documents of its category (PO, ASN, Bill, etc.)","expect":"entity declares a required property named `configuration` of type `valueType` whose info or valueTypeName references `ConfigurationRef`","reason":"Configurable entities must carry an explicit, uniformly-typed link to their Config record so runtime services can resolve configuration generically. Using a named value type (ConfigurationRef) instead of ad-hoc configId strings keeps the contract in one place, supports entityDetail denormalization of the Config identity, and leaves room to evolve the reference shape (adding scope, version, override chain) without migrating every entity. The single-inheritance model of the registry means this trait cannot be expressed as a mixin base schema; this convention is the enforcement mechanism. Document Type specifically is included as a *policy anchor* — concrete document entities (Purchase Order, Bill, ASN, Vendor Invoice) inherit rules like expiration, approval thresholds, and numbering from their Document Type's configuration rather than declaring their own, which keeps lifecycle behavior uniform across all documents of a category.","active":true},{"id":"product-read-through-must-aggregate-item","scope":"property","severity":"warning","when":"Property is on Product, is calculated:true, type=datetime, name ends in 'At', AND a property of the same name exists on Item with calculated:true and type=datetime","expect":"Product-level value must be the aggregation (MIN for properties starting with 'first', MAX for properties starting with 'last') of the corresponding Item-level values across every Item belonging to the Product. Stock Ledger Service (or other SoR providers) must implement Product-level projections by rolling up Item-level results, not by issuing a separate query path.","reason":"Product is the parent of Item (SKU/variant). Defining the aggregation contract in one place keeps SoR projection logic consistent and prevents drift between Product and Item answers to the same question (e.g., Product.lastSoldAt should never be older than the most recent Item.lastSoldAt for that product). Without this rule, two implementations could diverge silently.","active":true},{"id":"item-read-through-must-aggregate-item-stock","scope":"property","severity":"warning","when":"Property is on Item, is calculated:true, type=datetime, name ends in 'At', AND a property of the same name exists on Item Stock with calculated:true and type=datetime","expect":"Item-level value must be the aggregation (MIN for properties starting with 'first', MAX for properties starting with 'last') of the corresponding Item Stock-level values across every Item Stock row (Item × Location) belonging to the Item. SoR providers must implement Item-level projections by rolling up Item Stock-level results, not by issuing a separate query path against the Stock Ledger or PO subsystem.","reason":"Item Stock is the per-Location leaf for these date projections, Item is the per-SKU rollup across Locations, and Product is the per-parent rollup across SKUs (governed by product-read-through-must-aggregate-item). This convention completes the three-level chain Item Stock → Item → Product so projection logic stays consistent end-to-end. Without it, an SoR could compute Item.lastReceivedAt directly from the Stock Ledger by Item without going through Item Stock, then drift from the per-Location values surfaced on Item Stock rows. Sibling rule to product-read-through-must-aggregate-item.","active":true}]}