# Account

## Description

Account is the fundamental GL account entity in the ERP system — every journal entry, sub-ledger posting, and financial report ultimately references one or more GL accounts. Each account carries a structured numeric code, a descriptive name, an account type (ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE), an account classification describing its operational role (REGULAR, RECEIVABLE, PAYABLE, BANK_CASH, FIXED_ASSET, RETAINED_EARNINGS, NON_POSTING), optional currency restriction, reconciliation flag, default tax code reference, and tags.

Accounts are always scoped to a parent CoA and may optionally belong to an account group. The account follows a lifecycle state machine (DRAFT -> ACTIVE <-> INACTIVE) that governs posting eligibility, mutability, and deletion.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Draft: createAccount
    Draft --> Active: activateAccount
    Active --> Inactive: deactivateAccount
    Inactive --> Active: reactivateAccount
    Draft --> [*]: deleteAccount
```

| Operation | From | To | Command |
|-----------|------|----|---------|
| activate | DRAFT | ACTIVE | [activateAccount](../commands/ActivateAccount.md) |
| deactivate | ACTIVE | INACTIVE | [deactivateAccount](../commands/DeactivateAccount.md) |
| reactivate | INACTIVE | ACTIVE | [reactivateAccount](../commands/ReactivateAccount.md) |

### Command Definitions

- [createAccount](../commands/CreateAccount.md) - Create a new GL account in DRAFT status within a CoA
- [updateAccount](../commands/UpdateAccount.md) - Update mutable fields of an existing account (structural fields immutable after posting)
- [activateAccount](../commands/ActivateAccount.md) - Transition account from DRAFT to ACTIVE
- [deactivateAccount](../commands/DeactivateAccount.md) - Transition account from ACTIVE to INACTIVE with optional successor mapping
- [reactivateAccount](../commands/ReactivateAccount.md) - Transition account from INACTIVE to ACTIVE
- [deleteAccount](../commands/DeleteAccount.md) - Permanently delete a DRAFT account with no posted transactions

### Query Definitions

- [GetAccount](../queries/GetAccount.md) - Retrieve an account by id or by code within a CoA
- [ListAccounts](../queries/ListAccounts.md) - List accounts within a CoA with optional filters (type, classification, group, tags, status)

### Models

- Account

### Invariants

- Accounts can only be created in DRAFT status
- Account creation and update require the parent CoA to be in DRAFT or ACTIVE status; operations on accounts under an ARCHIVED CoA are rejected
- Account deactivation and reactivation require the parent CoA to be in ACTIVE status; the DRAFT CoA case is unreachable because these operations act on ACTIVE or INACTIVE accounts, which can only exist under an ACTIVE CoA (since account activation requires an ACTIVE CoA). Operations on accounts under an ARCHIVED CoA are rejected
- Account deletion requires the parent CoA to be in DRAFT or ACTIVE status; operations on accounts under an ARCHIVED CoA are rejected
- Account activation (activateAccount) specifically requires the parent CoA to be in ACTIVE status — not DRAFT. This ensures that all accounts under a DRAFT CoA remain in DRAFT status, which is a prerequisite for safe cascade deletion of DRAFT CoAs
- Account code is required, must be a structured numeric identifier, and must be unique within its CoA
- Account code is immutable after the account has posted transactions
- Account name is required and must be non-empty
- Account type must be one of ASSET, LIABILITY, EQUITY, REVENUE, or EXPENSE
- Account classification must be one of REGULAR, RECEIVABLE, PAYABLE, BANK_CASH, FIXED_ASSET, RETAINED_EARNINGS, or NON_POSTING
- Account classification defaults to REGULAR when not explicitly set
- Classification must be compatible with account type: RECEIVABLE, BANK_CASH, and FIXED_ASSET require type ASSET; PAYABLE requires type LIABILITY; RETAINED_EARNINGS requires type EQUITY; REGULAR and NON_POSTING are allowed with any type
- Only one account per CoA may carry the RETAINED_EARNINGS classification
- Reconciliation flag defaults to false for REGULAR, FIXED_ASSET, RETAINED_EARNINGS, and NON_POSTING classifications
- Accounts with RECEIVABLE, PAYABLE, or BANK_CASH classification must have reconciliation enabled (enforced invariant, not a default); attempting to set reconciliation to false for these classifications is rejected
- RECEIVABLE and PAYABLE accounts block direct manual journal postings (control account constraint stored here, enforced by GL/posting layer)
- NON_POSTING accounts are excluded from journal entry target selection (postability attribute only, not a hierarchy mechanism)
- Currency restriction, when provided, must reference a valid currency from the primitives module
- An account with currency restriction only accepts postings in that currency
- Once an account has posted transactions, structural fields (code, type, classification, currency restriction) become immutable
- Only ACTIVE accounts can receive new journal postings
- Only DRAFT accounts with no posted transactions can be deleted; ACTIVE and INACTIVE accounts cannot be deleted regardless of transaction history
- Deleting a DRAFT account that has posted transactions is rejected to preserve ledger integrity
- Default tax code is optional free-text (future migration to validated reference when tax-configuration module is implemented)
- Tags are optional; when provided, stored as a comma-separated string of labels (e.g. `"tag1,tag2"`)
- An account can optionally belong to an account group within the same CoA; assigning an account to a group in a different CoA fails validation
- When an account belongs to a group with a defined number range, the account code must always fall within that range — this invariant is enforced on creation, on group reassignment, and on code changes while the account remains in the same group
- Deactivation exposes a pre-deactivation hook for the general-ledger module to block the transition when open or unreconciled balances exist
- A successor account can optionally be mapped during deactivation; the successor must be in ACTIVE status
- Reactivating an account clears any previously mapped successor account
- All account lifecycle operations (create, update, activate, deactivate, reactivate, delete) emit audit events via the audit module recording the acting user, timestamp, CoA reference, account code, classification, and relevant field values

### Relationships

- **References ChartOfAccounts**: Each account belongs to a ChartOfAccounts via chartOfAccountsId
- **References AccountGroup**: Each account optionally references an AccountGroup via accountGroupId
- **References Currency**: Each account optionally references a Currency from the primitives module via currencyRestriction
- **References Account (successor)**: Each account optionally references another Account as successor via successorAccountId
- **Referenced By Downstream Modules**: Accounts are referenced by general-ledger, AP, AR, and fixed-asset modules
