PrintBit is a web app coin-operated kiosk machine. Dedicated for printing document, photocopying documents, and even converting your documents into an soft copy. It is designed for campus usage (students, faculty, and staff) with phone-to-kiosk document upload and on-device job confirmation.
- Coin balance via serial input (Arduino/coin acceptor).
- Wireless upload sessions for print jobs (QR + hotspot flow).
- Print, copy, and scan job charging tied to configurable pricing.
- PH-localized Pricing Engine (v1): Coverage-aware per-page pricing with threshold classification, bulk tier discounts, and whole-peso settlement.
- Tokenized E-Receipt links for settled transactions (
/receipt/t/:token). - Wireless scan-to-phone soft copy delivery with dual-QR completion.
- Admin dashboard for earnings, logs, settings, and diagnostics.
Before using mobile-connected features (uploading print files, downloading scanned soft copies, or viewing E-Receipts), customers must connect to the kiosk's local Wi-Fi:
- Scan the Wi-Fi QR code on the kiosk screen or manually connect to the Wi-Fi network:
- SSID:
PrintBit
- SSID:
- If a captive portal pop-up appears, proceed or tap Continue.
- Connect your phone to PrintBit Wi-Fi.
- Select Print on the kiosk screen.
- Scan the on-screen session QR code with your phone.
- Select and upload your document (PDF, DOCX, and other image file formats) on the mobile upload page.
- On the kiosk screen, select your file under Received files and tap Continue to settings.
- Configure print options (color mode, copies, orientation, paper size, page range) and continue.
- On the confirm screen, insert coins until your balance covers the total fee, then confirm payment.
- Collect your printed documents from the tray.
- (Optional) Scan the E-Receipt QR code on the completion screen with your phone to view and save your digital receipt.
Troubleshooting:
- If no file appears, generate a new kiosk session and upload again.
- Complete upload and selection before the session timer expires.
- If balance is insufficient, insert additional coins before confirming.
- Select Copy on the kiosk screen.
- Place the document face-down on the scanner glass.
- Tap Check Document to generate a scan preview.
- If the preview is correct, tap Continue to Config.
- Configure copy options (color mode, copies, paper size) and continue to confirmation.
- Insert coins until the required balance is met, then confirm payment.
- Collect your copied pages from the tray.
- (Optional) Connect your phone to PrintBit Wi-Fi and scan the E-Receipt QR code on the completion screen to view and save your digital receipt.
Troubleshooting:
- If no document is detected, reposition the page and tap Retry.
- If preview looks incorrect, tap Check Document again before continuing.
- Connect your phone to PrintBit Wi-Fi.
- Select Scan on the kiosk screen.
- Select your desired export format (PDF, JPG, or PNG) and paper size.
- Place your document on the scanner and tap Scan Document (rescan or add pages if needed).
- Review the preview and tap Proceed to Pay.
- Insert coins until the soft-copy fee is covered, then confirm payment.
- The completion screen displays two QR codes:
- Download QR Code: Scan with your phone (connected to PrintBit Wi-Fi) to download the soft-copy file directly.
- E-Receipt QR Code: (Optional) Scan to view and save your digital transaction receipt.
Troubleshooting:
- Ensure your phone remains connected to PrintBit Wi-Fi when scanning the download QR code.
- If the scanner is busy or unavailable, check connections and retry.
- Available after payment confirmation across all 3 methods (Print, Copy, and Scan).
- Customer receipt links use tokenized routes:
/receipt/t/:token. - Retained for up to 24 hours. After expiry, links show an expired outcome.
- Phone must be connected to PrintBit Wi-Fi to view the local E-Receipt.
- Admin support lookup: Admin -> Transactions -> Open E-Receipt.
- Backend: Node.js, Express, Socket.IO, TypeScript, C# Worker Service
- Storage: SQLite (
printbit.sqlite) for persisted kiosk state - Upload handling: Multer
- Printing: Phased dispatcher (
SumatraPDF.exe) - Serial integration:
serialport - Frontend: Static HTML/CSS + TypeScript bundles under
src/public - Testing: Jest, Supertest
pnpm installpnpm run devServer starts on http://0.0.0.0:3000.
pnpm run buildpnpm exec tsc --noEmit --ignoreDeprecations 6.0If upgrading from an older deployment that still has db.json, run:
pnpm run db:migrate:legacyUse --force to rerun import after clearing the migration marker:
pnpm run db:migrate:legacy -- --forcesrc/
server.ts # App entrypoint
config/ # Runtime constants and route-to-page mappings
middleware/ # Captive portal, static assets, admin auth
routes/ # HTTP API and page route registration
services/ # Printer, serial, session, hotspot, db, admin logic
public/ # Browser UI pages (print/upload/config/confirm/copy/scan/admin)
uploads/ # Runtime uploaded files
printbit.sqlite # Runtime persisted machine state (SQLite)
bin/ # External executables (ex: PDFtoPrinter.exe, SumatraPDF.exe)
- Windows machine (required for current hardware/print/hotspot integrations).
- Print dispatch dependencies configured for your selected mode:
bin/PDFtoPrinter.exe(orPRINTBIT_PDFTOPRINTER_PATH)- GhostScript (
PRINTBIT_GHOSTSCRIPT_PATHor PATHgswin64c) - Optional Sumatra fallback (
bin/SumatraPDF.exeorPRINTBIT_SUMATRA_PATH) for phased mode
- Optional but expected in production:
- Coin acceptor serial device
- Scanner device
- ESP32 network bridge
PRINTBIT_PRINT_DISPATCH_MODE=legacy|phased|new-only(defaultlegacy)legacy: Sumatra-only behaviorphased: PDFtoPrinter/GhostScript with Sumatra emergency fallbacknew-only: PDFtoPrinter/GhostScript only
PRINTBIT_POWER_SAFETY_BYPASS=true(optional, local development only) treats power safety as operational while testing Node.js without the physical printer/UPS. It does not bypass printer preflight checks or enable printing.PRINTBIT_PDFTOPRINTER_PATH(orPDFTOPRINTER_PATH) default:bin/PDFtoPrinter.exePRINTBIT_GHOSTSCRIPT_PATH(orGHOSTSCRIPT_PATH) optional explicit path togswin64c.exePRINTBIT_SUMATRA_PATH(orSUMATRA_PATH) optional Sumatra fallback pathPRINTBIT_PRINT_DISPATCH_TIMEOUT_MS(default60000)PRINTBIT_PRINT_SPOOLER_MONITOR_WINDOW_MS(default180000, minimum30000)PRINTBIT_PRINT_SPOOLER_POLL_INTERVAL_MS(default1500, minimum250)PRINTBIT_PRINT_SPOOLER_LOOKBACK_MINUTES(default3, minimum1)PRINTBIT_PRINT_SPOOLER_QUERY_TIMEOUT_MS(default20000, minimum5000)
- Android: Chrome (latest stable + prior major) for
/upload/:token - iOS: Safari (latest stable + prior major) for
/upload/:token - Supported upload formats: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, JPG, PNG
- Session continuity: upload page refreshes lease periodically and also on app resume (visibility/focus events)
PRINTBIT_NETWORK_PROVIDER=esp32(default)- ESP32 provides AP + captive portal onboarding.
- PrintBit still serves session/upload endpoints and
/portalbridge. POST /api/hotspot/startregisters the kiosk with the ESP32 bridge.
Related env knobs:
PRINTBIT_HOTSPOT_SSID(defaultPrintBit)PRINTBIT_HOTSPOT_PASSWORD(default empty)PRINTBIT_HOTSPOT_AUTH_TYPE(derived from password by default:nopasswhen empty,WPAotherwise)PRINTBIT_ESP32_CAPTIVE_PORTAL_PATH(default/portal)PRINTBIT_ESP32_AP_BASE_URL(defaulthttp://192.168.4.1) for kiosk registration endpointPRINTBIT_ESP32_REGISTER_TOKEN(defaultprintbit-register-token) shared token for ESP32/kiosk/registerPRINTBIT_ESP32_KIOSK_SUBNET_PREFIX(default192.168.4.) to detect kiosk IP for ESP32 modePRINTBIT_ESP32_KIOSK_IP(default192.168.4.2) kiosk IP used by launch/watchdog URLs and startup static-IP enforcement in ESP32 modePRINTBIT_ESP32_STATIC_IP_ENFORCE(defaultfalsein ESP32 mode) reconnects Wi-Fi; only reapplies kiosk static IPv4 when set totruePRINTBIT_ESP32_KIOSK_NETMASK(default255.255.255.0) netmask used by startup static-IP enforcementPRINTBIT_ESP32_GATEWAY_IP(optional) explicit ESP32 gateway override for startup static-IP enforcement (otherwise derived fromPRINTBIT_ESP32_AP_BASE_URL)PRINTBIT_ESP32_WIFI_INTERFACE(optional) explicit Windows Wi-Fi interface alias for startup static-IP enforcementPRINTBIT_ESP32_COIN_SOURCE(defaultesp32) expected source label for/coinbridge requestsPRINTBIT_ESP32_COIN_API_KEY(required inesp32mode) shared secret required by/coinbridge requestsPRINTBIT_ESP32_COIN_BRIDGE_RELAXED(defaultfalse) simulation-only compatibility mode for legacy/coin?value=requestsPRINTBIT_ESP32_ALWAYS_ACCEPT_COINS(defaulttrueinesp32mode) accepts coin credits even when slot/printer safety gates are active so kiosk UI balance keeps updating from ESP32 eventsPRINTBIT_TRUSTED_TIME_ENFORCE(defaultfalse) blocks or allows financial operations when trusted time cannot syncPRINTBIT_SERIAL_PORT(optional) to pin the serial coin/hopper device when multiple COM ports are present
Recommended .env for ESP32 mode:
PRINTBIT_NETWORK_PROVIDER=esp32
PRINTBIT_HOTSPOT_SSID=PrintBit
PRINTBIT_HOTSPOT_PASSWORD=printbit123
PRINTBIT_HOTSPOT_AUTH_TYPE=WPA
# Fixed kiosk IP for reboot-stable ESP32 deployments
PRINTBIT_ESP32_KIOSK_IP=192.168.4.2
PRINTBIT_ESP32_AP_BASE_URL=http://192.168.4.1
PRINTBIT_ESP32_REGISTER_TOKEN=printbit-register-token
PRINTBIT_ESP32_STATIC_IP_ENFORCE=true
PRINTBIT_ESP32_KIOSK_NETMASK=255.255.255.0
# Optional interface/gateway overrides:
# PRINTBIT_ESP32_WIFI_INTERFACE=Wi-Fi
# PRINTBIT_ESP32_GATEWAY_IP=192.168.4.1
PRINTBIT_ESP32_COIN_SOURCE=esp32
PRINTBIT_ESP32_COIN_API_KEY=printbit-coin-bridge-key
# Keep strict mode for production and real ESP32 bridging
PRINTBIT_ESP32_COIN_BRIDGE_RELAXED=false
# Optional: keep ESP32 coin credits flowing even during printer/slot safety gates
PRINTBIT_ESP32_ALWAYS_ACCEPT_COINS=true
# Optional: turn on only when kiosk has stable NTP/internet access
PRINTBIT_TRUSTED_TIME_ENFORCE=falseSecurity note: printbit-coin-bridge-key is a predictable example value. Before deployment, generate a unique secret for PRINTBIT_ESP32_COIN_API_KEY, set it in the kiosk environment, and use the same value in ESP32 firmware (coinBridgeApiKey in esp32-captive-portal.ino). Do not reuse the default key in production.
Recommended .ino alignment for ESP32 mode:
- Use
WiFiManager.hto connect ESP32 to your 2.4GHz LAN (STA mode) - WiFiManager config portal SSID/password (firmware defaults):
PrintBit-Setup/printbit123 - Point
PRINTBIT_ESP32_AP_BASE_URLto the current ESP32 LAN IP (for examplehttp://192.168.1.120) - Handle kiosk registration on
POST /kiosk/register(ESP32 listens on port80) - Forward coins with secure
/coinrequest headers:x-coin-source: esp32x-coin-api-key: <same as PRINTBIT_ESP32_COIN_API_KEY>x-coin-event-id: <unique id per coin>
- For hopper change dispensing, support authenticated commands:
POST /hopper/dispensewithtoken,coins, optionalrequestIdGET /hopper/status?token=...for live dispense state- Use the same shared secret as
PRINTBIT_ESP32_COIN_API_KEY(hopperControlTokenin.ino)
Troubleshooting mobile captive onboarding:
- If captive page does not auto-open after joining kiosk Wi-Fi, open the fallback upload link shown on Print screen.
- If session is expired/owned by another device, generate a new kiosk print session and scan again.
- If logs show
no adapter IP matches 192.168.4.x, setPRINTBIT_ESP32_KIOSK_IPto the kiosk's current IP on the ESP32 network (for example192.168.4.3).
- Upload and machine state are persisted in
uploads/andprintbit.sqlite; do not delete these unintentionally during operation. - Admin routes are restricted by local-network checks and admin PIN header requirements.
- Current hotspot/captive behavior is optimized for Android flow; iOS flow improvements are being planned.
- CONTRIBUTING.md
- API_DOCUMENTATION.md
- ARCHITECTURE.md
- OPERATIONS.md
- INSTALLATION_AND_DEPENDENCIES.md
- DOCUMENTATION_SUGGESTIONS.md
- For full install/software/dependency setup, start with
INSTALLATION_AND_DEPENDENCIES.md. - For suggested next documentation improvements, see
DOCUMENTATION_SUGGESTIONS.md.
