J-12 — End-of-Day Cash Drawer Close
One-liner: Receptionist closes the till; system reconciles cash, surfaces variance, and finalises the day.
1. Purpose
End-of-shift / end-of-day, the receptionist closes the till. The Electron app reconciles total cash received vs. expected, presents a variance report, prompts for explanations, and produces a sealed EOD record (cash-in-drawer, total receipts by method, taxes, key-issuance count, dispute count). Outcome: a sealed EOD report tied to the receptionist's session, with variance documented, ready for finance review.
2. Persona Context
- Persona: Receptionist (closing); Finance (reviewer).
- Surface: Electron Desktop.
- Primary BFF:
bff-backoffice-service. - Backing services:
payments-service,folio-service,audit-service,reporting-service. - Preconditions: Drawer was opened with start float at start-of-shift; receptionist signed in; tenant timezone configured.
- Trigger: Receptionist clicks "Close drawer" or "End of day" at shift change / end of business day.
3. Entry Points
| # | Entry | Notes |
|---|---|---|
| 1 | "Close drawer" CTA | Default |
| 2 | Auto-prompt at tenant-configured EOD time | P2 |
4. Screen-by-Screen Flow
4.1 EndOfDaySummaryScreen
- Layout: Date + shift, expected cash (start float + cash receipts - cash refunds - drops), expected card totals, taxes by category, key-issuance count, dispute count, totals reconciled vs ledger.
- Components:
EodSummaryTable,Pill(status),Button("Begin close"). - Offline: Reads from SQLite; can finalise locally and queue.
- AI: None in P1; P2 — anomaly highlight (unusual variance).
- Errors: Open folios still pending -> warning with link to resolve.
- Loading: Mount <= 200 ms.
- A11y: Table semantics; status announced.
- RTL: Mirror.
- Perf: <= 200 ms.
- Telemetry:
frontend.eod.summary_viewed.
4.2 CashCountForm
- Layout: Denominations table (notes + coins) with quantity inputs; computed total; variance (vs expected) shown live; signature pad / manager PIN.
- Components:
DenominationCountTable,VarianceDisplay,SignaturePad,ManagerPinPad. - Offline: Local persist.
- AI: None.
- Errors: Negative quantity disallowed; variance > threshold requires manager approval.
- Loading: Sub-200 ms.
- A11y: Each denomination input is labelled; variance announced live.
- RTL: Mirror; numerals localised.
- Perf: Recompute <= 100 ms.
- Telemetry:
frontend.eod.cash_counted { variance }.
4.3 VarianceExplanationForm
- Layout: Free-text explanation, photo evidence (optional), responsibility flag (mistake / theft suspected / other), manager sign-off.
- Components:
Form,PhotoUpload,ManagerPinPad. - Offline: Editable; queued.
- AI: None.
- Errors: Required when variance != 0.
- Loading: Sub-200 ms.
- A11y: Field labels; manager sign-off announced.
- RTL: Mirror.
- Perf: Submit <= 500 ms.
- Telemetry:
frontend.eod.variance_explained { reason }.
4.4 EodReportPrintAndSeal
- Layout: Final EOD report preview; "Print" + "Email to manager" + "Seal day" actions; sealed pill on success.
- Components:
ReportPreview,Button(variants). - Offline: Print local; email queued; seal recorded local with cryptographic hash.
- AI: None.
- Errors: Print failure -> retry; seal already done -> banner.
- Loading: Print <= 5 s.
- A11y: Sealed pill announced; report content navigable.
- RTL: Mirror.
- Perf: Total flow <= 5 min wall-clock.
- Telemetry:
frontend.eod.sealed { dayId }.
5. State Machine
6. Data Requirements
6.1 Server state
GET /api/v1/eod/summary?day=...&sessionId=...POST /api/v1/eod/cash-count(idempotent)POST /api/v1/eod/variance(idempotent)POST /api/v1/eod/seal(idempotent; returns sealed report id + hash)
6.2 Local persistence
- SQLite
eod_sessions_local,eod_cash_counts_local,eod_variances_local,outbox,audit_local. - Sealed report stored locally with cryptographic hash.
6.3 Idempotency
- All mutations carry
X-Idempotency-Key.
7. AI Behavior
n/a in P1; P2 — variance anomaly highlight.
8. Offline Behavior
- Reads from SQLite snapshot.
- Cash count, variance, manager approval all local.
- Report seal local; cryptographic hash; reconciled on reconnect.
9. Error States
| Error | Trigger | UX shown | Recovery | Telemetry |
|---|---|---|---|---|
OPEN_FOLIOS_AT_EOD | Folios still pending | Warning with link to resolve | User resolves | frontend.eod.open_folios { count } |
VARIANCE_OVER_THRESHOLD | Variance > tenant threshold | Manager approval required | Manager approves | frontend.eod.variance_over_threshold |
MANAGER_APPROVAL_FAILED | Wrong PIN / timeout | Inline error / banner | Retry | frontend.eod.approval_failed |
PRINT_FAILED | Printer error | Banner with retry | Retry / email instead | frontend.eod.print_failed |
EOD_ALREADY_SEALED | Replay attempt | Banner; show existing sealed report | n/a | frontend.eod.already_sealed |
10. E2E Test Gates
- Composite gate
G-DESK-FIN-1: summary -> cash count -> variance (zero & non-zero) -> seal -> report. - Variance > threshold -> manager approval path.
- Offline path -> reconnect -> seal reconciled.
11. Performance Requirements
| Metric | Target |
|---|---|
| Summary mount | <= 200 ms |
| Variance recompute | <= 100 ms |
| Seal RTT (online) | <= 1 s p95 |
| Total flow | <= 5 min wall-clock |
12. Accessibility Requirements
- All keyboard-completable.
- Variance announcements via
aria-live. - Manager PIN pad accessible.
13. Telemetry
Frontend events
frontend.eod.summary_viewedfrontend.eod.cash_counted { variance }frontend.eod.variance_explained { reason }frontend.eod.sealed { dayId }
Domain events emitted
melmastoon.eod.summary.generated.v1melmastoon.eod.cash.counted.v1melmastoon.eod.variance.recorded.v1melmastoon.eod.sealed.v1melmastoon.audit.recorded.v1
14. Success Criteria
- Sealed EOD report has cryptographic hash; reconciles to ledger.
- Variance documented and approved when non-zero.
- Open folios at EOD surfaced and resolvable.
- Reports printable + emailable; offline path proven.
- Audit log captures who-did-what.