Skip to content

PRD: Shift reports (X/Z)

ModuleReports (CORE-11)PRD IDPRD-SHF-001
StatusIn-progressOwnerReports squad
Date2026-04-22Versionv0.1
Packages@nx/sale · @nx/core · @nx/financeURDSHF

TL;DR

Lets a cashier read shift totals and reconcile the cash drawer without leaving the counter: an X report for a live, repeatable mid-shift snapshot and a Z report for the final, locked close-shift figures. Each report pairs cash reconciliation (opening float, cash sales, pay-in/out, expected vs. actual, discrepancy) with a sales summary, so every shift closes against a verifiable number instead of a guess.

1. Context & Problem

POS cashiers run shifts against an open PosSession. Today a session tracks cash movements but produces no report, so there is no way to read shift totals or reconcile the drawer at the counter: a cashier cannot see expected-vs-actual cash, cannot pull an interim mid-shift summary, and has no locked snapshot to hand off at close. Without that, shift handovers rely on manual counting and the owner has no auditable record of what each shift took in - a blocker for cash-honest operations at the HKD/SME scale KICKO targets.

This increment delivers the two reports a cashier expects against an open session - an interim X report and a closing Z report - backed by a persisted close-shift snapshot, on top of the existing POS session lifecycle and cash-movement tracking.

2. Goals & Non-Goals

Goals

  • An X report (interim): a live in-shift snapshot generated from the current open session, repeatable any number of times.
  • A Z report (closing): the final close-shift report, read once per session and backed by a persisted PosSessionReport snapshot.
  • Cash reconciliation: opening float, cash sales, pay-in / pay-out, expected vs. actual counted cash, and discrepancy, with a close-recount count on the session.
  • A sales summary on the report: gross, discount, tax, net, and order count.
  • Merchant + sale-channel scoping and session listing with pagination.

Non-Goals

  • Daily / product / category sales reports - owned by the SLS feature (URD-SLS).
  • Profit & loss, inventory valuation, customer analytics, export, and scheduled reports - ADV, Planned (URD-ADV).
  • Payment-method and category breakdowns on the shift report (Should-level URD-SHF-005..006).
  • Multi-employee shifts and PIN step-up on report access.

3. Success Metrics

MetricTarget / signal
Reconciliation coverage100% of closed sessions produce exactly one Z report
Cash accuracyDiscrepancy = counted cash − (opening float + cash sales − pay-outs); surfaced on every close
Interim usabilityX report is repeatable mid-shift with no session mutation
Scoping correctnessZero cross-merchant figures returned on any report

4. Personas & Use Cases

PersonaGoal in this feature
CashierPull an X report mid-shift; close the shift to produce the Z report with a counted-cash reconciliation
ManagerReview any shift's Z report for their merchant
OwnerSee shift reconciliation across their merchants

Core scenarios: open a POS session → pull an X report mid-shift (repeatable) → at close, count actual cash → the system computes expected vs. actual and locks a Z report snapshot, one per session.

5. User Stories

  • As a cashier, I want to pull an X report from my open session, so I can check interim cash and sales totals without closing the shift.
  • As a cashier, I want the X report to be repeatable, so I can re-check totals as the shift progresses.
  • As a cashier, I want to close my session with a counted-cash recount, so the Z report shows expected vs. actual and the discrepancy.
  • As a manager, I want exactly one locked Z report per session, so closed-shift figures can't drift.
  • As an owner, I want shift reports scoped to my merchant, so no other merchant's figures leak in.

6. Functional Requirements

#RequirementURD ref
FR-1X report (interim): generate a live snapshot from the current open session via POST …/x-report; repeatable, no session mutationURD-SHF-001
FR-2Z report (closing): aggregated close-shift report read once per session via GET …/z-report, backed by the persisted PosSessionReport snapshotURD-SHF-002
FR-3Cash reconciliation: opening float, cash sales, pay-in / pay-out, expected vs. actual counted cash, discrepancy, plus a close-recount count on the sessionURD-SHF-003
FR-4Sales summary on the report: gross, discount, tax, net, order countURD-SHF-004
FR-5Reports scoped per merchant and sale channel; session listing with pagination and filtersURD-SHF-001..002
FR-6Authorization subjects PosSession.getXReport / PosSession.getZReport (READ action) gate the two report routesURD-SHF-001..002

Full requirement text and acceptance criteria live in the Reports URD. This PRD references them rather than restating them. Payment-method and category breakdowns (URD-SHF-005..006, Should) are out of this increment - SHF remains In-progress.

7. Non-Functional Requirements

AreaRequirement
Data integrityThe Z report is a one-per-session terminal snapshot; once locked at close it does not change
Read-onlyReports aggregate over cash movements and completed orders; the X report never mutates the session
Tenancy & authzAll operations scoped per merchant (x-merchant-id) and sale channel; report routes gated by the PosSession.getXReport / getZReport READ subjects
PrecisionCash and monetary math uses float(value, 4)
Performance / scaleSession listing is paginated; report aggregation runs over a single session's movements
i18nUser-facing labels/statuses are bilingual ({ en, vi })

8. UX & Flows

Key screens (in apps/client): the shift/session view, the X-report action, the close-shift recount, and the Z-report view. The reports are served by the @nx/sale shift controller.

9. Data & Domain

EntityRole
PosSessionThe open shift - lifecycle (open/close), cash-movement tracking, close-recount count
PosSessionReportThe persisted close-shift (Z) snapshot - cash reconciliation + sales summary, one per session
FinanceTransactionCash movements aggregated by the report; the session reference (pos_session_id) is intentionally not held here

Conceptual only - full schema and invariants in the sale domain model.

10. Dependencies & Assumptions

Depends on

  • POS session lifecycle & cash-movement tracking (@nx/sale shift service) - the X/Z reports aggregate an open or just-closed session.
  • Completed orders (Orders) - the sales summary aggregates completed orders in the session.
  • Cash / payment movements (@nx/finance) - pay-in/out and cash sales feed the reconciliation.
  • @nx/core sale schemas - host the PosSession / PosSessionReport tables.

Assumptions

  • A cashier opens a session with an opening float before transacting.
  • Each session closes exactly once, producing exactly one Z report.

11. Risks & Open Questions

Risk / questionMitigation / status
Cash reconciliation diverging from the finance ledgerReport aggregates cash movements directly; pos_session_id removed from FinanceTransaction so the report - not the ledger - owns the session view
Double Z report per sessionZ report is read once per session against a persisted snapshot; terminal by design
Payment-method / category breakdowns expected by some merchantsOut of this increment (URD-SHF-005..006); SHF stays In-progress until delivered
Multi-employee shifts and PIN step-up on report accessOut of scope here; tracked separately

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - see URD feature catalog
RolloutAll merchants; no feature flag
MigrationAdds PosSession / PosSessionReport tables; removes pos_session_id from FinanceTransaction
Launch criteriaX report repeatable on an open session; exactly one Z report per closed session; cash reconciliation and sales summary verified against counted cash
MonitoringZ reports per closed session (expect 1:1), reconciliation discrepancy distribution, report request error rate

13. FAQ

What is the difference between an X report and a Z report? The X report is an interim, repeatable mid-shift snapshot pulled while the session is open; the Z report is the final close-shift report, produced once per session and locked.

Does pulling an X report change anything? No - it is read-only and repeatable; it does not mutate the session or finance records.

Can a session have more than one Z report? No - exactly one Z report is produced per session at close, backed by a persisted snapshot.

Why isn't the session referenced on the finance transaction? The report aggregates cash movements directly, so the session reference (pos_session_id) is not held on FinanceTransaction; the report owns the session view.

Do shift reports include payment-method or category breakdowns? Not in this increment - those are Should-level (URD-SHF-005..006) and remain open.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.