Implement the core anti-fraud primitive: an append-only, hash-chained,
signed event log (the schema + types predated this; the writer/signer are new).
- EventLog (apps/server): serialized append, monotonic index, prevHash chain,
signature; verifyChain() detects tamper/reorder/delete. No update/delete paths.
- Signer abstraction (packages/shared) over the ATECC608 secure element, with a
SoftwareSigner (HMAC, EVENT_SIGNING_KEY) shipped now since the chip is still
open-question #6. Documented: software signer is tamper-evident but NOT
unforgeable-by-owner.
- Add ParkingEventType "input_received" for raw device inputs (not yet a
vehicle_entry, which the entry flow will append later).
- Read API: GET /api/events; integrity self-check: GET /api/events/verify (admin).
Verified on hardware: shorting the Dingtian inputs produced signed, chained
input_received events; verifyChain ok; direct DB tamper/delete detected.
NOTE: the log captures host-originated actions only. Out-of-band relay
actuation (sniffed relay_pw, string protocol, ip_watchdog) produces no event
by design -- the control is reconciliation vs. an independent witness, which is
not yet built. See wiki/concepts/append-only-event-chain.md.
Turborepo (pnpm workspaces) with all dependencies pinned to latest
mutually-compatible versions: turbo 2.9, TypeScript 6, Fastify 5,
React 19, Vite 8, better-sqlite3 12 + Drizzle ORM 0.45.
Layout:
- apps/server Fastify backend (local JWT auth + role guard, /health)
- apps/web React 19 + Vite 8 operator SPA
- packages/db Drizzle schema on SQLite/WAL; append-only events + users
- packages/devices reader/printer/relay adapter interfaces (intent-only relay)
- packages/shared shared domain types
Architecture constraints from the design wiki are encoded in the scaffold:
append-only hash-chained + signed event log, device-agnostic adapters,
"a barrier is not a door" (relay expresses intent only), fully-local
offline-first auth.
wiki/ is an LLM-maintained Obsidian knowledge base (28 pages) ingested
from the architecture & design notes, with its own maintenance schema.
Verified: pnpm install, full turbo build (5/5), server boots and serves
/health, drizzle-kit generates the initial migration.