WorkspacePostingMapping

WorkspacePostingMapping encodes a single posting rule that maps a semantic document context (CoA version, semantic role, posting kind, document polarity) to accounting targets (LedgerAccount, TaxRate, Journal) for a workspace. The posting engine writes these rows deterministically or via LLM review; the rule-resolver reads them at journal-entry draft time to auto-classify postings. Each row is scoped to a Workspace and optionally to a specific WorkspaceConnector, with precision modifiers for tax behaviour, counterparty kind, currency, country code, and effective date range. A partial unique index (WHERE deleted_at IS NULL AND mapping_status = 'active') prevents duplicate active mappings for the same context tuple.

NamingValue
ObjectWorkspacePostingMapping
Resource type (JSON:API type)workspace_posting_mapping
Collection / records rootโ€” (not a records root)
REST base/v1/workspace-posting-mappings
Entity classWorkspacePostingMapping

Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.

API operations

OperationMethod & pathStatus
ListGET /v1/workspace-posting-mappings๐ŸŸก Planned
RetrieveGET /v1/workspace-posting-mappings/{id}๐ŸŸก Planned
CreatePOST /v1/workspace-posting-mappings๐ŸŸก Planned
UpdatePATCH /v1/workspace-posting-mappings/{id}๐ŸŸก Planned
DeleteDELETE /v1/workspace-posting-mappings/{id}๐ŸŸก Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
workspace_posting_mapping_idstring (UUID)โœ… YesUNIQUEโ€”Public UUID identifying this posting rule. Generated via gen_random_uuid() on insert.
well_coa_versionstringโœ… Yesmax length 32โ€”Version tag of the Well Chart-of-Accounts taxonomy this mapping targets (e.g. 'v2024').
well_semantic_rolestringโœ… Yesmax length 100โ€”Semantic accounting role within the CoA taxonomy (e.g. 'accounts_payable', 'revenue_product').
posting_kindstringโœ… Yesmax length 50โ€”Kind of source document or transaction driving the posting (e.g. 'invoice', 'bank_transaction').
document_polaritystringโœ… Yesmax length 50โ€”Polarity direction of the posting line: whether this rule applies to the debit or credit leg.
tax_behaviorstring | nullโšช Nomax length 50โ€”Optional tax inclusion modifier narrowing the rule ('exclusive', 'inclusive', 'none'). NULL means the rule applies regardless of tax behaviour.
counterparty_kindstring | nullโšช Nomax length 50โ€”Optional counterparty classification narrowing the rule (e.g. 'supplier', 'customer'). NULL matches any counterparty kind.
currencystring | nullโšช Nomax length 3โ€”Optional ISO 4217 currency code narrowing the rule. NULL matches any currency.
country_codestring | nullโšช Nomax length 2โ€”Optional ISO 3166-1 alpha-2 country code narrowing the rule. NULL matches any country.
effective_fromdate | nullโšช NoCHECK: effective_from <= effective_to when both non-NULLโ€”Inclusive start date from which this rule is effective. NULL means no lower bound. Used in the partial-unique active-context index via COALESCE.
effective_todate | nullโšช NoCHECK: effective_from <= effective_to when both non-NULLโ€”Exclusive end date after which this rule is no longer effective. NULL means open-ended.
mapping_status๐Ÿ”’ system โ€” enum (WorkspacePostingMappingStatusEnum)โœ… Yesdefault: 'active'; native enum workspace_posting_mapping_status_enumactive | needs_review | inactiveLifecycle state of this mapping rule. The partial unique index on active-context enforces one active rule per context tuple. Managed by the posting engine.
confidencestring (decimal 4,3) | nullโšช NoCHECK: value IS NULL OR (value >= 0 AND value <= 1); decimal(4,3)โ€”Confidence score in [0.000, 1.000] assigned by the LLM jury or deterministic engine. Stored as decimal(4,3); exposed as string in JSON to preserve precision.
evidenceobject (JSONB) | nullโšช Noโ€”โ€”Free-form JSONB payload recording why this mapping was created (matched patterns, rule sources, jury rationale). Shape varies by created_by value.
created_by๐Ÿ”’ system โ€” enum (WorkspacePostingMappingCreatedByEnum)โœ… Yesdefault: 'deterministic'; native enum workspace_posting_mapping_created_by_enumdeterministic | manual | reviewed_llmProvenance of this mapping: whether it was produced by a deterministic rule, manual human edit, or an LLM that was subsequently reviewed.
mapping_version๐Ÿ”’ system โ€” integerโœ… Yesdefault: 1โ€”Monotonically increasing version counter incremented by the posting engine on each rule revision. Default 1.
created_at๐Ÿ”’ system โ€” datetimeโœ… Yesโ€”โ€”Timestamp when this mapping was created. Set automatically via onCreate hook.
updated_at๐Ÿ”’ system โ€” datetime | nullโšช Noโ€”โ€”Timestamp of the last update to this mapping. Set automatically via onUpdate hook.
deleted_at๐Ÿ”’ system โ€” datetime | nullโšช Noโ€”โ€”Soft-delete timestamp. Non-null means the mapping is logically deleted and excluded from the partial unique active-context index. All queries must filter deleted_at IS NULL.

Relationships

NameTypeRequiredDescription
workspaceto-one (ManyToOne)โœ… YesThe Workspace this posting rule belongs to. All queries must scope by workspace_pk. Indexed as part of the role and status composite indexes.
sourceWorkspaceConnectorto-one (ManyToOne)โšช NoOptional WorkspaceConnector that provided the data driving this rule. NULL means the rule applies generically across all connectors for this workspace. ON DELETE SET NULL โ€” deleting the connector nullifies but does not delete the mapping.
ledger_accountto-one (ManyToOne)โšช NoTarget LedgerAccount to post to for this context. NULL is valid when the rule's primary purpose is to select only a TaxRate or Journal without specifying a ledger account.
tax_rateto-one (ManyToOne)โšช NoTarget TaxRate to apply when posting. NULL means no tax rate is assigned by this mapping; the posting engine may inherit or default.
journalto-one (ManyToOne)โšช NoTarget Journal (accounting book) to route journal entries into. NULL defers journal selection to the posting engine's default resolution logic.

System-computed

  • workspace_posting_mapping_id โ€” generated via gen_random_uuid() on insert, exposed as the public API id
  • created_at โ€” set automatically by the MikroORM onCreate hook; never writable after creation
  • updated_at โ€” set automatically by the MikroORM onUpdate hook on every write
  • deleted_at โ€” soft-delete field written by the posting engine on rule retirement; not writable by users
  • mapping_status โ€” managed exclusively by the posting engine (transitions: active โ†’ needs_review โ†’ inactive or active โ†’ deleted_at); default 'active' on creation
  • mapping_version โ€” incremented by the posting engine on each rule revision; default 1
  • created_by โ€” set at creation time by the engine to record provenance ('deterministic', 'reviewed_llm') or set to 'manual' for human-authored rules; not subsequently editable
  • confidence โ€” computed and stamped by the LLM jury or deterministic scoring logic; null for fully-deterministic rules
  • evidence โ€” populated by the engine with the reasoning payload from the mapping generation run
  • sourceWorkspaceConnector provenance โ€” when set, records which connector sync triggered the mapping creation; ON DELETE SET NULL ensures orphan safety on connector removal
  • Partial unique index workspace_posting_mappings_active_context_unique (WHERE deleted_at IS NULL AND mapping_status = 'active') โ€” enforced at the DB layer only; cannot be expressed via MikroORM decorators (COALESCE expressions + partial predicate). The entity comment documents this divergence from schema:fresh.

Example

{
  "data": {
    "type": "workspace_posting_mapping",
    "id": "a3f1c2e4-8b7d-4f9a-b2c1-0d5e6f7a8b9c",
    "attributes": {
      "workspace_posting_mapping_id": "a3f1c2e4-8b7d-4f9a-b2c1-0d5e6f7a8b9c",
      "well_coa_version": "v2024",
      "well_semantic_role": "accounts_payable",
      "posting_kind": "invoice",
      "document_polarity": "debit",
      "tax_behavior": "exclusive",
      "counterparty_kind": "supplier",
      "currency": "EUR",
      "country_code": "FR",
      "effective_from": "2024-01-01",
      "effective_to": null,
      "mapping_status": "active",
      "confidence": "0.950",
      "evidence": {
        "rule_source": "deterministic_coa_bootstrap",
        "matched_patterns": ["vat_fr_20", "supplier_invoice"]
      },
      "created_by": "deterministic",
      "mapping_version": 1,
      "created_at": "2025-05-25T10:00:00.000Z",
      "updated_at": "2025-05-25T10:00:00.000Z",
      "deleted_at": null
    },
    "relationships": {
      "workspace": {
        "data": { "type": "workspace", "id": "b1c2d3e4-0000-0000-0000-000000000001" }
      },
      "source_workspace_connector": {
        "data": null
      },
      "ledger_account": {
        "data": { "type": "ledger_account", "id": "c9d8e7f6-0000-0000-0000-000000000002" }
      },
      "tax_rate": {
        "data": { "type": "tax_rate", "id": "d1e2f3a4-0000-0000-0000-000000000003" }
      },
      "journal": {
        "data": null
      }
    }
  }
}
Source: apps/api/src/database/entities/WorkspacePostingMapping.ts ยท domain: financial-graph ยท tier: Infrastructure