# FamilyDashboard coin ledger explainability and corrections

Use this when the user asks for child-facing coin explainability, a coin ledger page, or admin correction of past coin entries.

## Principles

- Keep balances ledger-derived: `posted - reserved = available`.
- Default correction path: do **not** edit, delete, or overwrite old `CoinTransaction` rows to correct history; create append-only counter/adjustment rows with clear comments.
- Exception: if the user explicitly asks for coin-history maintenance/reset, Admin may expose protected destructive tools: multi-select hard-delete with confirmation `DELETE_COIN_BUCHUNGEN`, and per-child full reset with confirmation `COINS_AUF_NULL` that deletes that child’s `CoinTransaction` rows (and stale `BenefitRedemption` rows) so the child starts at 0. Back up production DB before deploying/testing destructive flows.
- Public child-facing coin views are read-only; admin actions stay in the Admin portal.

## Public `/coins` page pattern

- Make the sidebar coin indicator a real navigation control to `/coins` when children need explainability.
- Show one card/column per child:
  - current available coins
  - posted/booked total
  - reserved total
  - transaction list with date/time, type, amount/reserved amount, and comment
- Use child-friendly labels:
  - earned → `Bonus`
  - penalty → `Pflicht-Abzug`
  - penalty_reversal → `Nachträglich erledigt`
  - reserve → `Benefit reserviert`
  - capture → `Benefit erhalten`
  - release → `Benefit storniert`
  - undo → `Bonus rückgängig`
  - manual → `Korrektur`
- Keep this page read-only: no admin forms, no PIN, no edit buttons.

## Admin correction endpoint pattern

If not already present, add or harden:

```text
POST /api/admin/coins/manual
```

Payload:

```json
{
  "child_id": 1,
  "amount": 2,
  "comment": "Korrektur: Aufgabe war erledigt",
  "reference_transaction_id": 123,
  "idempotency_key": "ui-manual-..."
}
```

Validation:

- admin session required
- `child_id` must exist
- `amount` must be non-zero
- `comment` is always required and non-empty, for both additions and deductions
- optional `reference_transaction_id` must exist and belong to the same child
- use `idempotency_key` to avoid duplicate postings

Implementation:

- create a new `CoinTransaction(transaction_type=manual, amount=..., reserved_amount=0, comment=...)`
- if a reference is supplied, append a trace such as `(Korrektur zu Buchung #ID)` to the comment
- never modify the referenced transaction

## Admin UI pattern

- In the Admin coin ledger, each transaction can offer `Korrektur buchen`.
- Prefill the correction form with the counter amount:
  - `-(tx.amount || tx.reserved_amount || 0)`
- Prefill comment with `Korrektur: ` but still require the admin to finish the reason.
- Store `reference_transaction_id` in the manual booking payload.
- On success invalidate/refetch admin ledger, dashboard, benefits, and any public coin ledger query keys.

## Verification

- Backend tests should prove:
  - missing comment returns validation error
  - positive and negative manual bookings update `posted`/`available`
  - reference correction creates a new transaction and leaves the old one unchanged
- Frontend smoke:
  - sidebar coin box opens `/coins`
  - both child columns render
  - admin can book `+2` and `-1` with comments
  - correction button prefills counter-amount and reference
  - public `/coins` shows the correction after reload
