Opening a shop is an API call; the broker learns of it in the same request
The last step of onboarding that needed a shell: provision site printed a broker password and a person typed it into Mosquitto's passwd file on the host - mounted read-only in the container, so the first attempt failed silently and the password was re-rolled. No tenant could open a second branch without us. The server now drives Mosquitto's dynamic-security plugin over its own broker login: POST /api/sites (owner) writes the row and the sealed password, registers the login and a per-site role with literal topics (the 2.0 plugin does not substitute %u - measured), and removes the row again if the broker refuses, so a shop cannot exist in the database and not on the broker. provision site goes through the same path. The head-office Shops screen gets 'Open a new shop'. broker-init converts the existing passwd file into the plugin's store with every hash intact - PBKDF2-SHA512 both sides - so the cutover re-claims no shop PC. Rehearsed locally: old logins keep working, isolation holds, the health probe works, and a PC claiming a shop opened through the API connects as that shop. run-local.sh now brings the broker up the same way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
This commit is contained in:
29
API.md
29
API.md
@@ -49,6 +49,7 @@ user; the tenant is always taken from the session and never from the request.
|
||||
| `DELETE /api/visitors/{id}` — erasure | manager |
|
||||
| `GET /api/sites` · `GET /api/sites/{site}/check` · `GET /api/cameras` · `GET /api/cameras/{id}/snapshot.jpg` · `GET /api/cameras/{id}/live` | authed |
|
||||
| `POST /api/sites/{site}/cameras` · `PATCH` / `DELETE /api/cameras/{id}` · `POST /api/cameras/{id}/check` | manager |
|
||||
| `POST /api/sites` — open a shop | owner |
|
||||
| `POST /api/sites/{site}/enrolment-code` | manager |
|
||||
| `GET /api/team` | authed (tenant users only) |
|
||||
| `POST /api/team/members` · `POST /api/team/{id}/password` · `PATCH /api/team/{id}` · `/api/team/invitations*` | manager |
|
||||
@@ -164,9 +165,9 @@ PATCH /api/team/{id} { "role": "manager" } → promote
|
||||
PATCH /api/team/{id} { "active": false } → they have left; signs them out now
|
||||
```
|
||||
|
||||
The owner also sets the shop up from the same login — `POST
|
||||
/api/sites/{site}/enrolment-code` for the shop PC, `POST
|
||||
/api/sites/{site}/cameras` for cameras — see §8.
|
||||
The owner also opens shops and sets them up from the same login — `POST
|
||||
/api/sites` to open one, `POST /api/sites/{site}/enrolment-code` for its
|
||||
shop PC, `POST /api/sites/{site}/cameras` for cameras — see §8.
|
||||
|
||||
### Tier 3 — the salesperson gets their mobile login
|
||||
|
||||
@@ -718,6 +719,28 @@ unplugged PC.
|
||||
footfall lost because that queue overflowed. Non-zero `dropped` is a report
|
||||
that is wrong in a way the report itself cannot show.
|
||||
|
||||
### `POST /api/sites` — open a shop (owner)
|
||||
|
||||
```
|
||||
{ "name": "TeNext Bengaluru", "slug": "bengaluru", "timezone": "Asia/Kolkata" }
|
||||
→ 201 { "site_id": "…", "slug": "bengaluru", "name": "TeNext Bengaluru",
|
||||
"timezone": "Asia/Kolkata", "broker_username": "tenext-retail.bengaluru" }
|
||||
```
|
||||
|
||||
`slug` and `timezone` are optional: the slug is made from the name (lower-case,
|
||||
digits and dashes, 3–32 characters) and the timezone defaults to Asia/Kolkata.
|
||||
The slug is the shop PC's identity and an MQTT topic segment; it **cannot be
|
||||
changed afterwards**. The server registers the shop's broker login with
|
||||
Mosquitto in the same request, so the next step is simply
|
||||
`POST /api/sites/{slug}/enrolment-code` for the PC.
|
||||
|
||||
| status | code | meaning |
|
||||
|---|---|---|
|
||||
| 403 | `forbidden` | not the owner |
|
||||
| 409 | `conflict` | a shop with that slug exists |
|
||||
| 502 | `broker_unavailable` | the broker did not accept the login; **nothing was created** — try again |
|
||||
| 503 | `broker_unavailable` / `no_encryption_key` | this server cannot create shops; contact support |
|
||||
|
||||
### `GET /api/sites/{site}/check`
|
||||
|
||||
Five ordered steps that answer *is this shop working*, assembled from what head
|
||||
|
||||
Reference in New Issue
Block a user