This commit is contained in:
seb
2026-09-29 11:31:35 +02:00
parent cf4af1480b
commit 0e64233418
5 changed files with 253 additions and 4 deletions

View File

@@ -3,6 +3,7 @@
```
http://localhost:4208/api
https://localhost:8443/api
https://localhost:8443/v1 (POS API)
```
## CORS & cookies
@@ -154,6 +155,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
| [`routes/unit/delete.md`](routes/unit/delete.md) | `DELETE /unit` |
| [`routes/unit/list.md`](routes/unit/list.md) | `GET /unit` |
| [`routes/unit/upsert.md`](routes/unit/upsert.md) | `PUT /unit` |
| [`routes/pos/client.md`](routes/pos/client.md) | `GET /v1/client` |
| [`routes/warehouse/list.md`](routes/warehouse/list.md) | `GET /warehouse` |
| [`routes/warehouse/create.md`](routes/warehouse/create.md) | `POST /warehouse` |
| [`routes/warehouse/order.md`](routes/warehouse/order.md) | `PUT /warehouse/order` |

View File

@@ -8,7 +8,11 @@
"servers": [
{
"url": "http://localhost:4208/api",
"description": "Local default (PORT / .env)"
"description": "Local default HTTP (PORT / .env)"
},
{
"url": "https://localhost:8443",
"description": "Local default HTTPS (HTTPS_PORT / .env)"
}
],
"tags": [
@@ -20,6 +24,10 @@
"name": "Health",
"description": "Connectivity checks"
},
{
"name": "POS",
"description": "POS bind and sync API (/v1)"
},
{
"name": "Events",
"description": "SSE update signals for live clients"
@@ -11932,6 +11940,114 @@
}
}
}
},
"/v1/client": {
"get": {
"tags": [
"POS"
],
"summary": "POS discovery and pairing",
"description": "Special API for POS bind and sync.\n- Step 1 (Discovery): `authCode` length 1–4. Returns certificate fingerprints, serial number, and mandantId.\n- Step 2 (Pairing): `authCode` length 6 (pairingpin from posterminal). Verifies the pairingpin, sets token, paired_at, and clientserial, revokes the pairingpin, and returns device credentials and company metadata.\n",
"security": [],
"x-markdown": "pos/client.md",
"parameters": [
{
"in": "query",
"name": "authCode",
"required": true,
"schema": {
"type": "string"
},
"description": "Discovery code (1-4 digits) or pairing PIN (6 digits)",
"example": "678677"
},
{
"in": "query",
"name": "name",
"required": false,
"schema": {
"type": "string"
},
"description": "Client device name or serial identifier (default 'JTL-POS')",
"example": "Kasse 1"
}
],
"responses": {
"200": {
"description": "Discovery or pairing successful",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"authCode": {
"type": "string",
"nullable": true,
"example": "678677"
},
"authToken": {
"type": "string",
"nullable": true,
"example": "df40ad2067954646abb0499548a52241"
},
"certificateFingerprint": {
"type": "string",
"example": "30DD111E8048B57E6A4FB75AD7E63F7E657F1262"
},
"certificateSerialNumber": {
"type": "string",
"example": "1BB1BD7844451E3AC6"
},
"mandantId": {
"type": "string",
"example": "1"
},
"mandantName": {
"type": "string",
"nullable": true,
"example": "eB-Standard"
},
"mandantDatabase": {
"type": "string",
"nullable": true,
"example": "eazybusiness"
},
"serverFingerprint": {
"type": "string",
"nullable": true,
"example": "30-DD-11-1E-80-48-B5-7E-6A-4F-B7-5A-D7-E6-3F-7E-65-7F-12-62"
},
"name": {
"type": "string",
"nullable": true
},
"serverTimestamp": {
"type": "string",
"example": "2026-09-29 11:00:00"
}
}
}
}
}
},
"400": {
"description": "Invalid or incorrect authentication code",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"Message": {
"type": "string",
"example": "Der Authentifizierungscode ist falsch."
}
}
}
}
}
}
}
}
}
},
"components": {

View File

@@ -0,0 +1,46 @@
# `GET /v1/client`
Public. No cookie required.
POS discovery and pairing
Special API for POS bind and sync.
- Step 1 (Discovery): `authCode` length 1–4. Returns certificate fingerprints, serial number, and mandantId.
- Step 2 (Pairing): `authCode` length 6 (pairingpin from posterminal). Verifies the pairingpin, sets token, paired_at, and clientserial, revokes the pairingpin, and returns device credentials and company metadata.
## Query parameters
| Param | Required | Type | Description |
|-------|----------|------|-------------|
| `authCode` | yes | string | Discovery code (1-4 digits) or pairing PIN (6 digits) |
| `name` | no | string | Client device name or serial identifier (default 'JTL-POS') |
## Response `200`
Discovery or pairing successful
```json
{
"authCode": "678677",
"authToken": "df40ad2067954646abb0499548a52241",
"certificateFingerprint": "30DD111E8048B57E6A4FB75AD7E63F7E657F1262",
"certificateSerialNumber": "1BB1BD7844451E3AC6",
"mandantId": "1",
"mandantName": "eB-Standard",
"mandantDatabase": "eazybusiness",
"serverFingerprint": "30-DD-11-1E-80-48-B5-7E-6A-4F-B7-5A-D7-E6-3F-7E-65-7F-12-62",
"name": "…",
"serverTimestamp": "2026-09-29 11:00:00"
}
```
## Errors
| Status | Description |
|--------|-------------|
| 400 | Invalid or incorrect authentication code |
---
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._

View File

@@ -13,7 +13,7 @@ const root = path.resolve(__dirname, '..');
const docsDir = path.join(root, 'docs', 'api');
const routesDocsDir = path.join(docsDir, 'routes');
const PUBLIC_PATHS = new Set(['/auth/login', '/auth/logout', '/health']);
const PUBLIC_PATHS = new Set(['/auth/login', '/auth/logout', '/health', '/v1/client']);
const options = {
definition: {
@@ -26,10 +26,14 @@ const options = {
'Browser clients must send cookies (`credentials: \'include\'`). ' +
'Sessions use an HTTP-only `token` cookie (`Secure`, `SameSite=Strict`, 24h); HTTPS is required for login.',
},
servers: [{ url: 'http://localhost:4208/api', description: 'Local default (PORT / .env)' }],
servers: [
{ url: 'http://localhost:4208/api', description: 'Local default HTTP (PORT / .env)' },
{ url: 'https://localhost:8443', description: 'Local default HTTPS (HTTPS_PORT / .env)' },
],
tags: [
{ name: 'Auth', description: 'Google SSO and session' },
{ name: 'Health', description: 'Connectivity checks' },
{ name: 'POS', description: 'POS bind and sync API (/v1)' },
{ name: 'Events', description: 'SSE update signals for live clients' },
{ name: 'Article', description: 'Articles under categories' },
{ name: 'Category', description: 'Category tree and membership' },
@@ -55,6 +59,7 @@ const options = {
apis: [
path.join(root, 'src/api/openapi.js'),
path.join(root, 'src/api/routes/**/*.js'),
path.join(root, 'src/v1/**/*.js'),
],
};
@@ -352,6 +357,8 @@ function renderReadme(operations) {
lines.push('');
lines.push('```');
lines.push('http://localhost:4208/api');
lines.push('https://localhost:8443/api');
lines.push('https://localhost:8443/v1 (POS API)');
lines.push('```');
lines.push('');
lines.push('## CORS & cookies');

View File

@@ -56,7 +56,85 @@ export function buildClientStep2(authCode, config) {
}
/**
* Handles GET /v1/client
* @openapi
* /v1/client:
* get:
* tags: [POS]
* summary: POS discovery and pairing
* description: |
* Special API for POS bind and sync.
* - Step 1 (Discovery): `authCode` length 1–4. Returns certificate fingerprints, serial number, and mandantId.
* - Step 2 (Pairing): `authCode` length 6 (pairingpin from posterminal). Verifies the pairingpin, sets token, paired_at, and clientserial, revokes the pairingpin, and returns device credentials and company metadata.
* security: []
* x-markdown: pos/client.md
* parameters:
* - in: query
* name: authCode
* required: true
* schema:
* type: string
* description: Discovery code (1-4 digits) or pairing PIN (6 digits)
* example: "678677"
* - in: query
* name: name
* required: false
* schema:
* type: string
* description: Client device name or serial identifier (default 'JTL-POS')
* example: "Kasse 1"
* responses:
* 200:
* description: Discovery or pairing successful
* content:
* application/json:
* schema:
* type: object
* properties:
* authCode:
* type: string
* nullable: true
* example: "678677"
* authToken:
* type: string
* nullable: true
* example: "df40ad2067954646abb0499548a52241"
* certificateFingerprint:
* type: string
* example: "30DD111E8048B57E6A4FB75AD7E63F7E657F1262"
* certificateSerialNumber:
* type: string
* example: "1BB1BD7844451E3AC6"
* mandantId:
* type: string
* example: "1"
* mandantName:
* type: string
* nullable: true
* example: "eB-Standard"
* mandantDatabase:
* type: string
* nullable: true
* example: "eazybusiness"
* serverFingerprint:
* type: string
* nullable: true
* example: "30-DD-11-1E-80-48-B5-7E-6A-4F-B7-5A-D7-E6-3F-7E-65-7F-12-62"
* name:
* type: string
* nullable: true
* serverTimestamp:
* type: string
* example: "2026-09-29 11:00:00"
* 400:
* description: Invalid or incorrect authentication code
* content:
* application/json:
* schema:
* type: object
* properties:
* Message:
* type: string
* example: "Der Authentifizierungscode ist falsch."
* @param {import('express').Request} req
* @param {import('express').Response} res
*/