import { deviceEvents } from "../../device-events.js"; import type { ServerModule } from "../index.js"; import { ReviewOutbox, reviewUploadConfigFromEnv } from "./review-outbox.js"; import { carwashRoutes } from "./routes.js"; import { CarwashService } from "./service.js"; // Car Wash — the pilot venue module (wiki/decisions/venue-modules.md). Everything the // module is lives in this folder: its service (master data, the order queue, the bay // payment, the parking sponsorship + settlement), its routes, and the booth charge // provider it registers with the core's PayStation. The core knows it only through the // registry line in ../index.ts and the manifest in @parking/shared. export const carwashModule: ServerModule = { id: "carwash", async register(app, deps) { // The review outbox (wiki/concepts/vision-review-outbox.md): on when the stack env // names a collector URL, a per-booth token and a pseudonymous booth id; off = no // queueing at all. One-way, background, never on the intake path. const cfg = reviewUploadConfigFromEnv(); const outbox = new ReviewOutbox(deps.db, app.log, cfg); app.log.info(cfg ? `carwash review upload: on → ${new URL(cfg.url).host} as ${cfg.boothId}` : "carwash review upload: off"); outbox.start(); // Entry-stream sampling: one in N entry vehicle reads goes to the reviewer as pure // training material (the gate view, no order attached). The core announces the read; // the module decides. Off unless CARWASH_REVIEW_ENTRY_SAMPLE is set. const offVehicleRead = deviceEvents.onVehicleRead((e) => { if (e.direction === "entry" && outbox.sampleEntry()) void outbox.enqueueEntry(e.read); }); app.addHook("onClose", async () => offVehicleRead()); app.addHook("onClose", async () => outbox.stop()); const service = new CarwashService(deps, app.log, outbox); // A wash ordered with payAt = "booth" is a charge line on the parking settlement; // the core calls back after the payment is signed so the order is marked paid. deps.payStation.registerChargeProvider(service.chargeProvider()); await carwashRoutes(app, deps, service, outbox); }, };