# JournalEntry

## Description

JournalEntry is the accounting document header for the financial-accounting module. It owns the journal lifecycle, company scope, accounting period, entry date, reference number, description, and optional structured source document reference. DRAFT journal entries use JournalLine records as prepared lines. Posting validates the prepared lines, transitions the JournalEntry to POSTED, and appends immutable AccountingLedger facts used for balances, reporting, and traceability. Journal entries follow a lifecycle of DRAFT to POSTED, with posted entries eligible for reversal via a mirror entry that produces a REVERSED status on the original.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Draft: createJournalEntry
    Draft --> Draft: updateJournalEntry
    Draft --> Posted: postJournalEntry
    Posted --> Reversed: reverseJournalEntry
    Draft --> [*]: deleteJournalEntry
```

| Operation | From | To | Command |
|-----------|------|----|---------|
| post | DRAFT | POSTED | [postJournalEntry](../command/PostJournalEntry.md) |
| reverse | POSTED | REVERSED | [reverseJournalEntry](../command/ReverseJournalEntry.md) |

### Command Definitions

- [createJournalEntry](../command/CreateJournalEntry.md) - Create a new journal entry in DRAFT status with initial prepared lines
- [updateJournalEntry](../command/UpdateJournalEntry.md) - Update mutable header fields and replace prepared lines of a DRAFT journal entry
- [deleteJournalEntry](../command/DeleteJournalEntry.md) - Delete a DRAFT journal entry and all associated lines
- [postJournalEntry](../command/PostJournalEntry.md) - Post a balanced DRAFT journal entry to the general ledger
- [reverseJournalEntry](../command/ReverseJournalEntry.md) - Reverse a posted journal entry via a mirror entry

### Query Definitions

- [GetJournalEntry](../query/GetJournalEntry.md) - Retrieve a journal entry by id with all lines
- [ListJournalEntries](../query/ListJournalEntries.md) - List journal entries with filters (period, status, date range)

### Models

- JournalEntry
- JournalLine
- AccountingLedger

### Invariants

- Journal entries can only be created in DRAFT status
- Journal entry requires a valid entry date
- Journal entry requires a reference number that is unique within the company scope
- Journal entry must reference a valid companyId
- Journal entry must reference a valid accounting period; the period must be in OPEN status for posting
- Journal entry description is optional and can be updated while in DRAFT status
- Source document type and source document ID are optional and can be set on creation or update in DRAFT status
- A journal entry must have at least two journal lines before it can be posted
- Total debits must equal total credits for posting to succeed
- Posting creates posted-only AccountingLedger facts from the prepared JournalLine records
- Posted journal entries cannot be modified (no field updates, no line additions or removals)
- Posted journal entries cannot be deleted; only reversal is permitted
- DRAFT journal entries can be deleted; deletion removes all associated journal lines
- Reversing a posted entry creates a new journal entry with all debit/credit amounts inverted
- The reversal entry references the original entry and is automatically posted
- The original entry status transitions from POSTED to REVERSED upon successful reversal
- Reversing an entry that is already REVERSED fails
- The reversal entry must target a period that is in OPEN status
- Entry date cannot be changed after the entry is posted
- Posting a journal entry to a CLOSED, PERMANENTLY_CLOSED, or NEVER_OPENED period is rejected

### Relationships

- **References Company**: Each journal entry is scoped to a Company via companyId (organization module)
- **References AccountingPeriod**: Each journal entry references an AccountingPeriod via accountingPeriodId
- **Has Many JournalLine**: A journal entry contains one or more journal lines
- **Has Many AccountingLedger**: Posting creates immutable ledger facts for the entry
- **References JournalEntry (reversal)**: A reversal entry references the original via reversalOfId
