Period Lock — GoBD Immutability Service
NestJS Domain Service enforcing financial period immutability for GoBD compliance. Part of the Commerce Bounded Context.
Purpose
The PeriodLockService prevents mutation of financial records (FinancialLedger, Invoice, TaxLedgerEntry) after the user closes a reporting period or exports it to DATEV.
Lock Types
| Type | Trigger | Unlockable? |
|---|---|---|
EXPORT | Automatically created when the system generates a DATEV export for a period | No — irreversible |
MANUAL | Manually triggered by an operator (e.g., month-end close) | Only by manager with audit trail |
API Surface (Hasura Actions)
lockPeriod
graphql
mutation LockPeriod($tenantId: uuid!, $periodStart: date!, $periodEnd: date!, $lockType: String!) {
lockPeriod(tenant_id: $tenantId, period_start: $periodStart, period_end: $periodEnd, lock_type: $lockType) {
id
locked_at
}
}unlockPeriod
graphql
mutation UnlockPeriod($tenantId: uuid!, $lockId: uuid!) {
unlockPeriod(tenant_id: $tenantId, lock_id: $lockId) {
success
}
}(Note: Requires MANAGER role with strict audit logging for GoBD compliance. Admins can only unlock MANUAL lock types. EXPORT locks remain immutable).
isLocked (used internally as pre-mutation guard)
Called as a Hasura Action Permission or Pre-Insert/Update hook on commerce.invoices, commerce.financial_ledgers, and commerce.tax_ledger_entries.
Validation Logic
validateMutation(tenantId, entityDate):
locks = SELECT * FROM commerce.ledger_period_locks
WHERE tenant_id = tenantId
AND period_start <= entityDate
AND period_end >= entityDate
IF locks.length > 0:
THROW PeriodLockedException("Period is locked since {lock.locked_at}")Integration Points
| Caller | When | Purpose |
|---|---|---|
| Invoice mutation (Hasura ET) | Before any UPDATE on commerce.invoices | Block direct edits on locked periods |
| DATEV Export Service | After the system generates an export | Auto-create EXPORT lock for the exported period |
| Workspace UI | Manual month-end close | User-initiated MANUAL lock |
| Storno Workflow | Before cancelling an invoice | Validate the invoice's period is not locked |