image-cropper capability added; tools-app landing + config requirements updated (internal /cropper link, credentials-via-env carve-out).
3.9 KiB
3.9 KiB
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_imageauthorization 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
- Namespaced router,
tools/cropper.jswith DI.createCropperRouter({ minio, queue, fetch, requireApi, cropGate, a2loftBase, ... })— the same injectable pattern as the app factory, so tests fake minio/queue/upstreams. Mounted at/cropperin server.js; the UI uses relative request paths. - 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. crop_imagegate with read cache.permit.jsgrowscropPermission( phone, {force})beside the domain checker: same verifyOnce plumbing,relation: 'crop_image', objectdomain:idid, no fallback; results cached per phone for 5 minutes, save forces live. Router-level middleware covers every cropper route uniformly.- 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.envis 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. - 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. - Native
FormData(Node 22) replaces theform-datadependency for the cleanup proxy.
Risks / Trade-offs
- [a2loft
validateOtpmay 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
- Land the cropper in
tools/whileid-image-botkeeps running unchanged. - Field pass: login → gate → load a real queued item (or by ID) → crop → clean → save with OTP; confirm the picture lands in a2loft.
- Repoint the landing card (done in the same change); leave
spxa.yrka.apprunning until the team confirms the new home. - Rollback: the old deployment still serves the tool.
Open Questions
None — auth unification, secret handling and scope were confirmed with the operator.