Printer Config Module
Technical reference for apps/backend/src/printer-config/.
This module is the tenant-scoped home for printer definitions that used to live
only in Print Bridge's per-device config.json. Three features layered on the
same hexagonal folder:
| Feature | What it added |
|---|---|
050-mobile-printing-foundation | Tables + device-token read path + adoption flag |
052-mobile-generic-printing | Merchant session CRUD, test-print render, station claims |
053-mobile-vendor-printing | Vendor columns, discovery telemetry hashing, businessId on list |
Foundation overview: Mobile Printing Foundation. Vendor registry: Printer Vendor Port.
Hexagonal map
Domain
Repository ports only — no framework imports:
IPrinterConfigRepositoryIPrinterDiscoveryEventRepositoryIPrinterOrchestratorSettingRepository
Application
| Service | Use case |
|---|---|
PrinterConfigService | Device-token list for Print Bridge |
PrinterOrchestratorFlagService | Adoption flag. No row means off. |
PrinterConfigManagementService | Merchant save/update/remove, station assignment |
TestPrintRenderService | Encode a test slip; does not print |
MobileClientRegistrationService | Station claims, release, heartbeat |
StationServiceStatusService | Who is serving each assigned station |
PrinterDiscoveryEventService | Hashed scan telemetry |
VendorResolutionService | Passive backfill of vendor on saved rows |
DiscoveryIdentityHasherService | Per-business identity hashes |
Infrastructure
Kysely adapters in infrastructure/. Soft-delete on remove keeps history
(FR-021) and releases station assignments so nothing is still routed there.
Interfaces
Two auth surfaces, deliberately separate (design §1a — Print Bridge's path is untouched):
| Controller | Auth | Audience |
|---|---|---|
PrinterConfigController GET /printer-config | @IsPublic() + DeviceGuard | Print Bridge |
PrinterDiscoveryEventController | Device token | Print Bridge scans |
PrinterConfigManagementController /printer-config/manage | Firebase session + RolesGuard | Mobile / PWA merchants |
Domain concepts
A printer is a tenant-scoped row (business_id + location_id) with a
connection, optional device binding, optional station list, and a role
(receipt or kitchen). Station assignment is not exclusive — a station
may appear on more than one printer.
printer_orchestrator_setting is the adoption flag. Absence of a row is off.
No row is auto-created.
printer_discovery_event is append-only scan telemetry. Identifiers are
hashed per business before write. Display names, hosts, and MACs are stripped.
Merchant API (/printer-config/manage)
Tenant scope is the session plus ?locationId=. businessId is never taken
from a body.
| Method | Path | Permission | Notes |
|---|---|---|---|
GET | /printer-config/manage?locationId= | Printer Read | With deviceId, returns network printers plus this device's bound ones. Response includes businessId and servedBy. |
POST | /printer-config/manage?locationId= | Printer Create | Upsert by stable identity — a DHCP reassignment does not duplicate the row. |
PATCH | /printer-config/manage/:id | Printer Update | Rename, address, profile, vendorLockedGeneric. |
PUT | /printer-config/manage/:id/stations | PrinterStationAssignment Update | Only writer of station assignments. |
POST | /printer-config/manage/:id/test-print | Printer Update | Returns { payloadB64, cols }. Caller enqueues into the device outbox. |
DELETE | /printer-config/manage/:id | Printer Delete | Soft delete; 204. |
POST | /printer-config/manage/claims | PrinterStationAssignment Update | Claim stations. Caller must already hold a ready printer connection. |
DELETE | /printer-config/manage/claims/:deviceId?stationId= | PrinterStationAssignment Update | Release one station. |
POST | /printer-config/manage/claims/heartbeat | PrinterStationAssignment Update | Every 20s; 60s staleness cutoff. |
POST | /printer-config/manage/discovery-events | Printer Read | Best-effort telemetry. Failure must not block setup. |
Printer vs PrinterStationAssignment is blast radius: setting up a printer
affects one device; assigning a station stands Print Bridge down for that
station. Retail merchants with no kitchen stations can still save a receipt
printer.
Device API (GET /printer-config)
Print Bridge polls this with its pairing token. businessId / locationId
come from the device row. Returns { orchestratorEnabled, printers }.
Kitchen-ticket dispatch uses the shared orchestrator only when the flag is
on. Document/receipt jobs keyed by receiptPrinter / targetPrinterId stay
on the legacy path.
Constraints
- The backend never delivers bytes to a printer. Test-print render and document encode stop at payload; the mobile outbox or Print Bridge writes.
vendoraccepted on save is a device-side resolution. A wrong value costs capability on that device, not tenant isolation.vendorLockedGenericdoes not clearvendor. Undo restores the vendor path without a re-probe.- Listing omits soft-deleted rows. History stays in the table.