docs(openspec): move-image-cropper change — specs synced, change archived
image-cropper capability added; tools-app landing + config requirements updated (internal /cropper link, credentials-via-env carve-out).
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Design
|
||||
|
||||
## Context
|
||||
|
||||
`id-image-bot` is three things: a Telegram intake bot (handlers disabled in
|
||||
code), a picture-review pipeline (Azure queue `id-images`, Minio `files`
|
||||
bucket, nodered review/process endpoints), and the operator web tool ("Smart
|
||||
Photo Editor": Vue 2 + vue-croppa, phone/OTP login against a2loft). Only the
|
||||
web tool moves; the bot and its deployment stay. The a2loft save route
|
||||
(`POST /:domainCode/profile/picture`) accepts only `?phone=&otp=` — no key
|
||||
variant — so the operator OTP survives, but only at save time. See proposal.md
|
||||
for motivation.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- One login story: YOUreka session everywhere; the cropper adds only a
|
||||
save-time OTP (a2loft's requirement).
|
||||
- Uniform `crop_image` authorization over every proxied cropper endpoint,
|
||||
cheap for the portal (read cache, live at save).
|
||||
- Faithful behavior: same queue/review/nodered flows and review-reason list.
|
||||
|
||||
**Non-Goals:**
|
||||
- Moving the Telegram bot; decommissioning `spxa.yrka.app`.
|
||||
- Changing the review/reject workflow or the review-reason catalog.
|
||||
- Replacing toastr/swal UX patterns wholesale.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **Namespaced router, `tools/cropper.js` with DI.** `createCropperRouter({
|
||||
minio, queue, fetch, requireApi, cropGate, a2loftBase, ... })` — the same
|
||||
injectable pattern as the app factory, so tests fake minio/queue/upstreams.
|
||||
Mounted at `/cropper` in server.js; the UI uses relative request paths.
|
||||
2. **Unified login.** The bot app's phone+OTP middleware validated every
|
||||
request; here the YOUreka session replaces it, and the one a2loft call that
|
||||
needs an OTP (picture save) takes an operator-entered OTP forwarded with the
|
||||
session phone and the picture's domain. Phone prefill from `/auth/session`.
|
||||
3. **`crop_image` gate with read cache.** `permit.js` grows `cropPermission(
|
||||
phone, {force})` beside the domain checker: same verifyOnce plumbing,
|
||||
`relation: 'crop_image'`, object `domain:idid`, no fallback; results cached
|
||||
per phone for 5 minutes, save forces live. Router-level middleware covers
|
||||
every cropper route uniformly.
|
||||
4. **Credentials via env, URLs hardcoded.** `MINIO_ACCESS_KEY`,
|
||||
`MINIO_SECRET_KEY`, `AZURE_STORAGE_CONNECTION_STRING`,
|
||||
`NODERED_HTTP_USERNAME`, `NODERED_HTTP_PASSWORD`, `CARVEKIT_API_KEY` — same
|
||||
names the bot app used, so an existing `.env` is drop-in. Clients are built
|
||||
only when the env is present; without it the router answers 503 and the
|
||||
rest of the app is unaffected.
|
||||
5. **Restyle to the tools design language.** Same stylesheet and panel
|
||||
structure as `/fingerprint` (navbar, step chips, badges, buttons); toastr
|
||||
stays for toasts. No behavior change beyond namespacing and auth.
|
||||
6. **Native `FormData`** (Node 22) replaces the `form-data` dependency for the
|
||||
cleanup proxy.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [a2loft `validateOtp` may not recognize the YOUreka session phone format] →
|
||||
the fingerprint walkthrough already saw a2loft accept the session phone on
|
||||
lookups; the field pass confirms on the save path before cutover.
|
||||
- [Cached crop gate lets a revoked operator act for ≤5 minutes] → reads only;
|
||||
the save verifies live, and a2loft's OTP check remains the hard gate.
|
||||
- [Review/process endpoints depend on nodered availability] → unchanged from
|
||||
the bot app; failures surface as route errors, not crashes.
|
||||
- [Two auth domains (mnet/ucth) disappear from the login] → the save validates
|
||||
against the picture's domain; the field pass exercises a real item.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Land the cropper in `tools/` while `id-image-bot` keeps running unchanged.
|
||||
2. Field pass: login → gate → load a real queued item (or by ID) → crop →
|
||||
clean → save with OTP; confirm the picture lands in a2loft.
|
||||
3. Repoint the landing card (done in the same change); leave `spxa.yrka.app`
|
||||
running until the team confirms the new home.
|
||||
4. Rollback: the old deployment still serves the tool.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None — auth unification, secret handling and scope were confirmed with the
|
||||
operator.
|
||||
Reference in New Issue
Block a user