add Insin integration spec and CLAUDE.md notes
This commit is contained in:
64
CLAUDE.md
64
CLAUDE.md
@@ -287,3 +287,67 @@ Font magnification is 1-8x for both width and height:
|
||||
- Check RestaurantId and ApiKey in config.txt (base64-encoded)
|
||||
- Verify network connectivity to the API URL
|
||||
- SignalR auto-reconnects with infinite retry; check logs for reconnection attempts
|
||||
|
||||
## Insin Integration
|
||||
|
||||
This service is deployed as an Insin package and emits telemetry via the on-device Insin agent's **local loopback listener**. Env vars `INSIN_URL` and `INSIN_TOKEN` are provided by the deployment environment.
|
||||
|
||||
### Publishing events (local loopback — the path we use)
|
||||
|
||||
Because this service runs on Insin-managed devices where `insin monitor` (the `insin.service` systemd unit) is active, events go to the loopback ingest — **not** a remote HTTP endpoint. The on-device agent persists locally and forwards on the next device heartbeat.
|
||||
|
||||
- **Endpoint:** `POST http://127.0.0.1:47823/events` (loopback-only, no auth).
|
||||
- **Single event payload:** `{"kind": "<subsystem>.<verb>[.<qualifier>]", "message": "<free-form>", "at": "<ISO-8601 UTC>"}`.
|
||||
- **Batch payload:** `{"events": [ {...}, {...} ]}`.
|
||||
- **Event `kind` conventions** for this service:
|
||||
- `job.printed` — successful print, message includes printer + jobId
|
||||
- `job.failed.<reason>` — e.g. `job.failed.paper_out`, `job.failed.cover_open`, `job.failed.connection`
|
||||
- `printer.online` / `printer.offline` — status transitions
|
||||
- `printer.discovered` — new printer found by discovery
|
||||
- **Metrics** use the same shape at `POST /metrics` with `{name, value, unit}` (e.g. `printer.head.temperature`).
|
||||
- Delivery: at-least-once, server ring-trims to ~1000 per device. Admin UI polls every 5s. No rate limiting or 429s; each POST commits to local SQLite before returning 200.
|
||||
- **If `127.0.0.1:47823` is unreachable**, `insin monitor` isn't running — do not swallow this silently in production; log it. In dev, just no-op.
|
||||
- Full reference: `docs/device-telemetry-api.md` in the Insin repo.
|
||||
|
||||
### Deploying / publishing this service as an Insin package
|
||||
|
||||
Insin uses a flat global package namespace with the `AdminToken` auth header (NOT `Bearer`). Publish flow for CI or a release script:
|
||||
|
||||
```bash
|
||||
set -euo pipefail
|
||||
: "${INSIN_URL:?}" "${INSIN_TOKEN:?}"
|
||||
|
||||
# 1. Fetch latest CLI (linux-arm64 shown; use win-x64 on Windows CI).
|
||||
LATEST=$(curl -fsSL "$INSIN_URL/api/v1/downloads/cli" \
|
||||
| python3 -c 'import json,sys; m=json.load(sys.stdin)[0]; a=next(x for x in m["artifacts"] if x["rid"]=="linux-arm64"); print(m["version"], a["filename"])')
|
||||
VERSION=${LATEST% *}; FILENAME=${LATEST#* }
|
||||
curl -fsSL "$INSIN_URL/api/v1/downloads/cli/$VERSION/$FILENAME" -o /tmp/insin.tar.gz
|
||||
mkdir -p /tmp/insin && tar -xzf /tmp/insin.tar.gz -C /tmp/insin
|
||||
chmod +x /tmp/insin/insin
|
||||
|
||||
# 2. Pack. NOTE: pack zips CWD recursively (minus *.pkg) and writes to
|
||||
# ../packages/<name>@<version>.pkg — one directory UP from CWD.
|
||||
# cd into the build output first; don't run from repo root (would bundle .git/).
|
||||
cd EpsonPrintService/bin/Release/net8.0/publish
|
||||
/tmp/insin/insin pack epson-print-service@1.2.3
|
||||
|
||||
# 3. Publish. Reads INSIN_URL + INSIN_TOKEN from env; --url/--token override.
|
||||
/tmp/insin/insin publish ../packages/epson-print-service@1.2.3.pkg
|
||||
```
|
||||
|
||||
Under the hood `publish` = `POST $INSIN_URL/api/v1/admin/packages` (multipart form, field `file`) with header `Authorization: AdminToken $INSIN_TOKEN`.
|
||||
|
||||
### Insin rules & gotchas
|
||||
|
||||
- **Auth header:** `Authorization: AdminToken <token>` — NOT `Bearer`. Same header for master admin token AND service tokens.
|
||||
- **Always use a service token** (minted in admin UI → Service Tokens → New token, plaintext shown once). Never ship the master `INSIN_ADMIN_TOKEN`.
|
||||
- **`INSIN_URL` is a bare origin:** no trailing slash, no `/api` suffix. Just `https://insin.example.com`.
|
||||
- **First publish auto-creates** the package name. No separate registration.
|
||||
- **Versions are immutable.** Re-publishing the same `(name, version)` returns **409 Conflict**. Bump the version.
|
||||
- **Flat global namespace** — no scopes. Pick a distinctive name (we use `epson-print-service`).
|
||||
- **CLI artifacts:** only `linux-arm64` and `win-x64` today. On `linux-x64` CI, run under qemu (`--platform linux/arm64`) — the CLI is just packer + uploader so emulation is fine.
|
||||
- **`insin pack` output is one dir UP** (`../packages/`), not `./`. Look there if the `.pkg` seems missing.
|
||||
- If both `INSIN_ADMIN_TOKEN` and `INSIN_TOKEN` are set, `publish` reads `INSIN_TOKEN` first (service token wins).
|
||||
- **List packages:** `curl -H "Authorization: AdminToken $INSIN_TOKEN" $INSIN_URL/api/v1/admin/packages`.
|
||||
- **Delete a version:** `DELETE /api/v1/admin/packages/{name}/{version}` (same header).
|
||||
- No shared public staging — stand up a scratch instance if you need one.
|
||||
|
||||
Reference in New Issue
Block a user