Files
parking_solution/wiki/concepts/shift.md
T
julian 8a8e74561d wiki: design the business layer (session, tariff, permit, vision, shift, ops)
Pivot from the hardware/integrity layer to the parking operation. All
wiki-only; no code yet. Core principle throughout: business entities are
projections over the signed append-only event log, never mutable tables.

New concepts: parking-session, tariff (composable/versioned, FX-ready),
shift (manned-only Z-report), capacity-occupancy, validation-discounts,
reporting-analytics, clock-integrity, ticket-encoding, anti-passback.
New entities: permit, opencv-anpr-service, blocklist.
Decisions: session-model, vision-service (host-side ANPR + vehicle
verification; scoped AGPL exception for the isolated service).

Updates: append-only-event-chain (new event types + vision witness),
local-jwt-auth (drop 8h expiry -> until logout; code change pending),
lpr-camera (host-side recognition supersedes edge-AI), standing-decisions
(AGPL exception), open-questions (+FX, +pay-station money corners, backup).

Deferred + flagged: intercom/help-call, receipts/refunds/change, FX engine,
lane topology (#1).
2026-06-15 17:41:38 +02:00

4.2 KiB

type, tags, sources, updated, status
type tags sources updated status
concept
parking
domain
business
shifts
anti-fraud
2026-06-15 open

Shift (manned mode) & the Z-Report

A shift is one operator's accountability period at a manned booth: from the moment they take over to the moment they hand over, however long that is. At the end, the system signs and prints a Z-report — the cash and POS totals taken during the shift. (Decisions 2026-06-15.)

Shifts exist ONLY in manned mode

A shift is fundamentally a human accountability boundary — "this person was responsible for the takings from here to here." In the autonomous-direction system there is no operator and no shift; what replaces it is the pay station's cash-collection cycle (who emptied the vault, when, how much vs. what the signed log expected) plus ongoing reconciliation — a separate concept, not a shift. So shifts are scoped to manned operation; don't force one model across both.

A shift is NOT time-based

It is delimited by explicit operator action, never by a clock:

  • Booth reality: relief comes late, doesn't show, or one operator is forced to work two shifts in a row. A fixed 8h boundary (or an 8h token expiry) would be wrong — it could strand an active operator. So the local-jwt-auth (valid until logout).
  • Start Shift / End Shift are explicit, and independent of login. One login can span many shifts; a back-to-back double is simply End Shift → Start Shift again, no re-login. The operator (the same person or the next) marks the boundary.
login ——————————————————————————————————————————————→ (until logout)
   [Start shift] … takings … [End shift→sign+print Z] [Start shift] … [End shift] …

What End Shift does

  1. Determine the shift's payment set: the signed payment events (parking-session, append-only-event-chain) between this shift's start mark and now.
  2. Sum by tender: cashTotal, and cardTotal from the POS/terminal if a POS is configured (the card line is omitted when there's no terminal).
  3. Append a signed shift_z_report event (type already in packages/shared): { operator, startedAt, endedAt, cashTotal, cardTotal?, paymentCount, eventRange, prevZHash } — chained to the prior Z so a missing/out-of-order Z-report is itself visible.
  4. Print the Z-report (cash total, POS total if any, counts, shift window, operator) on the booth printer.

That's the whole human-side requirement: print the cash and the POS (if any). No blind count, no variance gate, no manager override.

Where the fraud control actually lives

Deliberately not in a shift-close ceremony. Because every payment is a signed event in the append-only chain, the printed cash figure is the system's tamper-evident truth. A manager reconciles the signed Z-report against the actual drawer and the bank/POS batch later — that's reconciliation, the real control (deferred). The tradeoff vs. a heavier control is purely when a skim is caught (after the fact, by a human), not whether.

Optional enhancement (not building now): blind cash count. Have the operator enter the counted cash before the system reveals the expected figure, and record the variance into the shift_z_report. Blindness removes the operator's ability to back-fill their declaration to match expectation, catching a skim at close rather than later. Explicitly out of scope per 2026-06-15; documented as a clean add-on if ever wanted.

Open

  • Shift ↔ session boundary: a vehicle may enter under one shift and pay under another — the Z-report sums by payment time (when cash/card was taken), which is the operator who handled the money. Confirm that's the intended accountability (vs. by entry).
  • Mid-shift report / X-report (read-only "so far" total without closing) — add if booths want it; the sum is the same projection.
  • Multiple lanes/booths — whether a shift is per-operator, per-booth, or per-site (relates to open-questions #1 lane topology).