docs(openspec): archive cropper-token-auth and sync specs

The cropper upload POSTs with the session token and no OTP query auth, and the
panel shows the profile's domain and picture target. Field pass was verified
earlier (upload 0b90075b, saved with no OTP). Merged the image-cropper delta
into the main spec and archived the change.
This commit is contained in:
2026-10-06 19:29:45 +01:00
parent 8a13fb527e
commit 528eaafb18
6 changed files with 18 additions and 9 deletions
@@ -0,0 +1,51 @@
# Design
## Context
See proposal.md. The a2loft `cropper-token-auth` change adds token mode to the
profile-picture endpoints: `Authorization: Bearer <pb token>`, identity from
the token's phone, authorized with OpenFGA `crop_image` on `domain:<code>` then
`domain:idid`. This change consumes it.
## Goals / Non-Goals
**Goals:** the cropper saves with the session token and no OTP; the save's
domain is a2loft's own record of the picture; the panel is truthful about the
profile's domain.
**Non-Goals:** the fingerprint wizard's OTP flow; the cropper's lookup (there
is none — pictures come from the queue); removing OTP support in a2loft.
## Decisions
1. **Token sent from the server**, never exposed to the browser beyond the
page's existing injected session: the proxy attaches
`Authorization: Bearer ${req.session.token}`.
2. **Domain from a2loft, not the client**: `dims/picture/{uploadId}` is the
record of the picture; its `domainCode` is the profile's identity domain and
its `domain` is the picture target (`core`). Sent as `domainCode`, displayed
as both. Falls back to the queue item's label when a2loft has no record
(custom ids), guarded by a path-safety pattern.
3. **The `core → uc` alias is deleted**: `core` is a2loft's own pseudo-domain
(special-cased in `getUserByPhoneAsync`/`updatePicture`), so rewriting it —
as the old bot did for its own calls — changed attribution and the
notification. Authorization no longer depends on the domain, so no alias is
needed.
4. **Queue loads are enriched** with `domainCode` for display (one extra
read-only a2loft call per picture).
## Risks / Trade-offs
- [a2loft record unavailable for an upload] → falls back to the queue label
under the path-safety check; the save still carries the token for authz.
- [Operators outside the domain's super-users] → irrelevant now: the OpenFGA
check with the `domain:idid` fallback authorizes them.
## Migration Plan
Deploy a2loft first (dual-mode, no client change), then this change; the
cropper saves without an OTP. Rollback = revert the proxy and re-add the field.
## Open Questions
None.