--- type: concept tags: [parking, architecture, devices] sources: [parking-system-architecture] updated: 2026-06-14 --- # Device-Adapter Pattern How the system stays **device-agnostic**: business logic talks **only to interfaces, never to a device SDK**. Each physical device is an adapter implementing one interface; **swapping hardware means writing a new adapter and nothing else changes.** Implemented as isolated [[fastify]] plugins emitting onto a shared internal event bus. (See [[parking-system-architecture]] §5.) ```ts interface CardReaderDevice { connect(): Promise onCardRead(cb: (cardNumber: string, door: number) => void): void disconnect(): Promise } interface PrinterDevice { printTicket(data: TicketData): Promise checkStatus(): Promise<'ready' | 'offline' | 'paper_out'> } interface RelayDevice { pulseOpen(doorId: number): Promise // intent only — see safety note getDoorStatus(doorId: number): Promise<'open' | 'closed'> } ``` Note the `RelayDevice` expresses **intent only** — see the [[barrier-not-a-door]] safety principle. The choice of *which* adapter to trust is the [[trust-boundary]] decision. > **In practice** the adapters are made *selectable*: a [[device-registry]] catalogs the > supported drivers (ZKTeco / ESP32 relay, Wiegand / TCP-IP readers, Hikvision / Dahua cameras), > and the admin assigns one per lane during [[first-run-setup]]. Adding hardware support = one > more registered driver, no business-logic change. (The implemented interfaces add a > `CameraDevice` for entry/exit snapshots alongside reader/relay/printer.)