# Printing Strategy (Frontend + Backend + Windows PrintService)

This document summarizes the current printing architecture, the .NET PrintService
implementation, and the key gaps/loopholes to address. No code changes are included.

## Goals

- Use a single, reliable Windows-native print service for ZPL label printing.
- Keep printer discovery real-time and consistent (no stale local caches).
- Make “test print” a clear, explicit UI workflow without impacting production flows.
- Ensure GRN, Production, and FG Inventory are the real printing entry points.
- Enforce consistent printer selection (ID vs name) and request schemas end-to-end.

## Current Architecture (High Level)

- **Backend** generates ZPL from inventory items/products and supports previews.
- **Frontend** requests printers from a local print service and sends ZPL to it.
- **Local print service** is expected to handle Windows spooler/RAW printing.

## .NET PrintService (Native Windows)

### Endpoints and Hosting

- Binds to `http://127.0.0.1:9101`.
  ```6:28:PrintService/Program.cs
  builder.WebHost.UseUrls("http://127.0.0.1:9101");
  ```
- Endpoints: `/health`, `/printers`, `/print`.
  ```10:24:PrintService/Api/PrinterEndpoints.cs
  app.MapGet("/health", ...);
  app.MapGet("/printers", ...);
  app.MapPost("/print", ...);
  ```

### Discovery

- Uses `System.Drawing.Printing.PrinterSettings` to enumerate installed printers.
- Detects brand and DPI from driver settings.
  ```12:23:PrintService/Services/PrinterDiscoveryService.cs
  list.Add(new PrinterInfo { Id = name, Name = name, Brand = DetectBrand(name),
    Dpi = DetectDpi(settings), Port = settings.PortName });
  ```

### Execution

- Requires `PrinterName` and ZPL payload. Uses raw spooler printing.
  ```8:22:PrintService/Services/PrintExecutionService.cs
  if (string.IsNullOrWhiteSpace(request.PrinterName)) throw ...
  RawPrinterHelper.SendStringToPrinter(request.PrinterName, payload);
  ```
- Raw printing is done via `winspool.drv` P/Invoke.
  ```7:55:PrintService/Native/RawPrinterHelper.cs
  OpenPrinter(...); StartDocPrinter(...); WritePrinter(...); EndDocPrinter(...);
  ```

### Security

- Requires `X-Print-Agent-Key` for any endpoint except `/health`.
  ```16:27:PrintService/Security/ApiKeyMiddleware.cs
  if (!context.Request.Headers.TryGetValue("X-Print-Agent-Key", out var key) ...
  ```

## Gaps and Loopholes

### 1) API Contract Mismatch (Frontend ↔ .NET PrintService)

- **Frontend expects** local print service to accept `printer` or `port`.
  - It sends `{ zpl, port }` or `{ zpl, printer }`.
  - .NET PrintService expects **`PrinterName`**, and ignores `port`.
- **Result**: 401 or 400/500 when calling `/printers` or `/print` if headers and schema
  don’t match.
  - .NET service requires `X-Print-Agent-Key`, but frontend does not set it.

### 2) Multiple Print Service Implementations

- The repo currently has **two printing stacks**:
  - Node local print service (older) used by frontend earlier.
  - .NET PrintService (new native Windows version).
- The backend also has a **server-side printer module** that supports network/USB
  on Linux-style device paths, which does not align with Windows RAW printing.
  ```164:177:server/modules/label-printing/services/printer.js
  if (host) { ... } else if (devicePath) { ... } else { throw ... }
  ```
- **Result**: unclear source of truth and inconsistent runtime assumptions.

### 3) Printer Identity Inconsistency

- Some UI flows treat printer **ID** as an opaque identifier.
- Other flows expect **printer name** (actual Windows printer name).
- Example mismatch exists between `usePrintLabel` and reprint flows, leading to
  failed prints if IDs are sent to the service.

### 4) “Test Print” UI Is Mixed With Production Concepts

- The current Label Printing page includes:
  - Manual printer “save” logic (localStorage).
  - A demo-like flow that overlaps with production printing paths.
- This makes it harder to enforce a clean “testing only” UI.

### 5) Label Size Messaging Mismatch

- UI text mentions **2.5cm × 5cm**, but backend ZPL generator uses **2.5" × 5"**.
  This is an operational risk because operators may calibrate for the wrong size.

### 6) Error Handling and Telemetry

- .NET PrintService uses RAW calls without explicit error checks or status returns.
  It always returns `{ success: true }` from `/print`.
  This can produce **false positives** when spooler write fails.

## Strategy Recommendations (No Code, Direction Only)

1. **Adopt a single Windows-native print service** (the .NET PrintService) and
   deprecate the older local service paths in docs and config.
2. **Standardize request schema** for `/print`:
   - Always send `{ printerName, zpl }`.
   - Include required `X-Print-Agent-Key`.
3. **Normalize printer identity**:
   - Use printer **name** as canonical in the UI and backend.
   - Only use IDs if they map to an explicit `name` from the service.
4. **Split the UI**:
   - “Test Print” UI: diagnostics, preview, and a single label test.
   - “Production Print” flows: GRN, Production, FG Inventory reprint.
5. **Align label size messaging** across UI and backend:
   - Explicitly state **2.5" × 5"** in all user-facing text.
6. **Improve success signals** from the print service:
   - Return explicit success/failure and spooler errors.

## Concrete Areas to Improve (Mapped to Your Request)

- **Label UI (testing)**: simplify to a diagnostic/test page that only uses
  the print service and does not store printers locally.
- **Inventory reprint**: ensure printer selection is consistent (name-based)
  and tied to real-time print service printers.
- **GRN process**: keep the post-process redirect to reprint, but confirm printer
  selection and service health before sending to print.
- **Production order**: same as GRN; align printer selection and add clear
  “reprint by production order number” messaging.

