Problem
Access-control work — barrier gates, turnstiles, card readers, CCTV — needs a way to rehearse operations before touching real hardware, and software that can never claim a physical action succeeded when it didn't.
Approach
A simulation-first monorepo: a Next.js dashboard, a Fastify gateway, and four packages for shared domain logic, zod validation, device adapters and Prisma/MySQL persistence. Every command flows through capability checks, a simulation/physical branch, a pure six-condition safety gate, a PENDING record, adapter execution under timeout, adapter-confirmed result, audit and SSE broadcast. Every refusal is machine-readable and audited.
My contribution
All of it: the architecture, the vendor-neutral access rules engine with overnight time windows, the device state machines (barrier, turnstile, camera, NVR, reader), AES-256-GCM credential encryption, RBAC across four roles, the device simulator, and 94 test cases.
How AI was used
The project runs on a ten-rule AGENTS.md contract for agents — simulation first, no invented vendor APIs, physical actuation disabled by default, tests before success claims. Source comments cite spec sections; the agents worked from the spec, and I verified behavior against it.
Technical decisions
- 01
No vendor API is invented: undocumented adapters refuse every action except connection tests, and return a list of the official docs required to implement more.
- 02
Success is only reported after the adapter confirms it — the UI can never render a lie, and timeouts map to an explicit TIMEOUT state.
- 03
MemoryStore by default with Prisma as an opt-in — the entire platform runs with zero setup, and the store contract keeps both honest.
Debugging
The safety-gate refusal matrix, the audit-log secret-leak scan and the visitor auto-check-in flow each began as failures found by their own test suites — the suites exist because the behaviors mattered, not the other way round.
Testing
94 hermetic test cases across nine files — adapter state machines, the safety gate matrix, RBAC, audit sanitization, visitor lifecycle — all via Fastify app.inject with no hardware or database required.
Result
A complete v0.1 platform in daily local use — runtime logs show sessions across all 18 dashboard pages. Real hardware adapters are the documented next step, gated behind the same safety rules.