--- 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 [[subscription]] 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. - [[subscription]] 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]].