feat(subscription): rename permit→subscription + monthly pricing
The "permit/lejet" feature is really a subscription. Full rename of the mutable master data, plus a recurring monthly price. - DB (migration 0004, data-preserving ALTER RENAME): permits→subscriptions, permit_credentials/_plates→subscription_*, sessions.permit_id→subscription_id. - Pricing: per-subscription priceMinor + period(monthly) + currency, with a site default (site_config.subscription_monthly_price_minor) pre-filling the form. - Server: subscription-flow.ts (SubscriptionFlow), routes/subscriptions.ts (/api/subscriptions). Web: SubscriptionManager, route, i18n (sq Abonimet/en). - The signed ledger `permitId` payload is intentionally kept — immutable hash-chained history; renaming it would break verification of past events. Deferred (wiki notes): fee collection into the ledger/shift (a shift-attributed payment), LPR/ANPR plate source, time-of-day access windows (overnight subscriber). Also carries the device-footer UI surface (api DeviceStatus, router mount, i18n devices) due to shared-file overlap with the preceding footer commit. Verified end-to-end on a fresh DB and migration on a live-DB copy (sessions preserved). Live DB migrated. Full monorepo builds clean. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -17,12 +17,12 @@ recognition **host-side on ordinary IP-camera snapshots**, replacing the dedicat
|
||||
|
||||
1. **Identity (ANPR).** snapshot → `{ plate, confidence, bbox }`. Feeds the existing
|
||||
`IdentitySource = "lpr"` ([[parking-session]]): the plate is a session/identity key and the way
|
||||
a plate-bound [[permit]] is matched.
|
||||
a plate-bound [[subscription]] is matched.
|
||||
2. **Verification (anti-fraud witness).** snapshot → vehicle attributes — at minimum
|
||||
`{ make?, model?, colour, bodyType }`, ideally a compact **visual fingerprint** (an embedding).
|
||||
This is the answer to **plate-spoofing**: *a fraudster prints a registered/paid plate and drives
|
||||
in with a different car.* Plate-reading alone can't catch that; comparing the **vehicle** seen at
|
||||
entry vs. exit (and vs. the [[permit]]'s known car) can. A plate that entered on a red hatchback
|
||||
entry vs. exit (and vs. the [[subscription]]'s known car) can. A plate that entered on a red hatchback
|
||||
but exits on a black SUV is a **reconciliation anomaly** — exactly the independent-witness role
|
||||
the [[append-only-event-chain]] flags as the unbuilt gap. See [[reconciliation]].
|
||||
|
||||
@@ -64,7 +64,7 @@ guarantee is preserved. Recorded as an explicit exception in [[standing-decision
|
||||
## Anti-fraud / threat-model fit
|
||||
|
||||
- **Plate spoofing** (the motivating case): vehicle-attribute / fingerprint mismatch entry↔exit or
|
||||
vs. a [[permit]]'s registered car → anomaly. Doesn't *block* on its own (recognition is
|
||||
vs. a [[subscription]]'s registered car → anomaly. Doesn't *block* on its own (recognition is
|
||||
probabilistic) — it **flags for [[reconciliation]]** and is captured in the signed record.
|
||||
- The recognition result and the source image both attach to the signed [[append-only-event-chain]]
|
||||
entry, so the *evidence* is tamper-evident even though recognition itself is host-side and
|
||||
|
||||
Reference in New Issue
Block a user