Submit customer identity proofs and show reviewed limits

This commit is contained in:
Stephan D committed 2026-10-15 02:22:28 +02:00
1 parent 7bf8b8087a
commit 1354551ae8
50 files changed
+1777 -67

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
# Customer identity verification
Task [SXCHNGE #48](https://git.sendico.io/tech/sxchnge/issues/48), following
[sign-up Facts intake](signup-facts.md). Platform implementation:
[Sendico #2885](https://git.sendico.io/tech/sendico/issues/2885).
## Customer flow
Sign-up still creates a basic account and submits its initial name/email/customer
reference as immutable facts. Email verification and login remain independent of
identity proof collection. After the first authenticated login in an app session,
an unverified customer is offered verification and can choose **Keep basic
limits**. An unavailable optional identity dependency does not prevent login.
**Accounts → Identity verification**, **Limits**, and the existing identity
navigation let the customer return later.
The customer supplies their full legal name, date of birth (YYYY-MM-DD), country
of residence, an ID document photo and a selfie holding that same document. The
backend supplies the authenticated customer's email and reference. The client
cannot choose a platform subject, organization, source principal, review status
or limits profile. JPEG/PNG photos must decode, be at least 600×600, at most
40 megapixels and no larger than 10 MiB each. Sendico also enforces its existing
configured evidence cap, MIME/extension rules and submission rate limits.
Unsent fields and photos stay in memory, survive retryable errors and are cleared
on successful submission, discard or page disposal. Previews leave Flutter's
image cache on exit/replacement. Profile edits or photo replacements create a
new request key; unchanged retries retain their key. Draft loss requires an
explicit discard choice. No sensitive extras enter browser history or analytics.
A successful submission means **pending staff review**. Corrections permit a new
submission; rejection retains basic access and the existing support route. A
recorded approval with an unfinished limits assignment is shown as **Limits
upgrade pending**, rather than verified. Refresh fetches the real reviewed state
and the authoritative limits. Production uses no simulated KYC review controls
or illustrative limit amounts. Demo mode remains separately simulated.
## Boundaries and contracts
The authenticated local routes are `GET/POST /accounts/identity` and
`GET /accounts/limits`, under the configured API mount. Multipart POST fields are
`profile` (JSON), `document`, `selfie`, and `idempotencyKey`. A customer ID is
always resolved from the full authenticated session. Pending-login tokens do not
provide account access. Browser and native requests both carry the access token;
browser refresh cookies remain an auth concern.
The existing `signup_facts` binding resolves each local customer to one independent
Sendico subject. A conditional unique `(namespace, subjectRef)` index prevents
binding the same provider subject to two customers. Empty registration claims
are excluded. Existing duplicates cause bootstrap to fail and require controlled
reconciliation; the application never guesses a replacement subject. Credential
rotation must retain the configured source account.
The Sendico adapter exclusively uses public HTTP:
- `GET/POST /identity_facts/{organization}/proofs/{subject}`;
- `GET /identity_facts/{organization}/proofs/{subject}/limits`.
Adapter DTOs and mappers remain separate from local models and local HTTP DTOs.
There are no Sendico database, gRPC, bus or sibling-module imports in SXCHNGE.
Provider organization/source settings remain in the adapter configuration.
Uploads have a bounded 60-second upstream timeout and redirects are rejected.
Upstream error bodies and photo bytes are never logged. Rate-limit responses
retain typed recovery. Registration's existing non-idempotent reconciliation
rules are unchanged.
Visible policy entries retain exact decimal strings, currency, group labels and
per-operation minimum/maximum, day and month slots. Usage is not invented for
per-operation slots. The backend owns the effective policy and remaining
capacity. The existing wallet remains a simulated service; this contribution
connects identity and visible limits, not real money movement. Future money
adapters must use the platform-owned customer account resource and authoritative
Limits reservation path, not a browser-selected policy or displayed balance.
## Review and rollout
Staff work in the existing **Sendico backoffice → KYC → Identity proof review**.
The platform stores private proofs, immutable profile assertions, review history
and the reviewed limits assignment. See the platform's
`docs/customer-identity-proofs.md` for authorization, retry and retention details.
Deploy Sendico Product/provider, Backoffice, Limits and backoffice frontend
changes together before enabling the new SXCHNGE frontend/backend adapters.
Existing `api.sendico` settings are reused. The integration account needs
organization read/update access. The platform's existing evidence/storage,
cleanup, discovery and limits configuration must be provisioned. Its ACCOUNT
default for SXCHNGE must be the existing unverified profile, and the existing
verified profile and personal-account visible view must be active. No new runtime
configuration parameters or live submissions are introduced by this work.
Merge SXCHNGE sign-up Facts PR #47 before this task's branch. Deploy the Sendico
identity-proofs PR before using this flow. The platform change reuses the Limits
assignment contract being developed in Sendico #2884; its PR documents the shared
scope and merge order. No merge or deployment is automatic.
## UX, measurement and validation
Existing KYC journey events measure preparation, selection, accepted submission,
status reads, retries, abandonment and latency. Profile contents, filenames,
photo bytes and credentials are excluded. Submission success is an intake
outcome, not proof of approval. Pending asynchronous staff review is not counted
as customer abandonment. A resumed route starts a new client attempt; immutable
submission IDs deduplicate backend business outcomes.
Authoritative completion is the staff decision plus the Limits assignment
receipt for that submission. Backend IDs correlate these records without becoming
metric labels. Existing identity request counters/histograms distinguish accepted,
invalid, denied, conflict, rate-limited and unavailable operations and include
actual authorization/I/O duration. Client analytics still defaults to the
existing in-memory sink; retained cross-device analytics depends on deployment.
Review covers optional onboarding, later account navigation, editable profile,
readable ID/selfie guidance, disabled actions, error/session recovery, input
preservation, correction/rejection/pending/approval, exact monetary presentation,
EN/RU at narrow widths and large text, keyboard access and private-image cache
eviction. Tests use synthetic data, local HTTP servers and disposable MongoDB.
No live ID documents, live email, production review or deployment were exercised.
Full validation commands and final PR links are recorded in `implementation.md`
and the task.