add Insin integration spec and CLAUDE.md notes

This commit is contained in:
EugeneTes
2026-07-23 07:21:07 +00:00
parent dc9bbbe467
commit 042b9c9633
2 changed files with 351 additions and 0 deletions

View File

@@ -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.