Files
parking_solution/wiki/concepts/validation-sponsorship.md
T
julian 5697137c52 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
2026-06-18 13:15:04 +02:00

5.3 KiB
Raw Blame History

type, tags, sources, updated, status
type tags sources updated status
concept
parking
domain
business
pricing
validation
design
parksql2017-legacy-schema
2026-06-17 open

Validation & Sponsorship — merchant comps, coupons, postpaid B2B

Builds on validation-discounts (the signed-event discount mechanism) to add the layer it leaves open: a sponsor account and postpaid B2B billing. The driving case — a nearby business with a postpaid agreement whose customers enter and exit freely, billed to the business monthly.

This page owns the sponsor/account/settlement model and the permit-vs-validation distinction. The how a discount is applied mechanics (signed event, due = max(0, fee − discounts), attribution, anti-abuse) live in validation-discounts — not duplicated here. Status: design, not built.

Why this is NOT a permit (the key distinction)

subscription Validation / sponsorship
Subject Known in advance; carries a credential (card/QR/plate) Anonymous walk-in; identified only by the ticket they were issued
When applied At entry (credential opens the lane) After entry, against an existing session — at a pay station, by a code, or by a sponsor rule
Who pays The subscriber, out-of-band A third party (merchant/sponsor), or nobody (comp)
Model fit permits + credentials New: a validation event on a session + a sponsor account

A permit bypasses tariff computation; a validation adjusts the computed fee (or zeroes it). They compose — but they are different primitives.

Two economic models (both real)

  • Prepaid — merchant buys a pool of value up front (legacy BA_Cupons: printed single-use codes worth DiscMinutes; City Center research: merchant pre-buys time tickets 15 min→all-day). Reconciliation = count used codes against the pool.
  • Postpaid (the asked-for case) — merchant signs an agreement; their customers park free or discounted; the system accrues each validation against a sponsor balance and invoices monthly (City Center: "billed for the number of tickets validated each month," verified 3-0). No money moves at the lane.

The legacy system did only prepaid coupons — the postpaid sponsor account is net-new for this project.

Modifier types (extends validation-discounts)

The discount-type enum lives in validation-discounts; legacy DiscType (smallint) and research (Amano McGann / HUB J4M, abstained-not-refuted) confirm the set: comp / percent / fixed / time-credit (legacy DiscMinutes) / rate-switch. Sponsorship adds one field to a validation: a sponsorId. Full-comp + a sponsor = the "free entry/exit, bill the business" case.

The sponsor-liability consequence (anti-fraud)

The validation is a signed event (validation-discounts, append-only-event-chain); what sponsorship adds is that free-to-the-parker is not free-to-the-ledger — it is a receivable from the sponsor. Under the threat-model model:

  • A postpaid sponsor's "enter/exit freely" still mints signed entry + exit events (and snapshots) — the audit trail is identical to a paying car; only the settlement target differs.
  • The sponsor's period liability = the sum of sponsorId-tagged validation events over the period — derivable from the chain, reconcilable like a shift and visible to reconciliation (a sponsor comping far more than plausible footfall is an anomaly).

Proposed data shape (illustrative — design only)

sponsors          id, name, contact, mode {prepaid|postpaid},
                  balance_minor (prepaid pool / postpaid accrual), billing_period, active
validations       id, session_id, sponsor_id?, type, amount_minor|minutes,
                  code?, operator_id, created_at   // append-only; one row per application
(coupons)         code, value_minutes|minor, single_use, used_at?   // prepaid pool, optional
  • A postpaid sponsor: each full-comp validation appends a row and accrues amount to the sponsor; monthly invoice = sum over the period; exit is free at the lane.
  • Free entry/exit "freely": either the sponsor issues credentials (then it's closer to a subscription — pick that path), or customers take a normal ticket and a sponsor rule / merchant code comps it at exit. The agreement wording decides which; both are expressible.

Reconciliation & settlement

  • Prepaid: pool decrements; alert at low balance; no invoice.
  • Postpaid: accrue; monthly statement per sponsor (legacy/City Center cadence ~the 10th). Statement lines trace to signed validation events → disputes resolvable against the chain.

Open

  • "Enter/exit freely" mechanism: sponsor-issued credentials (subscription-like) vs. ticket + comp-at-exit. Likely offer both; confirm the operator's actual deal shape.
  • Prepaid coupon format: printed codes (legacy) vs. QR vs. merchant web-validation portal.
  • Who may apply a validation, and the per-operator cap (a comp is a fraud vector — bound it and always sign it).
  • Invoicing: in-app statement only, or export for external billing? FX if sponsor bills in another currency (defer to tariff FX).
  • Partial-stay sponsorship (merchant covers first 2h, parker pays the rest) — time-credit or rate-switch covers it; confirm.