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:
@@ -64,6 +64,19 @@ Dingtian **input (button) pushes** → bus → `input_received` events (see [[de
|
||||
[[dingtian-relay]]). These are recorded faithfully as raw inputs, **not** as `vehicle_entry` —
|
||||
the richer entry event waits for the entry flow (ticket print + barrier command).
|
||||
|
||||
**Business-layer event types (designed, not yet implemented — see [[session-model]]).** The
|
||||
[[parking-session]] domain folds over these signed events, extending `input_received`:
|
||||
|
||||
- `vehicle_entry` / `vehicle_exit` — a stay's endpoints; `identity` carries the ticket id or plate.
|
||||
- `payment` — a settled fee at the pay station, referencing the session it pays for (amount in
|
||||
integer minor units; see [[tariff]]). Making "paid" a signed event — not a mutable row — is the
|
||||
whole point: an operator can't forge it or silently delete it.
|
||||
- `void` — a correction / lost-ticket write-off; like every other void here it is an **appended
|
||||
event, never an erasure**.
|
||||
|
||||
A session is a **projection** over this chain, never a mutable table — the same anti-fraud reason
|
||||
the chain exists. See [[parking-session]].
|
||||
|
||||
- **`lane`** is now resolved from the firing device. A `LaneMap` (`apps/server/src/lane-map.ts`)
|
||||
caches `lane_devices.id → lane`, built at startup and refreshed by the setup routes on every
|
||||
assign/unassign. Device events carry the device instance id, not a lane; the handler looks it
|
||||
@@ -91,7 +104,9 @@ host. **Proven on hardware**: a binary relay command sent directly to the device
|
||||
So the log alone does **not** detect operator/attacker fraud at the relay. That is **by design** —
|
||||
the actual control is [[reconciliation]]: compare the host's signed *commanded* opens against an
|
||||
**independent witness** of opens that physically happened (a door/loop sensor on a Dingtian input
|
||||
→ which DOES push + log; the [[lpr-camera]]; payment/Z-report). **A physical open with no matching
|
||||
signed command is the fraud signal.** Both the witness sources and the reconciliation logic are
|
||||
**NOT yet built** — this is the main open gap. Prevention (VLAN isolation so the attacker can't
|
||||
→ which DOES push + log; the [[opencv-anpr-service|vision service]]'s plate **and vehicle** read;
|
||||
payment/Z-report). **A physical open with no matching signed command is the fraud signal** — and,
|
||||
with vehicle verification, **a plate that enters/exits on a different car** is too (the
|
||||
plate-spoofing case). Both the witness sources and the reconciliation logic are **NOT yet built** —
|
||||
this is the main open gap. Prevention (VLAN isolation so the attacker can't
|
||||
reach UDP 60000) is the necessary first line; detection-via-reconciliation is the backstop.
|
||||
|
||||
Reference in New Issue
Block a user