Documentation Index
Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt
Use this file to discover all available pages before exploring further.
JournalEntryPostingAttempt is an append-only audit ledger that records every attempt to post a double-entry journal entry from a source document (invoice, invoice_transaction, or bank transaction). One row is written per attempt — persisted or halted — so that human-driven retries never overwrite prior halt reasons and the full posting history is preserved. It is workspace-scoped and carries actor metadata (system vs user) together with a nullable reference to the People who triggered a manual retry. The table is the authority for why a journal entry was or was not created for a given source document.
| Naming | Value |
|---|
| Object | JournalEntryPostingAttempt |
Resource type (JSON:API type) | journal_entry_posting_attempt |
| Collection / records root | — (not a records root) |
| REST base | /v1/journal-entry-posting-attempts |
| Entity class | JournalEntryPostingAttempt |
Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.
API operations
| Operation | Method & path | Status |
|---|
| List | GET /v1/journal-entry-posting-attempts | 🟡 Planned |
| Retrieve | GET /v1/journal-entry-posting-attempts/{id} | 🟡 Planned |
| Create | POST /v1/journal-entry-posting-attempts | 🟡 Planned |
| Update | PATCH /v1/journal-entry-posting-attempts/{id} | 🟡 Planned |
| Delete | DELETE /v1/journal-entry-posting-attempts/{id} | 🟡 Planned |
Data model
Attributes
| Field | Type | Required | Constraints | Allowed values | Description |
|---|
| journal_entry_posting_attempt_id | string (UUID) 🔒 system | ✅ Yes | UNIQUE | — | Public UUID identifier for this posting attempt. Generated by gen_random_uuid() on insert. This is the value exposed as the JSON:API resource id. |
| source_kind | enum (JournalEntryPostingAttemptSourceKindEnum) | ✅ Yes | Native Postgres enum: journal_entry_posting_attempt_source_kind_enum. NOT NULL. | invoice | invoice_transaction | transaction | Identifies the type of source document that triggered the posting attempt. ‘invoice’ = invoice-driven JE; ‘invoice_transaction’ = legacy per-bridge-row trigger (D9, preserved for backward compat); ‘transaction’ = D9.1 per-bank-transaction payment-settlement JE. |
| source_id | string | ✅ Yes | VARCHAR(64), NOT NULL | — | Public UUID string of the source row (invoice_id, invoice_transaction_id, or transaction_id). Stored as VARCHAR(64) rather than a typed FK so new source kinds do not require schema changes. |
| source_pk | integer | ⚪ No | INTEGER, NULLABLE | — | Internal integer PK of the source row for fast joins when the source kind is known. Nullable because legacy attempt rows pre-dating the D9.1 migration may not have this populated. |
| status | enum (JournalEntryPostingAttemptStatusEnum) | ✅ Yes | Native Postgres enum: journal_entry_posting_attempt_status_enum. NOT NULL. | persisted | halt | Outcome of this posting attempt. ‘persisted’ = a journal entry was written; ‘halt’ = posting was blocked (see reason/details). Halts never roll back the source document. |
| reason | string | ⚪ No | VARCHAR(100), NULLABLE | — | Short machine-readable reason code for a halt (e.g. ‘missing_mapping’, ‘polarity_conflict’). Free-string rather than enum because halt reasons span multiple subsystems and are expected to grow. NULL on status=persisted. |
| details | string | ⚪ No | VARCHAR(500), NULLABLE | — | Human-readable explanation of the halt reason, providing context for the operator reviewing the audit trail. NULL on status=persisted. |
| idempotency_key | string | ⚪ No | VARCHAR(160), NULLABLE | — | Idempotency key passed to the journal entry persister. Set on status=persisted; null on status=halt. Allows the persister to detect duplicate attempts and avoid double-writing JEs. |
| line_count | integer | ⚪ No | INTEGER, NULLABLE | — | Number of journal entry lines written when status=persisted. Null on status=halt. Useful for sanity-checking multi-line JEs (e.g. AR/AP lines per counterparty). |
| created | boolean | ⚪ No | BOOLEAN, NULLABLE | — | True when a new journal entry was created; false when an existing one was updated/reused via the idempotency key. Null on status=halt. |
| attempted_at | Date (timestamptz) | ✅ Yes | TIMESTAMPTZ, NOT NULL | — | Wall-clock timestamp at which the posting was attempted. Used as the DESC sort key in the latest-per-source and timeline indexes. Stored as TIMESTAMPTZ. |
| attempted_by_kind | enum (JournalEntryPostingAttemptActorKindEnum) | ✅ Yes | Native Postgres enum: journal_entry_posting_attempt_actor_kind_enum. NOT NULL. DEFAULT ‘system’. | system | user | Whether the attempt was triggered by an automated pipeline (‘system’) or by an explicit human action such as a manual retry after fixing a classification (‘user’). Defaults to ‘system’. |
| created_at | Date 🔒 system | ✅ Yes | TIMESTAMP, NOT NULL, DEFAULT now() | — | Row creation timestamp. Set by the onCreate hook; never user-editable. |
| updated_at | Date 🔒 system | ⚪ No | TIMESTAMP, NULLABLE | — | Last modification timestamp. Set by onUpdate hook. Nullable per entity declaration. |
| deleted_at | Date 🔒 system | ⚪ No | TIMESTAMP, NULLABLE | — | Soft-delete timestamp. NULL means the row is active. Used in the workspace-status composite index to keep halted-attempt dashboard queries efficient. |
Relationships
| Name | Type | Required | Description |
|---|
| workspace | to-one (ManyToOne) | ✅ Yes | The workspace this posting attempt belongs to. All queries must filter by workspace_pk for tenant isolation. References core_api.workspaces(pk). |
| journal_entry | to-one (ManyToOne, nullable) | ⚪ No | The journal entry that was written on a successful (persisted) attempt. NULL on status=halt. References core_api.journal_entries(pk). |
| attempted_by | to-one (ManyToOne, nullable) | ⚪ No | The People record of the user who triggered a manual retry when attempted_by_kind=‘user’. NULL when attempted_by_kind=‘system’. References core_api.peoples(pk). |
System-computed
- journal_entry_posting_attempt_id — generated by gen_random_uuid() on insert; never user-supplied
- created_at — set by MikroORM onCreate hook (new Date()); immutable after creation
- updated_at — set by MikroORM onUpdate hook on every flush
- deleted_at — soft-delete; set by repository-layer soft-delete helpers; not set by the application layer on normal posting flows
- attempted_by_kind defaults to JournalEntryPostingAttemptActorKindEnum.SYSTEM (‘system’) when not explicitly provided
- source_kind native enum extended via Migration20260526030000 to include ‘transaction’ for D9.1 payment-settlement attempts; ‘invoice_transaction’ retained for backward compat with pre-D9.1 rows
Example
{
"data": {
"type": "journal_entry_posting_attempt",
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"attributes": {
"source_kind": "invoice",
"source_id": "inv_7e2f3a1b-4c5d-6e7f-8a9b-0c1d2e3f4a5b",
"source_pk": 10482,
"status": "halt",
"reason": "missing_mapping",
"details": "No ledger account mapping found for category 'operating_expense' in chart of accounts version 3.",
"idempotency_key": "inv_7e2f3a1b-4c5d-6e7f-8a9b-0c1d2e3f4a5b:attempt:3",
"line_count": null,
"created": null,
"attempted_at": "2026-05-26T14:23:11.000Z",
"attempted_by_kind": "system",
"created_at": "2026-05-26T14:23:11.000Z",
"updated_at": "2026-05-26T14:23:11.000Z",
"deleted_at": null
},
"relationships": {
"workspace": {
"data": { "type": "workspace", "id": "ws_00000000-0000-0000-0000-000000000001" }
},
"journal_entry": {
"data": null
},
"attempted_by": {
"data": null
}
}
}
}
Source: apps/api/src/database/entities/JournalEntryPostingAttempt.ts · domain: financial-graph · tier: Infrastructure