feat(cropper): move the Image Cropper into the tools app at /cropper

- Smart Photo Editor ported from id-image-bot: queue/by-ID picture
  loading, vue-croppa editing, carvekit background cleanup, nodered
  review flow, a2loft save — restyled to the tools design language
- unified login: YOUreka session identity, phone prefilled, OTP only at
  save (a2loft's requirement); artist-login step removed
- crop_image @ domain:idid OpenFGA gate on every cropper route: cached
  5-min on reads, live on save, fail closed
- credentials (minio/azure/nodered/carvekit) via env, sole exception to
  hardcoded config; 503 when unconfigured; native FormData replaces
  form-data; new deps minio + azure-storage
- 10 new tests (35 total) with fake minio/queue/nodered/removebg/a2loft
This commit is contained in:
2026-10-01 01:13:30 +01:00
parent 531c419e32
commit d689434047
13 changed files with 2496 additions and 21 deletions
+25 -1
View File
@@ -64,15 +64,39 @@ Everything is hardcoded in `tools/server.js` by design — port `4173`, portal
catalog. Change them there; there are no environment variables or config
files.
## The Image Cropper
The `/cropper` page (Smart Photo Editor) lets operators review, crop and save
identity photos. It reuses the YOUreka session for identity, requires the
`crop_image` permission on `domain:idid` for every proxied action (verified
against the portal's OpenFGA endpoint — live on save, 5-minute cached on
reads), and keeps the a2loft OTP requirement only on the save step.
Its service credentials are the sole environment variables this app uses
(same names the old `id-image-bot` used — an existing `.env` is drop-in):
```sh
MINIO_ACCESS_KEY=… MINIO_SECRET_KEY=…
AZURE_STORAGE_CONNECTION_STRING=…
NODERED_HTTP_USERNAME=… NODERED_HTTP_PASSWORD=…
CARVEKIT_API_KEY=…
```
Without them the rest of the app works and `/cropper` routes answer `503`.
Run locally with `cp tools/.env.example tools/.env` + your values and
`node --env-file=tools/.env tools/server.js` (or `docker run --env-file …`).
## Tests
```sh
cd tools
npm test # node --test — 27 tests, no network or hardware required
npm test # node --test — 35 tests, no network or hardware required
```
## Docker
## Docker
The app is stateless, so the container only serves the web front-end; fpagent
keeps running on the operator's laptop (the wizard connects to
`http://127.0.0.1:9000` from the browser, wherever this container lives).