docs(wiki): industry survey of parking tariff systems + session log
Build desktop / desktop (push) Successful in 4m14s
CI / check (push) Successful in 43s
Build & push images / images (push) Successful in 2m49s

New reference page tariff-industry-survey.md (2026-07 web research):
field taxonomy — per-started-increment hourly (per-minute tried and
rolled back in practice), degressive ladders, day caps, up-to matrices,
day tickets, evening/overnight packages, event rates, early bird
(entry-time-conditioned), day/night + weekend/holiday/seasonal windows,
category pricing, contracts, merchant validations (amount/percent/
time-credit/re-rate), SFpark-style dynamic pricing. Coverage map: our
engine expresses everything a staffed single lot advertises; real gaps =
early bird (the pick-table-by-entry-time future design, same mechanism
as weekend menus) and validation overlays; anti-features = per-minute
billing + dynamic pricing. Indexed + logged.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-07-05 16:37:53 +02:00
parent 4f902d869e
commit 14638c2e13
3 changed files with 156 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
---
type: reference
tags: [parking, domain, business, pricing, research]
sources: []
updated: 2026-07-05
---
# Tariff systems in the parking industry — survey (2026-07)
Web research (2026-07-05) into the tariff/pricing structures the parking industry actually uses,
to sanity-check the [[tariff]] engine's coverage and rank the gaps. Sources at the end; legacy
cross-check in [[parksql2017-legacy-schema]].
## The taxonomy — what operators run in the field
**1. Time-based accrual (the bread and butter everywhere)**
- **Linear hourly** — €/hr **per started hour**; billing increments of 30/60 min dominate.
**Per-minute billing is rejected in practice**: garages that tried it (e.g. Leuven) rolled it
back within months — customers couldn't predict the price and complaints rose. Vindicates our
`incrementMin` default of 60.
- **Degressive ladder** — marginal price FALLS with duration (€2.50 first hour, €0.50/30min
after): the standard shape for hospitals, city-centre garages, anywhere encouraging longer
stays. Exactly our V1/V2 `blocks`.
- **Progressive ladder** — marginal price RISES with duration: rarer, used to force turnover
(short-stay curbside). Same `blocks` primitive, ascending.
- **Daily / weekly caps** — a ceiling regardless of accrual ("day max €7"). Universal in
commercial garages. Our `dailyCapMinor`.
- **Free grace period** — 15–30 min free at entry (airports: pickup/dropoff support). Our
`gracePeriodEntryMin`.
**2. Whole-stay prices (not accrual)**
- **Flat rate / day ticket** — one price for the day (Delft inner city: €29/day). Our stepped
("up-to") table with one row, or a flat V1.
- **Up-to matrices** — "stay up to N hours costs TOTAL" tables: the region's habit (legacy
ParkSQL confirms). Our `steps`.
- **Evening/overnight package** — "€8 after 18:00 until 06:00", whole window one price. VERY
common municipally. Exactly our `packageMinor` (built 2026-07-05).
- **Event rate** — flat premium price during a known event window, set in advance. Expressible
today as a date-ranged windowed card (flat or package).
**3. Entry-time-conditioned rates (the notable GAP)**
- **Early bird** — a discounted all-day flat for cars that ENTER before a cutoff (typically
09:00–10:00), sometimes with an exit-window condition too; no forgiveness for missing the
cutoff. A CBD-commuter staple worldwide. The defining trait: the rate is selected by the
ENTRY instant and governs the whole stay — which is precisely the
**pick-table-by-entry-time** design we identified as the sound future shape (also solves
weekend menus). Anti-arbitrage conditions (min stay / exit window) exist to stop short-stay
parkers grabbing the flat.
**4. Calendar windows** — day/night rates, weekday vs weekend/holiday, seasonal date ranges
(Berlin: free nights + Sundays in some zones). Our V2 windowed cards cover all of these.
**5. Category pricing** — by vehicle type (car/bus/truck) and by customer class
(resident/visitor — SKIDATA advertises residency + vehicle-type tariffs). Our `card.category` +
frozen session category.
**6. Contracts / recurring** — weekly/monthly fixed rates for commuters; steady-revenue anchor
everywhere. Ours lives outside the tariff: [[subscription]] plans.
**7. Discount overlays (validations) — the second GAP**
- **Merchant validation** — a sponsor (shop/hotel/cinema) reduces the parker's fee: mechanisms
range from stamped/barcoded tickets to one-use codes to LPR-keyed auto-validation. Discount
shapes in PARCS products: fixed amount, percentage (up to 100% comp), TIME CREDIT ("first 2h
free"), or a full re-rate to a different rate table. Fully vs partially sponsor-subsidised.
- **Channel discounts** — cheaper pre-booked/online/app rates (airports especially).
**8. Dynamic / demand-based** — price moves with occupancy. SFpark (the canonical study):
target 60–80% block occupancy, ±$0.25 adjustments, → −43% search time, −30% GHG; average rate
actually FELL. Airports run revenue-management engines inside operator-set floor/ceiling.
Almost exclusively municipal-curbside + large-airport territory, needs demand telemetry +
price-communication infrastructure — not single-lot booth territory.
**9. Fees/penalties** — lost ticket = worst-case exposure (max daily × assumed duration): ours
(`lostTicketMinor`). Post-payment exit grace, then overstay repricing: ours.
## Coverage map — our engine vs the industry
| Industry structure | Status in our engine |
| --- | --- |
| Linear hourly, per-started-increment | ✅ V1/V2 blocks + incrementMin |
| Degressive / progressive ladder | ✅ blocks |
| Daily cap, entry grace, exit grace | ✅ |
| Up-to matrix / day ticket | ✅ steps (defaultCard) |
| Day/night, weekend/holiday, seasonal | ✅ V2 windowed cards |
| Night/evening whole-window package | ✅ packageMinor (2026-07-05) |
| Event rate | ✅ expressible (date-ranged card) |
| Vehicle/customer category | ✅ card.category (capture seam pending) |
| Monthly/weekly contracts | ✅ subscription plans (separate) |
| Lost ticket, overstay reprice | ✅ |
| **Early bird / entry-time-conditioned** | ❌ gap — needs pick-table-by-entry-time (see [[tariff]] up-to/tiers incompatibility discussion) |
| **Validations / merchant discounts** | ❌ gap — no discount overlay mechanism; would need signed discount events + sponsor accounting |
| Pre-book/online channel rates | ❌ out of scope (no online channel; offline-first) |
| Dynamic/demand pricing | ❌ deliberately out — municipal/airport scale, needs telemetry; conflicts with printed-price predictability at a booth lot |
## Takeaways for the roadmap
1. **Coverage is already strong**: everything a single staffed lot typically advertises is
expressible today. The 2026-07-05 package mode closed the last everyday gap (real night
price).
2. **Early bird is the highest-value missing structure** and shares its mechanism with the
weekend-menu ask: select the ENTIRE rate table by entry instant (window → table), instead of
pricing per wall-clock slice. One future mechanism, two market features. Include min-stay /
exit-window conditions if built (anti-arbitrage is part of the product, not a nicety).
3. **Validations are the second candidate** once merchants near the site matter: time-credit +
percent + full-comp shapes, as signed appended events (fits the ledger model); sponsor
settlement stays outside the app (like drawer-review denials).
4. **Do not build**: per-minute billing (industry tried it, customers rejected it), dynamic
pricing (wrong scale + breaks price predictability at a booth).
## Sources
- FHWA, *Contemporary Approaches to Parking Pricing: A Primer* — <https://ops.fhwa.dot.gov/publications/fhwahop12026/sec_2.htm>
- Arivo, *The Right Parking Tariff* (practitioner taxonomy) — <https://arivo.co/en/blog/optimal-parking-pricing>
- Pitane, *Per-minute parking creates chaos* (Leuven rollback) — <https://pitane.blue/en/2025/01/16/Parking-rates-in-garages-per-minute-parking-causes-chaos-according-to-experts/>
- Secure Parking, *Early Bird Parking* (entry/exit conditions) — <https://www.secureparking.com.au/en-au/parking-solutions/early-bird-parking/>
- ParkWhiz help, *What is Early Bird* — <https://help.parkwhiz.com/support/solutions/articles/60001010507-what-is-early-bird->
- Parking BOXX, *Validation programs guide* — <https://blog.parkingboxx.com/industry/parking-validation-programs-guide/>
- Amano McGann, *Validation solutions* (discount shapes incl. re-rate) — <https://amanomcgann.com/our-solutions-parking-management/validation/>
- ITS DOT evaluation of SFpark — <https://www.itskrs.its.dot.gov/2024-b01818>
- UCLA ITS, *Pricing Parking by Demand (SFpark)* — <https://www.its.ucla.edu/publication/pricing-parking-by-demand-sfpark/>
- IDeaS, *Airport parking dynamic pricing* — <https://ideas.com/airport-parking-dynamic-pricing/>
- SKIDATA, mobility & parking solutions (tariff axes) — <https://www.skidata.com/en-us/solutions/mobility-parking>
- City of Tampa / MPLS Parking / RDU T&Cs (published rate-card examples) —
<https://www.tampa.gov/parking/info/parking-hourly-and-daily-rates>,
<https://www.mplsparking.com/parking-rates>, <https://www.rdu.com/terms-conditions/>
+1
View File
@@ -90,6 +90,7 @@ Counts: 4 sources · 19 entities · 47 concepts · 7 decision records.
- [[parking-session]] — the core domain entity; a projection over the signed log, never a mutable table.
- [[tariff]] — fee model; pure, data-driven, offline; pay-on-foot adds a walk-back grace window.
- [[tariff-time-tiers]] — BUILT (V2 tariff): happy-hour/off-peak/weekend/seasonal + vehicle category + flat rate via wall-clock windowed cards; tz frozen per version.
- [[tariff-industry-survey]] — 2026-07 web survey of industry tariff structures: coverage map vs our engine; gaps = early bird (pick-table-by-entry-time) + merchant validations; per-minute & dynamic pricing ruled out.
- [[booth-exit-flow]] — manned booth: pay → voucher (self-exit later) or immediate exit; active sessions; audited barrier re-open.
- [[operator-issued-entry]] — operator mints an entry ticket when the physical button is broken; presence-gated (radar AND camera, both sides), flagged (source=manual + operatorInitiated + anomaly), capacity-override allowed; needs `session:create` (2026-07-01).
- [[plate-reconciliation]] — ANPR plate-as-invariant catches the ticket-swap fraud (paid car let out on a fresh $0 ticket, original lingers "inside"); exact/high-conf match vs open sessions; booth = flag + operator override, reader = log-only fail-open (2026-07-01).
+30
View File
@@ -2342,3 +2342,33 @@ read as a dead click on a slow open. Root cause of the slowness recorded as an o
fold from the last z-report's signed expectedDrawerMinor forward. Also from this session: dev-DB
migrations are MANUAL (pnpm db:migrate in packages/db) — a 500 "no such column" after pulling a
migration means it was skipped; booth containers migrate on boot and are immune.
## [2026-07-05] update | Camera health-check detail bucketed — device-monitor log noise fix
The monitor logs + re-emits a device status only when state OR detail changes, but the camera
probe's detail was the exact snapshot byte count — which differs on every JPEG frame, so healthy
cameras "changed" on nearly every poll (a log line + websocket event each, inflating the freshly
budgeted container logs). Camera healthCheck detail is now a stable power-of-two bucket
("snapshot ≈16 KB" / "≈256 KB"; "<1 KB" stays exact as a suspicious-frame flag), so it moves only
on a real shift (stream/resolution change, empty body). packages/devices camera.ts + 3 tests.
## [2026-07-05] query | Industry survey: most-used parking tariff systems
Web research filed as [[tariff-industry-survey]] (reference). Field taxonomy: linear-hourly per
started increment (per-MINUTE tried and rolled back — Leuven), degressive ladders, day caps,
grace; whole-stay prices (day tickets, up-to matrices, evening/overnight packages, event rates);
entry-time-conditioned EARLY BIRD (enter-before cutoff, anti-arbitrage exit conditions); calendar
windows (day/night, weekend/holiday, seasonal); category pricing; monthly contracts; merchant
VALIDATIONS (amount/percent/time-credit/full-comp/re-rate); dynamic demand pricing (SFpark 60-80%
occupancy banding — municipal/airport scale only). Coverage map: our engine expresses everything
a staffed single lot advertises; the two real gaps are early bird (= the pick-table-by-entry-time
future design, same mechanism as weekend menus) and validation overlays. Anti-features confirmed:
per-minute billing, dynamic pricing.
## [2026-07-05] update | Composer page gets the published-versions sidebar too
The published-history sidebar built for the lab landed only there; the operator expected it on
/setup/tariff as well. TariffComposer now mirrors it: right sidebar of published versions (name or
effective date, active badge), click → formFromVersion loads it into the editor as the seed for
the next publish (which, per the sidebar hint, always creates a NEW immutable version). Details on
[[tariff]] (Composer section).