Subscription page: the one-window model can't express prepaid/postpaid, calendar or anniversary anchoring, grace or an expiry notice; and renewal is OFF-BOOK today (a PUT that appends no payment — the same hole closed for the first sale on 2026-06-20). Designed: plan billing rule, per-day pricing so both anchors share one formula, open- ended agreement, subscription_periods where each period is a ledger charge and a renewal = paying the next period, one subscriptionAccess() gate function, expiry notice derived not stored. New decision page party-ledger: a counterparty sub-ledger for who-owes-whom across modules — parties + signed charge / settlement / write_off events, balance derived never stored, aging + statements + CSV; lands postpaid subscriptions, hotel guest-nights, fleet washes on account, supplier/utility bills. Sub-ledger only: no bookkeeping, a statement is not a fiscal invoice, parties per appliance. validation-sponsorship's sponsor table marked superseded; open-questions #17; index. Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
13 KiB
type, tags, sources, updated, status
| type | tags | sources | updated | status | ||||
|---|---|---|---|---|---|---|---|---|
| decision |
|
|
2026-09-08 | open |
Open Questions / Next Steps
Not yet decided (or decided-but-not-yet-built), and they drive everything else — settle before procurement. (See parking-system-architecture §10.)
-
Lane topology. One host per lane, or one central host driving networked devices in each lane? Decides how many controllers, printers, UPSs, and sqlite instances exist, and the failure blast radius. (A single central host is a single point of failure for all lanes.)
-
Failure modes. Define per direction what happens to barriers on host/power/network loss — particularly fail-open on exit for egress safety. Currently unaddressed. See fail-state-safety.
-
Payment subsystem. Manned booth (P2PE terminal + cash drawer) vs unmanned pay station; confirm PCI scope is kept out of the application via a standalone certified terminal (see bom). No POS on any site yet (2026-07-01) → card tender is disabled in the UI (cash-only); the future-POS requirements + re-enable path are in card-payments.
-
Reconciliation channel. Even if "offline," establish some periodic path (USB, hotspot, manager visit) to reconcile the signed log against an external authority — the real anti-fraud control. See reconciliation.
-
Durability / backup. (Design SETTLED + engine/target/UI BUILT 2026-06-29 — see backup-recovery; engine + admin-configured target (site_config, migration 0016) + daily timer + manual route + admin UI (target field, Test-target probe, status, Back-up-now) done; SFTP + restore-tooling pending. The target dir is admin-chosen in the UI, not env; only BACKUP_KEY is a server secret.) A disk failure / stolen-or-destroyed PC currently leaves total revenue-history loss. Settled design: an admin-driven encrypted full-DB backup (online-backup/
VACUUM INTO, snapshots included) to a local/USB · SMB/NFS · SFTP target, manual button + in-process daily timer, keep-last-N + dailies retention, encrypted with a dedicatedpark_buzi_backup_key(separate Komodo secret, not the signing key). Recovery = backup file + the two escrowed keys held out-of-band; a restored copy must stillverifyChain. Key-custody stance:EVENT_SIGNING_KEYstays decoupled from the TPM (an extractable, escrowed software key) precisely so it survives total hardware loss — the conscious trade against #6 (a TPM-sealed signing key would be unforgeable but unverifiable after the machine dies). Restore is admin-only/out-of-band (operator-adversary surface — threat-model). See backup-recovery, fleet-deployment-komodo, disk-os-hardening, reconciliation (#4). -
Secure-element integration. (Updated 2026-07-02: no secure element is on-site today.) Event signing currently runs on the software
SoftwareSigner(HMAC-SHA256, key inEVENT_SIGNING_KEY— an env var on the host disk). So the ledger is tamper-EVIDENT but not unforgeable by anyone who owns the host: a case-opening adversary who decrypts the disk reads the key and can re-sign a doctored chain (see append-only-event-chain "pull-the-disk", disk-os-hardening physical-tamper chain). The atecc608 is UPCOMING, not present — and it isn't even the right host part: on a PC appliance the realistic non-extractable host signer is the tpm the box already has, or a USB HSM (Nitrokey HSM 2 / SmartCard-HSM); reserve the ATECC608 for the (deferred) esp32-custom-controller. The concrete menu + recommendation (TPM interim → USB-HSM target) is in hardware-signer-options. The controller command-authentication use is deferred — not being implemented for now (access control is the dingtian-relay behind network-isolation); revisit only if prevention-grade device auth becomes a requirement. -
JWT signing: symmetric vs. asymmetric key. (Raised by the commit security review, not the source doc.) Auth currently uses a symmetric HMAC secret (
@fastify/jwt, see local-jwt-auth) — the same secret signs and verifies, so it must live on every host that validates tokens. Consider rotating to an asymmetric key (RS256 / EdDSA) so the server holds only the public key to verify; the private signing key can then live in the atecc608 or a key-management step. This mirrors the "store only the public key" property already used for atecc608 event signing and the challenge-response-auth scheme — compromising a verifying host yields nothing that can forge a token. Decide before multi-host / multi-lane deployment (see #1 lane topology), since that's when shared-secret distribution becomes the liability. -
Exchange-rate (FX) system. (Raised by the tariff design, 2026-06-15.) Currency is selectable per tariff version and the money model is FX-ready (
paymentstores currency + a reservedfxRate), but no conversion is built. If multi-currency pricing/charging is ever needed, it requires an offline rate source (rates can't depend on the network — offline-first), a base currency, and a rounding policy. Deferred; nothing blocks adding it later without migrating stored amounts. -
Pay-station money corners — receipts & refunds/change. (Raised by the scope sweep, 2026-06-15; deferred until pay-station hardware is chosen.) Not yet designed: receipts / VAT invoices (fiscal receipt with tax number + sequential numbering may be legally required — could change what the
paymentevent must store) and refunds / overpayment / change (cash change, "exact change only", a refund as a signed reversal event). Both depend on the unmanned-vs-manned payment subsystem (#3) and the note/coin/card acceptor hardware. Revisit at procurement. -
Snapshot retention. (Raised by the entry-exit-points camera-snapshot build, 2026-06-16.) Entry/exit snapshots are stored as BLOBs in the sqlite
snapshotstable. This grows the single DB file fast (~100–300 KB per image × every entry and exit), and SQLite doesn't reclaim deleted-blob pages withoutVACUUM. Undecided: pruning policy (age-based vs. total-size cap), VACUUM cadence, and how this interacts with the #5 backup strategy (blobs bloat every backup). Until decided, snapshots accumulate unbounded. See entry-exit-points. (Update 2026-06-29: pruning is now disk-pressure based — see entry-exit-points; and the settled #5 backup includes snapshot BLOBs by default, with a noted future "exclude snapshots" toggle since they dominate backup size — see backup-recovery.) -
Appliance OS image → WebKitGTK version (Tauri dependency). (Raised by desktop-shell-tauri, 2026-06-21; narrowed same day.) The chosen desktop-shell-tauri renders through the host's WebKitGTK, not a bundled browser. The risk reduces to which OS the appliance runs:
- Best case — Ubuntu 26.04 LTS desktop (intended): ships a current, distro-maintained WebKitGTK → this question is effectively resolved; just confirm the built SPA renders on the actual image and pin it.
- Worst case — Windows 11 + WSL + Docker: this conflicts with the standing platform decision (Linux appliance, not Windows/WSL — see standing-decisions, disk-os-hardening) and a GUI shell doesn't live inside headless WSL/Docker. Fallback is no native shell — a kiosk browser at the local fastify-served SPA (Electron only if a standalone Windows installer is mandated). See desktop-shell-tauri for the decision table. Close this once the appliance OS image is fixed and the SPA is verified against its WebView. (Ties to #1 lane topology / image standardization.)
-
TPM 2.0 hardening — implementation (to build). (Recorded 2026-06-21; analysis in tpm.) On the Ubuntu 26.04 LTS appliance, harden using the host TPM: (a) sealed-LUKS auto-unlock (
systemd-cryptenroll --tpm2-device) so the encrypted disk auto-unlocks only on an untampered boot → unattended reboot after power loss; (b) optionally hold the non-extractable host event-signing key in the TPM (a newSignerimpl — noEventLogchange; mirrors the atecc608 swap), defeating the offline pull-the-disk-and-re-sign attack. Must include: require TPM 2.0 (reject 1.2), prefer fTPM + a per-op PIN/auth policy (not PCR-only — bus-sniff), a LUKS recovery passphrase, and a re-seal-on-update runbook (kernel/GRUB/BIOS updates change the PCRs and lock the disk). TPM complements, never replaces, reconciliation; it does nothing against a rooted live host or the operator. Moot in the Windows + WSL fallback. See tpm, disk-os-hardening; relates to #6 (host secure-element by platform) and #13. -
Startup chain-integrity self-check (to build). (Raised by the pull-the-disk trace, 2026-06-21.)
verifyChain()exists and pinpoints any tamper, but nothing invokes it on boot — a tampered DB loads and serves normally (detectable but undetected). Wire a startup self-check that runsverifyChain()and, on a break, flags degraded state / writes a signedanomaly+ alarms (surfaced to the booth footer / next reconciliation). Open: refuse-to-serve vs. serve-degraded — lean serve-degraded + loud alarm (fail-open on exit still governs; refusing to boot could strand a lane). Software-only, independent of the TPM/atecc608 hardware. See append-only-event-chain. -
Printer USB transport — confirm the on-site printer + bake the provisioning. (Recorded 2026-06-24; the transport code is built — see printer-usb-transport.) The ESC/POS drivers now drive TCP (port 9100) OR local USB (
/dev/usb/lp0) behind one render layer, selectable per device. Open: is the actual booth printer USB or network? (The site's verified units are networked — Cashino10.0.10.9, Rongta10.0.10.10— so USB may be unused here; the original BOM listed "Epson TM / Citizen (USB or network)", so a future site may need it.) If USB is used, the appliance image must (a) load/keep theusblpkernel module bound to the printer (CUPS can claim the interface first), and (b) ship a udev rule giving the non-root server process write access to/dev/usb/lp*. Both are appliance-provisioning steps, not app code, and are unverified on hardware. Close this once the printer transport per site is fixed and (if USB) the udev/usblp rule is in the image and a real USB print is verified. Relates to #1 (lane topology / image standardization). See printer-usb-transport, rongta-printer. -
Venue modules — Car Wash / Bar as peers of Parking. (Raised by the user, 2026-09-04.) Optional per-site modules on a shared venue core, with Parking itself becoming a module. Name stays
parking-system(settled 2026-09-05); validation stays for the Bar, only the Lavazh station retires when Car Wash (the pilot module) ships. Registry + Car Wash v1 are built (2026-09-05), and so are tills — shifts/drawers per money-taking module (a bay payment lands on the wash operator's own till, never the booth's). Open: vision category flag, bay camera, the Bar's scope. Full design and the remaining questions on venue-modules. -
Permissions matrix after venue modules. (Raised by the user, 2026-09-05.) The flat
resource:actiongrid was composed for one desk; a second desk (Car Wash) exposed borrowed meanings (session:readas "works the booth till",report:readas "may open the socket") and a composer at the wrong altitude. Decision + three moves (per-desk till guards, jobs on top of the grid, a permission-scoped live feed) on venue-modules §"Permissions matrix"; moves built 2026-09-05. The three loose ends closed 2026-09-06: the supervisor bundle already carriedsubscription:*(stale note); roles now remember the jobs they follow and a grown job is re-applied with one click, never silently; every role edit is signed as aconfig_change. Settled — details on venue-modules §"Permissions matrix" Status. -
Party ledger — receivables & payables across modules. (Raised by the user, 2026-09-08.) Postpaid subscriptions, hotel guest-nights billed to the hotel, Car Wash fleet deals on account, and supplier/utility bills all need "who owes whom". Designed as a counterparty sub-ledger — parties + signed
charge/ settlement /write_offevents, balance derived, aging + statements, CSV for the accountant — see party-ledger (design only, not built). Interacts with #9 (a statement is not a fiscal invoice; fiscalisation is off-appliance) and #8 (one currency per party until FX exists). Also reopened on the subscription page: a renewal is currently off-book (an edit, nopayment).