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).
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
---
|
||||
type: decision
|
||||
tags: [parking, decisions, domain, business]
|
||||
sources: []
|
||||
updated: 2026-06-15
|
||||
status: open
|
||||
---
|
||||
|
||||
# Decision: Parking Session Model
|
||||
|
||||
The starting decision for the **business layer**, taken 2026-06-15 as the project pivots from the
|
||||
(now hardware-verified) device/integrity layer to the parking *operation*.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **A session is a projection over the signed event log, not a mutable table.** The
|
||||
[[append-only-event-chain]] `events` table stays the only source of truth; a
|
||||
[[parking-session]] is folded from `vehicle_entry` / `vehicle_exit` / `payment` / `void`
|
||||
events. A cache table is allowed for query speed but is always rebuildable and never
|
||||
authoritative.
|
||||
2. **Transient-first, mixed site.** Model the casual pay-for-duration session + [[tariff]] first;
|
||||
layer [[permit]] holders on top as a second identity source that short-circuits payment
|
||||
([[entry-exit-readers]]).
|
||||
3. **Pay-on-foot / pay station.** Payment is **decoupled from exit**: the customer pays at a
|
||||
central station; the exit lane only validates the session is paid and within the walk-back
|
||||
grace window before opening ([[parking-session]] lifecycle). Matches the
|
||||
[[autonomous-direction|unmanned]] roadmap and sharpens [[open-questions]] #3 toward an unmanned
|
||||
pay station (PCI scope still kept out of the app via a certified terminal).
|
||||
4. **New signed event types:** `vehicle_entry`, `vehicle_exit`, `payment`, `void` — extend the
|
||||
existing `input_received`. Recorded in [[append-only-event-chain]].
|
||||
|
||||
## Why (rejected alternative)
|
||||
|
||||
A **mutable `sessions` table** carrying `amountOwed` / `paidStatus` as the source of truth was
|
||||
rejected: it reopens the exact fraud vector the system exists to close ([[threat-model]] — the
|
||||
insider edits the row, marks it paid, pockets the cash). Making "paid" a **signed `payment`
|
||||
event** means it can't be forged and can't be silently deleted (a deletion breaks the chain). The
|
||||
projection approach costs a fold/cache but keeps the anti-fraud guarantee intact end-to-end.
|
||||
|
||||
## What this unblocks
|
||||
|
||||
Closes the dangling thread from [[device-input-flow]] ("the entry flow itself is the next
|
||||
build"): `input_received` → signed `vehicle_entry` → ticket print → `pulseOpen`, then the
|
||||
pay-station and exit-validation flows. Schema (`packages/db`) + shared types follow the
|
||||
[[parking-session]] + [[tariff]] design pages.
|
||||
|
||||
## Open / next
|
||||
|
||||
- Rate card, currency, grace windows, caps — operator/procurement input ([[tariff]]).
|
||||
- Tariff versioning (effective-dated) for historical repricing.
|
||||
- [[permit]] data model + lapsed-mid-stay handling.
|
||||
- Wire payment capture to a concrete pay-station terminal ([[open-questions]] #3) — kept abstract
|
||||
(payment = an independent signed event referencing a session) until procurement settles.
|
||||
- Reconciliation of sessions/payments against an external authority remains [[open-questions]] #4
|
||||
+ the unbuilt witness/reconciliation gap in [[append-only-event-chain]].
|
||||
Reference in New Issue
Block a user