# Printer System Architecture & Debugging Guide

## Overview
The printer system consists of three main components:
1. **Frontend (React/Next.js)** - User interface and print initiation
2. **Backend (Node.js/Express)** - ZPL generation and API endpoints
3. **Print Service (.NET Windows Service)** - Direct printer communication via Windows Print Spooler API

---

## Complete Flow Diagram

```
┌─────────────────────────────────────────────────────────────────┐
│                    FRONTEND (Browser)                            │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ User clicks "Print Label" button                          │  │
│  │ (Label Printing page, Inventory page, Reprint page)      │  │
│  └──────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ PrinterSelect Component                                   │  │
│  │ - Queries Print Service: GET /printers                   │  │
│  │ - Displays available printers                            │  │
│  │ - User selects printer                                   │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ printLabelMutation / usePrintLabel                        │  │
│  │ Step 1: Fetch ZPL from backend                            │  │
│  │   GET /api/label-printing/inventory-items/:id/zpl        │  │
│  │   OR                                                      │  │
│  │   GET /api/label-printing/products/:id/zpl               │  │
│  │                                                           │  │
│  │ Step 2: Send ZPL to Print Service                        │  │
│  │   POST http://127.0.0.1:9101/print                       │  │
│  │   Headers: X-Print-Agent-Key: xyz-pos-local-token        │  │
│  │   Body: { printerName, zpl }                             │  │
│  └───────────────────┬─────────────────────────────────────┘  │
└──────────────────────┼──────────────────────────────────────────┘
                       │
                       │ HTTP Request
                       │
┌──────────────────────▼──────────────────────────────────────────┐
│                    BACKEND (Node.js)                             │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ GET /api/label-printing/inventory-items/:id/zpl           │  │
│  │ Controller: getInventoryItemLabelZPL                      │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ Service: generateLabelPreview                            │  │
│  │ - Loads InventoryItem + Product from DB                 │  │
│  │ - Validates product_type === 'FG'                       │  │
│  │ - Extracts productName, uid                             │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ Service: generateZPLTemplate                            │  │
│  │ - Input: { productName, uid, qrData }                   │  │
│  │ - Options: { dpi, labelLength, labelWidth }             │  │
│  │ - Calculates dimensions in dots (DPI-based)              │  │
│  │ - Generates ZPL string with:                            │  │
│  │   * Product name text                                    │  │
│  │   * UID text                                            │  │
│  │   * QR code (^BQ command)                               │  │
│  │ - Returns ZPL string                                    │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ Response: { zplData, productName, uid }                 │  │
│  │ Status: 200 OK                                          │  │
│  └───────────────────┬─────────────────────────────────────┘  │
└──────────────────────┼──────────────────────────────────────────┘
                       │
                       │ HTTP Response (ZPL string)
                       │
┌──────────────────────▼──────────────────────────────────────────┐
│                    FRONTEND (Browser)                            │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ Receives ZPL data from backend                            │  │
│  │ Calls: printZPL(zplData, { printerName, printerPort })   │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ printerClient.printZPLToPrinter                          │  │
│  │ - Validates zplData, printerName                         │  │
│  │ - Builds request body: { printerName, zpl, printerPort }│  │
│  │ - POST http://127.0.0.1:9101/print                      │  │
│  │ - Headers: X-Print-Agent-Key                            │  │
│  │ - Timeout: 30 seconds                                    │  │
│  └───────────────────┬─────────────────────────────────────┘  │
└──────────────────────┼──────────────────────────────────────────┘
                       │
                       │ HTTP POST Request
                       │
┌──────────────────────▼──────────────────────────────────────────┐
│              PRINT SERVICE (.NET Windows Service)                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ Endpoint: POST /print                                     │  │
│  │ Middleware: ApiKeyMiddleware (validates X-Print-Agent-Key)│  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ PrinterEndpoints.Map("/print")                          │  │
│  │ - Receives PrintRequest { PrinterName, Zpl }            │  │
│  │ - Calls PrintExecutionService.Print(request)           │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ PrintExecutionService.Print                             │  │
│  │ - Validates PrinterName, Zpl                            │  │
│  │ - Detects printer language (ZPL/EPL)                    │  │
│  │ - Calls RawPrinterHelper.SendStringToPrinter            │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ RawPrinterHelper.SendStringToPrinter                     │  │
│  │ - P/Invoke: OpenPrinter(printerName)                    │  │
│  │ - P/Invoke: StartDocPrinter (RAW data type)             │  │
│  │ - P/Invoke: StartPagePrinter                            │  │
│  │ - P/Invoke: WritePrinter(zpl bytes)                     │  │
│  │ - P/Invoke: EndPagePrinter                              │  │
│  │ - P/Invoke: EndDocPrinter                               │  │
│  │ - P/Invoke: ClosePrinter                                │  │
│  └───────────────────┬─────────────────────────────────────┘  │
│                      │                                          │
│  ┌───────────────────▼─────────────────────────────────────┐  │
│  │ Response: { success: true }                             │  │
│  │ Status: 200 OK                                          │  │
│  └───────────────────┬─────────────────────────────────────┘  │
└──────────────────────┼──────────────────────────────────────────┘
                       │
                       │ HTTP Response
                       │
┌──────────────────────▼──────────────────────────────────────────┐
│                    FRONTEND (Browser)                            │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ Receives success response                                  │  │
│  │ Shows toast: "Label printed successfully!"                │  │
│  │ Closes print modal                                        │  │
│  └──────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────┘
```

---

## Component Details

### 1. Frontend Components

#### A. PrinterSelect Component
**File**: `client/components/features/label-printing/PrinterSelect.jsx`

**Responsibilities**:
- Queries Print Service `/printers` endpoint on mount
- Displays list of available printers
- Allows user to select a printer
- Shows service health status (online/offline)
- Auto-selects first printer if `autoSelect={true}`

**Key Functions**:
- `getAvailablePrinters()` - Fetches printers from Print Service
- `checkPrintServiceHealth()` - Health check via `/health` endpoint

**Potential Issues**:
1. **Service not running**: Error "Cannot connect to print service"
2. **No printers found**: Error "No label printers found"
3. **Timeout**: 2-second timeout may be too short for slow networks
4. **CORS issues**: If Print Service CORS not configured correctly

---

#### B. usePrintLabel Hook
**File**: `client/hooks/usePrintLabel.js`

**Responsibilities**:
- Manages print label mutation
- Fetches ZPL from backend
- Sends ZPL to Print Service
- Handles success/error states

**Flow**:
1. Get available printers
2. Resolve target printer (from param, state, or first available)
3. Fetch ZPL from backend with printer DPI
4. Call `printZPL()` to send to Print Service

**Potential Issues**:
1. **Printer not found**: Selected printer name doesn't match any available printer
2. **ZPL fetch failure**: Backend API error or network issue
3. **ZPL data missing**: Response structure mismatch (multiple possible paths)
4. **Print service timeout**: 30-second timeout may not be enough for slow printers

---

#### C. printerClient Utility
**File**: `client/lib/utils/printerClient.js`

**Key Functions**:
- `getAvailablePrinters()` - Queries Print Service `/printers`
- `checkPrintServiceHealth()` - Health check
- `printZPL()` - Main print function
- `printZPLToPrinter()` - Sends ZPL to Print Service

**Request Format**:
```javascript
POST http://127.0.0.1:9101/print
Headers:
  Content-Type: application/json
  X-Print-Agent-Key: xyz-pos-local-token
Body:
  {
    "printerName": "ZDesigner ZT231-203dpi ZPL",
    "zpl": "^XA\n^PW...\n^XZ",
    "printerPort": "USB001" // optional
  }
```

**Potential Issues**:
1. **Service URL incorrect**: Default `http://127.0.0.1:9101` may not match actual service
2. **API key mismatch**: Default key `xyz-pos-local-token` must match Print Service config
3. **Timeout too short**: 30 seconds may not be enough for USB printers
4. **Response parsing**: Assumes `result.success === true`, but service may return different format

---

### 2. Backend Components

#### A. Label Printing Controllers
**File**: `server/modules/label-printing/controllers/index.js`

**Endpoints**:
- `GET /api/label-printing/inventory-items/:id/zpl` - Get ZPL for inventory item
- `GET /api/label-printing/products/:id/zpl` - Get ZPL for product

**Flow**:
1. Extract `id` from params
2. Extract `dpi`, `labelLength`, `labelWidth` from query params
3. Call `labelPrintingService.generateLabelPreview()`
4. Return `{ zplData, productName, uid }`

**Potential Issues**:
1. **Missing query params**: DPI defaults to 203, but may not match printer
2. **Product type validation**: Only FG products allowed, but error may not be clear
3. **UID missing**: Inventory item without UID will fail
4. **Response structure**: Multiple possible response paths (`data.data.zplData` vs `data.zplData`)

---

#### B. Label Printing Service
**File**: `server/modules/label-printing/services/labelPrinting.js`

**Functions**:
- `generateLabelPreview()` - Main function that generates ZPL
- `printInventoryItemLabel()` - Server-side printing (network printers)
- `printProductLabel()` - Product label generation

**Flow**:
1. Load InventoryItem/Product from database
2. Validate product_type === 'FG'
3. Extract productName, uid
4. Call `generateZPLTemplate()` with options
5. Return ZPL data

**Potential Issues**:
1. **Database query failure**: InventoryItem or Product not found
2. **Product type mismatch**: RM products will throw ValidationError
3. **UID missing**: Inventory item without UID will fail
4. **Options not passed correctly**: DPI/label size may not be forwarded to ZPL generator

---

#### C. ZPL Generator
**File**: `server/modules/label-printing/services/zplGenerator.js`

**Function**: `generateZPLTemplate(labelData, options)`

**Input**:
- `labelData`: `{ productName, uid, qrData }`
- `options`: `{ dpi, labelLength, labelWidth }`

**Process**:
1. Validates productName and uid
2. Converts label size from inches to dots: `dots = inches * DPI`
3. Calculates font sizes, margins, QR code size (all DPI-scaled)
4. Truncates product name to fit text area
5. Generates ZPL string with:
   - `^XA` - Start label
   - `^PW{width}` - Print width in dots
   - `^LL{length}` - Label length in dots
   - `^FO{x},{y}` - Field origin
   - `^A0N,{size},{size}` - Font command
   - `^FD{text}^FS` - Field data
   - `^BQN,2,6^FDQA,{qrData}^FS` - QR code
   - `^XZ` - End label

**Potential Issues**:
1. **DPI mismatch**: If frontend sends wrong DPI, label will be wrong size
2. **Label size mismatch**: Default 2.5" x 5" may not match actual label stock
3. **Text truncation**: Long product names may be cut off
4. **QR code size**: May be too large/small for label
5. **ZPL syntax errors**: Invalid ZPL commands will cause printer errors

---

### 3. Print Service (.NET)

#### A. Printer Discovery Service
**File**: `PrintService/Services/PrinterDiscoveryService.cs`

**Function**: `GetPrinters()`

**Process**:
1. Iterates `PrinterSettings.InstalledPrinters`
2. For each printer:
   - Gets `PrinterSettings` object
   - Detects brand from name
   - Detects DPI from `DefaultPageSettings.PrinterResolution`
   - Gets port via reflection (`PortName` property)
3. Returns `List<PrinterInfo>`

**Potential Issues**:
1. **Port detection failure**: `PortName` property may not be accessible (returns empty string)
2. **DPI detection failure**: Defaults to 203 if detection fails
3. **Brand detection**: Only checks name, may misidentify brand
4. **No printers found**: Returns empty list if no printers installed

---

#### B. Print Execution Service
**File**: `PrintService/Services/PrintExecutionService.cs`

**Function**: `Print(PrintRequest request)`

**Process**:
1. Validates `PrinterName` and `Zpl`
2. Detects printer language (ZPL/EPL) - currently just uses ZPL
3. Calls `RawPrinterHelper.SendStringToPrinter()`

**Potential Issues**:
1. **No error handling**: Exceptions are not caught, will bubble up
2. **No return value**: Function returns void, success/failure not communicated
3. **Language detection**: Currently doesn't transform EPL, may fail for EPL printers

---

#### C. Raw Printer Helper
**File**: `PrintService/Native/RawPrinterHelper.cs`

**Function**: `SendStringToPrinter(printerName, data)`

**Process**:
1. P/Invoke `OpenPrinter(printerName)` - Opens printer handle
2. Creates `DOCINFOA` struct with `pDataType = "RAW"`
3. P/Invoke `StartDocPrinter()` - Starts print job
4. P/Invoke `StartPagePrinter()` - Starts page
5. Marshals ZPL string to ANSI bytes
6. P/Invoke `WritePrinter()` - Writes ZPL bytes
7. P/Invoke `EndPagePrinter()` - Ends page
8. P/Invoke `EndDocPrinter()` - Ends document
9. P/Invoke `ClosePrinter()` - Closes printer handle
10. Frees marshaled memory

**Potential Issues**:
1. **No error checking**: P/Invoke calls don't check return values
2. **Printer not found**: `OpenPrinter` fails if printer name doesn't match exactly
3. **Printer busy**: Printer may be in use, causing `OpenPrinter` to fail
4. **Memory leak**: If exception occurs, `Marshal.FreeCoTaskMem` may not be called
5. **Invalid ZPL**: Printer may reject invalid ZPL, but no feedback to caller
6. **Printer offline**: Printer may be offline, causing write to fail silently

---

## Identified Bugs & Issues

### Bug #1: No Error Handling in Print Service
**Location**: `PrintService/Services/PrintExecutionService.cs`, `RawPrinterHelper.cs`

**Issue**:
- `PrintExecutionService.Print()` doesn't catch exceptions
- `RawPrinterHelper.SendStringToPrinter()` doesn't check P/Invoke return values
- Errors bubble up and may cause 500 response, but no detailed error message

**Impact**:
- Frontend receives generic error
- No way to diagnose printer-specific issues
- Silent failures if printer is offline/busy

**Debug Steps**:
1. Check Print Service logs (Windows Event Viewer)
2. Check if printer name matches exactly (case-sensitive)
3. Verify printer is online and not in use
4. Test with simple ZPL: `^XA^FO50,50^A0N50,50^FDTest^FS^XZ`

---

### Bug #2: Response Structure Mismatch
**Location**: Frontend ZPL response parsing

**Issue**:
- Backend may return: `{ data: { zplData, ... } }`
- Frontend checks multiple paths: `response?.data?.data?.zplData || response?.data?.zplData || response?.zplData`
- Inconsistent response structure causes "No ZPL data received" errors

**Impact**:
- Print fails even when backend returns valid ZPL
- Hard to debug which path is correct

**Debug Steps**:
1. Log full response in browser console
2. Check Network tab for actual response structure
3. Verify backend controller returns consistent format
4. Add response validation in frontend

---

### Bug #3: Printer Name Mismatch
**Location**: Frontend printer selection vs Print Service printer names

**Issue**:
- Frontend stores `selectedPrinterName` from printer list
- Print Service may return different name format
- Windows printer names are case-sensitive in some contexts
- Printer may be renamed in Windows after frontend cached the name

**Impact**:
- `OpenPrinter` fails with "printer not found"
- Print fails silently or with generic error

**Debug Steps**:
1. Compare printer name in frontend vs Windows Printers & Scanners
2. Check Print Service `/printers` response for exact name
3. Verify printer name is sent correctly in print request
4. Test with exact printer name from Windows

---

### Bug #4: DPI Mismatch
**Location**: Frontend DPI detection vs actual printer DPI

**Issue**:
- Print Service may detect wrong DPI (defaults to 203)
- Frontend uses detected DPI for ZPL generation
- If DPI is wrong, label elements will be wrong size
- Text may be too small/large, QR code may not fit

**Impact**:
- Labels print but are incorrectly sized
- Text may be cut off or too small to read
- QR code may not scan

**Debug Steps**:
1. Check printer DPI in Print Service response
2. Verify printer DPI in Windows printer properties
3. Test with known DPI (203, 300, 600)
4. Compare label output with expected size

---

### Bug #5: Port Detection Failure
**Location**: `PrintService/Services/PrinterDiscoveryService.cs`

**Issue**:
- `GetPrinterPort()` uses reflection to get `PortName`
- May return empty string if property not accessible
- Frontend may send empty `printerPort` to Print Service
- Print Service doesn't use port, but frontend expects it

**Impact**:
- Port information missing in frontend
- May cause issues if port-based printing is added later

**Debug Steps**:
1. Check Print Service response for `port` field
2. Verify port in Windows printer properties
3. Test with manual port specification (USB001, LPT1, etc.)

---

### Bug #6: No Print Job Status
**Location**: Print Service `/print` endpoint

**Issue**:
- Print Service returns `{ success: true }` immediately
- Doesn't verify print job actually started
- Doesn't check if printer accepted the data
- No way to query print job status

**Impact**:
- Frontend shows "success" but label may not print
- No way to verify print job completed
- Silent failures if printer rejects ZPL

**Debug Steps**:
1. Check Windows Print Queue for print job
2. Verify printer status (online, paper loaded, etc.)
3. Test with known-good ZPL
4. Check printer error lights/display

---

### Bug #7: Timeout Too Short
**Location**: Frontend `printerClient.js`

**Issue**:
- 30-second timeout for print request
- USB printers may take longer to process
- Network printers may have latency
- Timeout causes error even if print succeeds

**Impact**:
- Print may succeed but frontend shows error
- User may retry, causing duplicate prints

**Debug Steps**:
1. Monitor print request duration in Network tab
2. Check if print actually succeeded despite timeout
3. Test with different printer types (USB vs network)
4. Increase timeout if needed

---

### Bug #8: ZPL Validation Missing
**Location**: Backend ZPL generation, Print Service

**Issue**:
- No validation that ZPL is well-formed
- No check that ZPL commands are valid
- No verification that dimensions fit label size
- Invalid ZPL may cause printer errors

**Impact**:
- Printer may reject invalid ZPL
- No error message to user
- Hard to debug ZPL issues

**Debug Steps**:
1. Validate ZPL syntax before sending
2. Check ZPL in browser console before print
3. Test ZPL with Zebra printer emulator
4. Verify ZPL commands are correct for printer model

---

## Debugging Steps by Symptom

### Symptom: "Cannot connect to print service"
**Possible Causes**:
1. Print Service not running
2. Wrong service URL
3. Firewall blocking port 9101
4. CORS issue

**Debug Steps**:
1. Check if Print Service is running: `sc query "XYZ Print Service"`
2. Test service directly: `curl http://127.0.0.1:9101/health`
3. Check service logs in Windows Event Viewer
4. Verify `NEXT_PUBLIC_PRINT_SERVICE_URL` in frontend
5. Check browser console for CORS errors
6. Test with Postman/curl to isolate frontend vs service issue

---

### Symptom: "No printers found"
**Possible Causes**:
1. No printers installed in Windows
2. Print Service can't detect printers
3. Service running under account that cannot see user-installed printers
4. Using Remote Desktop / redirected printers confusing discovery

**Debug Steps**:
1. On the Windows machine, open **Control Panel → Devices and Printers** and confirm at least one label printer is installed and not greyed out.
2. Call the printers endpoint directly: `curl http://127.0.0.1:9101/printers` and inspect the JSON:
   - If `printers: []`, the service truly cannot see any printers.
   - If you see printers here but **not** in the frontend, suspect CORS, network, or API key issues.
3. Confirm the Windows service is not running under a restricted account:
   - Open **Services.msc** → `XYZ POS Print Service` → **Log On** tab.
   - If running as **Local System**, test changing to a user account that can print, or vice versa (depending on your environment).
4. If using Remote Desktop:
   - Temporarily disable redirected printers for that RDP session and reconnect.
   - Re-run `/printers` and see if the list stabilizes.
5. Check Event Viewer (Application log) for exceptions thrown inside `PrinterDiscoveryService.GetPrinters()`.
6. As a last resort, install a **test generic text printer** in Windows and see if it appears in `/printers`.

---

### Symptom: "Label prints but wrong size / layout"
**Possible Causes**:
1. DPI mismatch between backend ZPL generation and physical printer.
2. Label dimensions (2.5" x 5") do not match actual label stock.
3. Printer is configured with a different label size / print width in driver settings.
4. Printer is auto‑scaling or rotating labels due to internal configuration.

**Debug Steps**:
1. In the browser devtools Network tab, open the `.../zpl` response and copy the ZPL.
2. Inspect the ZPL for:
   - `^PW` (print width) and `^LL` (label length) values.
   - Confirm they match `5"` width and `2.5"` height converted to dots using the printer DPI.
3. In Windows printer properties:
   - Check **Printing Preferences → Stock / Paper size** and verify label size.
   - Ensure the printer is set to **no scaling** and correct orientation.
4. Temporarily override DPI:
   - Force 203, then 300, then 600 in the query params when fetching ZPL.
   - Compare which output matches the physical label.
5. If labels are rotated, check if the printer driver is set to **landscape vs portrait** and if ZPL assumes a specific orientation.

---

### Symptom: "No label prints, but frontend shows success"
**Possible Causes**:
1. Print Service returns `{ success: true }` without verifying job status (Bug #6).
2. Printer rejects invalid ZPL but does not propagate error.
3. Printer is paused, offline, or out of media.
4. Data is being sent to a different printer than expected.

**Debug Steps**:
1. Immediately after a "successful" print:
   - Open the **Windows print queue** for the target printer.
   - Check if a new job appears and whether it errors or completes.
2. Confirm the printer name in:
   - Frontend request body (`printerName`).
   - `/printers` response from the Print Service.
   - Windows printer list.
3. Copy the ZPL to a **Zebra test utility** or emulator and verify it renders.
4. Temporarily configure the printer to **print a config page** to confirm it's online and not in an error state.
5. If possible, switch to another known‑good printer and repeat the test to isolate printer‑specific issues.

---

### Symptom: "Print works from Windows apps but not from POS"
**Possible Causes**:
1. Wrong printer name or case mismatch in the POS.
2. POS is pointing to `127.0.0.1` but the browser is running on a different machine than the Print Service.
3. API key mismatch between frontend and Print Service.
4. Firewall or antivirus blocking HTTP traffic to `127.0.0.1:9101`.

**Debug Steps**:
1. From the same browser machine, run:
   - `curl http://127.0.0.1:9101/health`
   - `curl http://127.0.0.1:9101/printers`
   and confirm both succeed.
2. In the browser devtools, inspect the POST `/print` request:
   - Check headers include `X-Print-Agent-Key` with expected value.
   - Check the response status code (200 vs 401/403/500).
3. Open `PrintService/Security/ApiKeyMiddleware.cs` and confirm the expected API key matches:
   - The hard‑coded default (e.g. `xyz-pos-local-token`).
   - Or any overridden configuration.
4. Check Windows Defender / antivirus logs for blocked local HTTP connections.
5. Test from another simple client (Postman) on the same machine to remove the browser from the equation.

---

### Symptom: "Intermittent printing failures"
**Possible Causes**:
1. USB connection is flaky (loose cable, bad hub).
2. Printer is entering a temporary error state (overheating, label gap detection).
3. Race conditions due to multiple simultaneous print jobs.
4. Network glitches for network‑attached printers.

**Debug Steps**:
1. Correlate timestamps:
   - Frontend error times.
   - Print Service logs / Windows Event Viewer.
   - Printer panel / error lights.
2. Reduce the system to a minimal test:
   - Single printer, direct USB (no hubs).
   - Single browser session printing a simple test label.
3. Increase logging level in the Print Service (if available) and capture detailed logs for a failing run.
4. If using a network printer, ping it continuously while printing (`ping <printer-ip>`) to see if packet loss spikes during failures.
5. Try spacing print jobs (e.g. 5–10 seconds apart) to see if the issue correlates with high throughput.

---

## End‑to‑End Manual Test Checklist

Use this checklist when validating the entire label printing stack after changes or deployments.

- **Environment sanity**
  - **Verify**: Print Service installed and running as Windows service.
  - **Verify**: At least one label printer installed and prints a Windows test page.
  - **Verify**: `curl http://127.0.0.1:9101/health` returns status `ok`.

- **Printer discovery**
  - **Verify**: `curl http://127.0.0.1:9101/printers` lists expected printer(s) with correct names and DPI.
  - **Verify**: `PrinterSelect` dropdown shows the same printers.
  - **Verify**: Selecting a printer in `PrinterSelect` updates the selection state (and is passed into `usePrintLabel`).

- **ZPL generation**
  - **Verify**: Hitting `GET /api/label-printing/products/:id/zpl` returns a 200 with `zplData`.
  - **Verify**: Hitting `GET /api/label-printing/inventory-items/:id/zpl` works for a real FG inventory item.
  - **Verify**: ZPL contains correct product name and UID.

- **Client‑side print path**
  - **Verify**: From the Label Printing UI, printing a **test product** produces a correctly sized label.
  - **Verify**: Inventory item label printing works from the inventory list page.
  - **Verify**: Reprint flows (GRN / Production order) can print labels for existing items.

- **Failure handling**
  - **Verify**: Stopping the Print Service results in clear "Cannot connect to print service" messages in the UI.
  - **Verify**: Unplugging the printer while service is running results in a visible error (not silent success).
  - **Verify**: Attempting to print a label for a non‑FG product shows a clear validation error.

---

## What to Capture When Reporting a Printer Bug

When a label print does **not** behave as expected, capture the following to make debugging fast and deterministic:

- **High‑level description**
  - **What you expected** vs **what actually happened**.
  - Whether **any** labels printed, and if so, how they were wrong (size, content, duplicates, etc.).

- **Environment details**
  - Windows version, printer model, connection type (USB / network).
  - Whether you are on the same machine as the Print Service, or accessing it remotely.

- **Logs & network traces**
  - Browser console logs (errors from `printerClient.js` / `usePrintLabel`).
  - Network tab entries for:
    - `/api/label-printing/.../zpl`
    - `http://127.0.0.1:9101/printers`
    - `http://127.0.0.1:9101/print`
  - Response bodies and status codes for these requests.
  - Any entries in Windows Event Viewer related to `XYZ POS Print Service`.

- **Raw ZPL sample**
  - Copy the exact ZPL string that was sent to the printer.
  - Note which DPI and label size options were used.

- **Reproduction steps**
  - Exact clicks / inputs in the UI (page, product or inventory item, buttons pressed).
  - Whether the issue reproduces 100% of the time or only intermittently.

Having this information allows you (or anyone else) to quickly pinpoint whether the bug is:

- In the **frontend** (selection, request building, error handling),
- In the **backend** (ZPL generation, data validation), or
- In the **Print Service / printer** layer (printer discovery, raw printing, environment).
