POST
/
api
/
panes
/
{paneNumber}
/
scan
Scan a pane (QR scan endpoint)
curl --request POST \
  --url http://localhost:3000/api/panes/{paneNumber}/scan \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "station": "<string>",
  "operator": "<string>",
  "description": "<string>",
  "remakeStationId": "<string>",
  "laminateSurvivorPaneNumber": "<string>"
}
'
{
  "success": true,
  "message": "<string>",
  "data": {
    "pane": {
      "_id": "<string>",
      "paneNumber": "PNE-0001",
      "qrCode": "STDPLUS:PNE-0001",
      "request": "<string>",
      "order": "<string>",
      "material": "<string>",
      "inventory": "<string>",
      "currentStation": "<string>",
      "currentStatus": "pending",
      "routing": [
        "<string>"
      ],
      "customRouting": false,
      "dimensions": {
        "width": 1,
        "height": 1,
        "thickness": 1
      },
      "jobType": "<string>",
      "rawGlass": {
        "glassType": "<string>",
        "color": "<string>",
        "thickness": 123,
        "sheetsPerPane": 1
      },
      "glassType": "<string>",
      "glassTypeLabel": "<string>",
      "cornerSpec": "<string>",
      "dimensionTolerance": "<string>",
      "holes": [],
      "notches": [],
      "processes": [
        "<string>"
      ],
      "edgeTasks": [
        {
          "side": "<string>",
          "edgeProfile": "<string>",
          "machineType": "<string>",
          "status": "pending"
        }
      ],
      "withdrawal": "<string>",
      "remakeOf": "<string>",
      "mergedInto": "<string>",
      "laminateMergedAt": "2023-11-07T05:31:56Z",
      "laminateRole": "single",
      "parentPane": "<string>",
      "childPanes": [
        "<string>"
      ],
      "sheetLabel": "<string>",
      "laminateStation": "<string>",
      "startedAt": "2023-11-07T05:31:56Z",
      "completedAt": "2023-11-07T05:31:56Z",
      "deliveredAt": "2023-11-07T05:31:56Z",
      "createdAt": "2023-11-07T05:31:56Z",
      "updatedAt": "2023-11-07T05:31:56Z"
    },
    "log": {
      "_id": "<string>",
      "pane": "<string>",
      "order": "<string>",
      "material": "<string>",
      "worker": "<string>",
      "station": "<string>",
      "reason": "<string>",
      "description": "<string>",
      "completedAt": "2023-11-07T05:31:56Z",
      "createdAt": "2023-11-07T05:31:56Z",
      "updatedAt": "2023-11-07T05:31:56Z"
    },
    "nextStation": "<string>",
    "mergedSheets": 123,
    "survivorPaneNumber": "<string>",
    "retiredPaneNumbers": [
      "<string>"
    ],
    "parentRetired": true,
    "remadePane": {
      "_id": "<string>",
      "paneNumber": "PNE-0001",
      "qrCode": "STDPLUS:PNE-0001",
      "request": "<string>",
      "order": "<string>",
      "material": "<string>",
      "inventory": "<string>",
      "currentStation": "<string>",
      "currentStatus": "pending",
      "routing": [
        "<string>"
      ],
      "customRouting": false,
      "dimensions": {
        "width": 1,
        "height": 1,
        "thickness": 1
      },
      "jobType": "<string>",
      "rawGlass": {
        "glassType": "<string>",
        "color": "<string>",
        "thickness": 123,
        "sheetsPerPane": 1
      },
      "glassType": "<string>",
      "glassTypeLabel": "<string>",
      "cornerSpec": "<string>",
      "dimensionTolerance": "<string>",
      "holes": [],
      "notches": [],
      "processes": [
        "<string>"
      ],
      "edgeTasks": [
        {
          "side": "<string>",
          "edgeProfile": "<string>",
          "machineType": "<string>",
          "status": "pending"
        }
      ],
      "withdrawal": "<string>",
      "remakeOf": "<string>",
      "mergedInto": "<string>",
      "laminateMergedAt": "2023-11-07T05:31:56Z",
      "laminateRole": "single",
      "parentPane": "<string>",
      "childPanes": [
        "<string>"
      ],
      "sheetLabel": "<string>",
      "laminateStation": "<string>",
      "startedAt": "2023-11-07T05:31:56Z",
      "completedAt": "2023-11-07T05:31:56Z",
      "deliveredAt": "2023-11-07T05:31:56Z",
      "createdAt": "2023-11-07T05:31:56Z",
      "updatedAt": "2023-11-07T05:31:56Z"
    }
  }
}

Summary

POST /api/panes/{paneNumber}/scan drives the production line. Send the station ObjectId and action. The pane number in the path is the code from the QR label (without the STDPLUS: prefix).
ActionTypical use
scan_in, start, completeNormal station workflow
scan_outHand off after complete (awaiting_scan_out → next station or completed)
qc_passSame as scan_out, but logs qc_pass on PaneLog for QC audit
qc_failMark pane defected, log reason / description, return remadePane (auto remake)
laminateMerge sheets at lamination; sheet QR in path recommended; optional laminateSurvivorPaneNumber; parent path requires that field

QC fail body

{
  "station": "<qc-station-id>",
  "action": "qc_fail",
  "reason": "scratch",
  "description": "Optional free text",
  "remakeStationId": "<optional-station-id>"
}
reason (required): broken | chipped | dimension_wrong | scratch | stain | other.

Laminate merge body

Use a sheet pane number in the path (recommended). Optional laminateSurvivorPaneNumber selects which sheet survives if it differs from the URL pane. If the path is the dormant parent pane number, laminateSurvivorPaneNumber is required (must match an active sheet at the lam station).
{
  "station": "<lamination-station-id>",
  "action": "laminate",
  "laminateSurvivorPaneNumber": "PNE-0100-B"
}
Omit laminateSurvivorPaneNumber when the survivor is the same as the pane in the URL.

Dormant parent in the path

If the worker scans the parent row’s number (e.g. for an admin flow), laminateSurvivorPaneNumber is required and must be an active sheet at the lamination station:
{
  "station": "<lamination-station-id>",
  "action": "laminate",
  "laminateSurvivorPaneNumber": "PNE-0100-A"
}

Response (laminate)

On success, data includes:
  • pane — the survivor pane (laminateRole: "single", post-lam routing, awaiting_scan_out at lamination, laminateMergedAt set)
  • mergedSheets — count of sheets in the merge
  • survivorPaneNumber, retiredPaneNumbers, parentRetired

Response (QC fail)

On success, data includes:
  • pane — the defected pane (currentStatus: "defected")
  • log — the new PaneLog (action: "qc_fail", reason, description)
  • remadePane — the new pane queued for production (remakeOf points at the defected pane)
For other actions, the shape matches the OpenAPI ScanResult schema (nextStation after scan_out / qc_pass when applicable).

Scan errors (merged_into)

If a worker scans a pane that was retired by laminate merge (currentStatus: merged_into), the API returns 400 with errors.code: MERGED_INTO, errors.survivorPaneNumber, and a Thai message pointing at the survivor QR. The List all panes endpoint omits merged_into rows by default so station UIs stay clean.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path Parameters

paneNumber
string
required

The pane number (e.g. PNE-0001). Strip the STDPLUS: prefix from QR codes before sending.

Body

application/json
station
string
required

Station ObjectId where the scan is happening (must match the pane's currentStation)

Minimum string length: 1
action
enum<string>
required

scan_in — acknowledge arrival, start — begin work, complete — mark work done (awaiting_scan_out), scan_out / qc_pass — advance to next routing station or complete if last (same rules; QC pass logs qc_pass), qc_fail — mark pane defected, log reason/description, auto-create remake pane (requires reason), laminate — merge sheets; one sheet survives (see laminateSurvivorPaneNumber)

Available options:
scan_in,
start,
complete,
scan_out,
laminate,
qc_pass,
qc_fail
operator
string

Worker ID. Accepted by validation but currently unused — the authenticated user (req.user._id) is always recorded as the worker in the PaneLog.

Minimum string length: 1
reason
enum<string>

Required when action is qc_fail

Available options:
broken,
chipped,
dimension_wrong,
scratch,
stain,
other
description
string

Optional extra detail for qc_fail

remakeStationId
string

Optional station ObjectId to queue the auto-created remake pane; defaults to first station in routing

Minimum string length: 1
laminateSurvivorPaneNumber
string

For laminate: which sheet pane number survives (defaults to pane in URL if URL is a sheet). Required if URL is the dormant parent pane.

Minimum string length: 1

Response

Scan processed successfully

success
boolean
Example:

true

message
string
data
object