Preserve implemented workspace plan while integrating plan history

This commit is contained in:
Stephan D committed 2026-09-12 12:12:50 +02:00
commit 3c56fad4bf
74 files changed
+8040 -271

No files matched your search

+125 -1
View File
@@ -4,7 +4,7 @@
[Task #10](https://git.sendico.io/tech/sxchnge/issues/10), branch `skills-10`,
delivered in [PR #11](https://git.sendico.io/tech/sxchnge/pulls/11) into `main`,
adds a concise root UX policy linking two independent skills in `skills/`:
adds a concise root UX policy linking two independent skills, now consolidated under `.agents/skills/`:
UX Design covers usable interfaces and its design review; UX Observability covers
purposeful journey measurement and its observability review. Both preserve product
conventions and avoid prescribing frameworks, vendors, or visual styles.
@@ -123,6 +123,16 @@ Implementation commit `f1cbf64`; 68 tests and affected-package analysis/formatti
plus web build passed. Final browser verification confirms accessible recipient
text and keyboard recovery. No merge or actual PostHog collection was performed.
## Consolidated skill location
Task [#16](https://git.sendico.io/tech/sxchnge/issues/16) consolidates all four
repository skills under `.agents/skills/`. UX Design and UX Observability moved
without content changes; root policy links and this record now use that location.
The old root `skills/` directory is removed. Validation compares moved content
byte-for-byte, checks all four skill paths and updated UX links, and runs
`git diff --check`. No runtime tests are needed for this move.
Delivery: [PR #17](https://git.sendico.io/tech/sxchnge/pulls/17), branch `skills-16`.
## Editor configuration cleanup
Task [#14](https://git.sendico.io/tech/sxchnge/issues/14) removes the root VS Code
@@ -154,3 +164,117 @@ Documentation only; no runtime tests were run.
implementation should incorporate KYC PR #21 and usage PR #23.
- Validation: documentation links and diff checks; no runtime changes or tests.
- Delivery: [PR #25](https://git.sendico.io/tech/sxchnge/pulls/25), committed and pushed; not merged.
## Optional identity verification and backend-owned limits — task #20
- Branch: `kyc-20`, based on `61ccfc1` (main after README PR #19).
- Planned the UX before implementation in [docs/ux/kyc.md](ux/kyc.md), including
optional basic access, two-photo preparation/review, pending and decision states,
errors, recovery, privacy and measurement definitions.
- Added the mobile-reusable `sxchnge_kyc` package, injectable identity/photo/limits
services, transport mappers and providers. Followed Sendico's visible-limits
ownership boundary; current tier/caps/remaining amounts come from a service.
- Added themed EN/RU `/identity` screens, login/email-confirmation entry points,
route exit guards, review/replace/discard controls, safe error messages and
demo-only backoffice decision controls. No real documents are transmitted.
- Reviewed full frontend scope and corrected web image-metadata validation,
stale-state messaging, cancelled-picker analytics, step focus/scroll behavior,
duplicate submissions and sensitive image cache cleanup.
- Validation: format check for all 27 changed/new Dart files; analyzer passes for
app, sxchnge_kyc and sxchnge_analytics; `make test-frontend` passes **86 tests**
(10 KYC, 7 analytics, 20 auth, 3 theme, 3 consumer example, 43 app). Web build
passes. Actual browser selection of generated PNG samples reached pending
review with unchanged basic limits. EN/RU, 320px/1.6 text scale, accessibility
labels/tap targets, route guards and all decision paths have widget coverage.
- Limits are illustrative backend-stub fixtures. Real authenticated uploads,
private storage, staff review, support, authoritative limits enforcement and
server-side review analytics remain integration work. Native mobile and
VoiceOver/TalkBack checks remain release QA. Security scans were not requested.
- Delivery: [PR #21](https://git.sendico.io/tech/sxchnge/pulls/21), pushed on `kyc-20`; not merged. Final browser review also preserved heading semantics when moving keyboard focus.
## Limits usage display — task #22
- Branch `limits-22`, stacked on `kyc-20` / PR #21 (merge #21 first).
- Added explicit used/committed and reserved fields through DTO, mapper, service
and model. Remaining is independently supplied by the backend stand-in.
- Daily/monthly cards show used, reserved, available, cap and upgrade amounts,
with a labeled theme-based occupied-capacity indicator and exhausted text.
Dummy fixtures contain nonzero activity; usage survives tier increases.
- UX review: EN/RU labels explain pending holds, no color-only information,
320px/1.6-scale widget checks, actual browser visual verification, zero and
over-cap ratio handling. Existing KYC telemetry is sufficient; no usage amounts
are sent to analytics.
- Validation passed: all 91 frontend tests, analyze app and sxchnge_kyc,
format check of all 9 affected Dart files, web build and diff checks.
- Delivery: [PR #23](https://git.sendico.io/tech/sxchnge/pulls/23), unmerged. Merge #21 first and retarget #23 to main.
## UX simplicity preference
Task [#26](https://git.sendico.io/tech/sxchnge/issues/26), delivered in
[PR #27](https://git.sendico.io/tech/sxchnge/pulls/27) on `skills-26`, makes
simplicity an explicit preference in the UX Design skill and its review checklist.
Prefer fewer concepts, choices, and controls when they serve the same need; retain
essential information, accessibility, and recovery. Documentation only.
Validation: skill-creator `quick_validate.py` passed in an isolated environment
with PyYAML (the system Python lacked it); `git diff --check` passed. No runtime
tests were needed. The PR is not merged.
## Exchange workspace — task #28
- Branch `workspace-28`, stacked on `limits-22` / PR #23. Merge KYC #21 first,
then limits #23, then retarget this workspace contribution to main. The approved
plan from #24/#25 is included and updated for the user's available-only direction.
- Implemented Accounts, Activity/detail, Limits and Settings in a responsive
go_router shell, with top-up, exchange and payout input/review/status flows.
One action group follows the selected currency; all colors use theme roles.
Only available balances are displayed. Status explains credit timing, outgoing
amount plus fee, completion and full return after failure.
- Shared `sxchnge_wallet` service/providers own coherent demo balances, quotes,
idempotent submissions, reconciliation, history, account language and live
snapshot refresh. The limits adapter reuses the KYC DTO/mapper and refreshes
usage when operations change. Widgets consume provider models.
- Language is in account settings, with failed-save feedback and retry. Public
auth and verified-email screens enter the workspace. KYC remains optional;
the demo service enforces its basic/verified outgoing caps at submission.
- UX review: EN/RU at 320px with 1.6 text scaling; available-only presentation;
field preservation after errors; explicit draft discard; quote expiry;
loading/stale/empty states; operation outcome explanations; accessible labels,
semantic status announcements and focus after quote/errors. Browser walkthrough
verifies quote amounts and service-confirmed credit with the exchange handoff.
Native mobile and dedicated VoiceOver/TalkBack testing remain release QA.
- Measurement review: typed draft/quote/submission/settlement steps with scoped
journey IDs, safe failure enums, simulated flag and deduplicated terminal
outcomes. No financial amounts, recipients or account IDs in events. Pending
app closure is not draft abandonment. Real PostHog delivery and cross-session
server outcomes remain integration work.
- Validation passed: `make test-frontend` (115 tests), `flutter analyze` in app,
sxchnge_wallet, sxchnge_analytics and sxchnge_kyc; format check of all 36 changed
Dart files; `flutter build web`; `git diff --check`. Review fixes included
narrow Russian layouts, limit-provider typing, automatic pending refresh,
single-use quotes and ambiguous-response recovery. No security scan requested.
- Demo limits: opening EUR 75, fixed rates/fees and three currencies, no real
payment methods/bank validation/storage/auth enforcement. Account preferences,
history and balances reset on reload. No receipt export, date pagination,
notification preferences or security settings beyond an honest capability note.
Backend adapters must supply these before production use; see the wallet README.
- Delivery: [PR #29](https://git.sendico.io/tech/sxchnge/pulls/29), pushed and
unmerged. Task and PR have frontend label, tech owner and SXCHNGE project.
Browser demo walkthrough also completed exchange and payout, confirming source
currency handoffs and exact fee/debit/receipt values on the result screen.
### Workspace copy cleanup — follow-up to #28
At the user's request, removed repeated demo/preview banners from the workspace,
transaction forms, auth, email confirmation, identity and limits. Confirmation
and result copy now uses ordinary product wording in EN/RU; the mobile wordmark
remains without the extra note. Removed unused localization entries and duplicate
email-state copy. Existing journey measurement, simulation flags, service behavior,
funds explanations and recovery controls are unchanged. Development constraints
belong in this record and package README, not repeated throughout the product UI.
Delivery continues in [PR #29](https://git.sendico.io/tech/sxchnge/pulls/29) on
`workspace-28`. This copy change does not connect real authentication, email,
payment, support or backoffice services.
Validation: all 115 frontend tests, app analysis, app Dart formatting, web build
and diff checks pass. Updated existing copy expectations; telemetry tests still
verify simulated events never count as real business success. No new click events
were needed for this presentation-only cleanup.
+47 -8
View File
@@ -1,6 +1,6 @@
# Exchange workspace — UX plan
Task [#24](https://git.sendico.io/tech/sxchnge/issues/24). **Plan only; no app changes.**
Task [#24](https://git.sendico.io/tech/sxchnge/issues/24). Approved plan; implementation tracked in task #28.
## Product direction
@@ -20,10 +20,10 @@ Keep decoration secondary to balances, amounts, recipients and transaction terms
| Destination | What it contains | Main next action |
|---|---|---|
| Accounts (default) | Currency accounts, available balances, reserved amounts, recent activity, actionable pending items | Top up, exchange, pay out |
| Currency account | Available/booked balance, holds, relevant activity and applicable limits | Act on this currency |
| Accounts (default) | Currency accounts, available balances, recent activity, actionable pending items | Top up, exchange, pay out |
| Currency account | Available balance, relevant activity and applicable limits | Act on this currency |
| Activity | All operations, filters, search, processing items | Inspect an operation or resolve an actionable issue |
| Limits | Current caps, used, reserved, available, period/reset information and upgrade benefits | Verify identity when useful |
| Limits | Current caps, used and available, period/reset information and upgrade benefits | Verify identity when useful |
| Settings | Profile, language, security, notifications and help | Manage the account |
Desktop: a persistent sidebar with **Accounts · Activity · Limits · Settings**.
@@ -71,7 +71,7 @@ Your accounts [Add currency account, if supported]
[ EUR · available balance ] [ USD · available balance ] …
Selected account: EUR
Available: … Reserved: …
Available: …
[Top up] [Exchange] [Pay out]
Action needed / in progress (only when there is something useful to show)
@@ -80,9 +80,8 @@ Recent activity [See all]
- Each card shows currency code/name, available amount and a text status when
restricted. Do not rely on flags to identify currencies.
- Distinguish available, booked and reserved balances. “Available” is the default
spendable number; disclose the balance breakdown on account detail. Backend
balances are authoritative; a list of recent operations is not a balance ledger.
- Show only available balances. Held/reserved/booked amounts are internal service
details, not customer-facing concepts. Backend balances remain authoritative.
- Do not sum different currencies directly. A future total in a reporting currency
must be labeled estimated, with valuation currency/time and a service-provided
conversion. It is not needed for the first interface.
@@ -368,3 +367,43 @@ repeated submit, expired quote, zero balances, no methods, denied KYC, and logou
This document is a design deliverable, not evidence that these screens exist or
that accessibility/payment flows have been tested. Existing demo implementation
and pending PRs remain unchanged by this task.
## Implementation simplification — user direction for #28
Only available balances are shown. Customer limits show used and available, with
no held/reserved breakdown or explanatory jargon. Keep four navigation destinations
and straightforward input → review → result flows. Demo funding/payout methods
are explicitly simulated, not representations of live supported rails.
## Implemented demo scope — #28
Four primary destinations and three transaction journeys are implemented. The
single demo method needs no method picker; top-up and exchange collect an amount,
payout additionally collects sample destination text. Review shows fees, source
debit, destination credit and rate. There are no live payment instructions,
redirects, saved recipients, security controls or notification preferences.
Settings implements account language and links to identity. Unsupported production
capabilities remain future work, not decorative controls.
Pending top-up: money has not reached available balance. Pending outgoing: total
amount plus fee has left available balance, and processing continues. Completed
exchange/top-up: destination balance is credited. Failed outgoing: amount plus fee
is available again. These explanations appear on canonical operation detail.
Pending snapshots refresh automatically across screens; refresh failures mark data
potentially stale. The limits service independently supplies usage and remaining.
The customer sees aggregate consumed capacity and available capacity, not internal
reservations.
Activity offers kind/status/currency filters and reference search; operation detail
is deep-linkable while the demo session exists. Date filtering, pagination,
receipts, persistent history, actual reset timestamps and production support await
backend contracts. Transient drafts survive pushed settings/limits screens and
locale changes; closing a draft requires discard confirmation. Browser reload
resets the entire demo and is not durable recovery.
Measurement uses existing random journey IDs and typed quote/submission/settlement
steps. Only service-confirmed terminal status closes the transaction outcome.
Accepted operations are excluded from draft-abandonment on app disposal. Actual
server events, persistent reconciliation and cross-session conversion remain
integration gaps. No automatic click tracking, replay or financial data collection
is introduced.
+164
View File
@@ -0,0 +1,164 @@
# Identity verification UX plan
Task [#20](https://git.sendico.io/tech/sxchnge/issues/20). Plan recorded before implementation.
## User outcome and scope
Understand current access, decide whether higher limits are useful, and submit two
readable photos for a human review. No KYC is a valid account state. Email
confirmation and identity verification remain separate. The existing app is a demo:
this release simulates review, holds photos only in memory and never uploads them.
It must say so before selection and submission; use sample images only.
## Journey
1. **Verification & limits**: status, active tier, basic versus verified daily and
monthly limits, and one relevant next action. Preview policy is explicitly
labeled as fixtures in the stub service. A draft, pending review,
correction request or denial keeps basic limits; only approval enables the
verified tier. This is presentation, never financial authorization.
2. **Passport**: photograph the open identity/photo page of a valid passport;
all edges visible, readable text, no glare or fingers covering details.
3. **Selfie with passport**: face and open passport visible in the same photo,
unobstructed and in focus. Explain the difference with an icon and guidance.
Each slot supports JPEG/PNG up to 10 MiB, preview, replacement and removal.
Validate content/decodability, size and dimensions, not just extensions.
4. **Review**: both previews, ability to return and replace, explicit confirmation
that photos belong to the user, then submit for human review. No automatic
approval, invented review SLA or instant increase in limits.
5. **Review status**: pending message, unchanged limits and manual refresh. A
correctable rejection has a specific safe reason and a fresh submission path;
final denial offers support guidance and no futile resubmit control. Approval
clearly shows the active higher tier. No forced upgrade or dead-end gate.
Back preserves the in-memory draft; leaving the flow asks whether to discard
selected photos. Refresh/closing clears a demo session. Successful submission
releases photo bytes. Never put images, paths or filenames in routes, analytics,
logs, preferences or task records. Demo decision controls are explicitly separate
from customer actions and operate only with the dummy service.
## State and recovery contract
| State | Tier | Action |
|---|---|---|
| Not verified | Basic | Start optional verification |
| Local draft | Basic | Continue / discard |
| Loading status | Unknown | Wait; don't assert basic/verified before response |
| Status unavailable | Last known, marked stale | Retry; block new submission until refreshed |
| In review | Basic | Refresh; continue account use |
| Changes requested | Basic | Reason: unreadable passport, unreadable selfie, expired passport; replace and resubmit |
| Denied | Basic | Explain decision category; contact support for review |
| Verified | Verified | See increased limits |
Picker cancellation is neutral. Invalid type, oversized/corrupt/too-small image,
permission/read failure and unavailable submission have distinct recoverable
messages. Keep valid photos on failed replacement/submission. Serialize operations,
prevent duplicate submits, ignore results after disposal. Server adapters must
provide idempotent submissions and current status/revision, enforce account and
email access, handle session expiry and rate limits, and validate images again.
Do not infer identity validity from client image checks.
## Measurement
Use existing typed AnalyticsService/JourneyRecorder. A KYC submission journey
starts when the user starts/restarts verification. Semantic stages: preparation,
passport selection, selfie selection, submission. Replacements/retries are
operations in the same journey. Confirmed service acceptance is the terminal
submission outcome, **not identity approval**; demo outcomes are simulated.
Explicit draft discard/navigation or 30 minutes of settled inactivity marks
abandonment. Do not count time waiting for human review as abandonment. Review
status refresh is a separate terminal observation, not a new approval conversion.
Measure start-to-submission conversion, per-stage failures and recovery, elapsed
submission time and explicit/inactivity abandonment. Only enum reason categories,
random journey IDs, operation sequence and elapsed time are collected. No photo
content/metadata, names, emails, document numbers, URLs or exception strings.
Disable third-party session replay/autocapture on identity routes when PostHog is
added. Production time-to-decision and approval rate require server-side review
events correlated by an opaque submission ID; frontend refresh cannot establish
those metrics. Cross-session resume requires the future backend.
## Visual and accessibility plan
Reuse theme colors/typography, rounded panels, locale selector and GoRouter.
Single scrollable mobile column; constrained desktop reading width. Text labels
and icons accompany status colors. Visible numbered steps, back/skip controls,
minimum touch targets, keyboard-accessible buttons, live-region operation/error
feedback, image semantic labels without filenames. Check EN/RU, 320px viewport,
large text, success/failure paths and analytics isolation before delivery.
## Production integration prerequisites
This frontend scope does not implement a staff backoffice, document storage or a
real KYC policy. An authenticated backend must own entitlements, limits and review
transitions. Provide private upload/download authorization, human-review roles,
audit trail, safe rejection categories, retention/deletion policy, user privacy
notice/support destination, idempotency and malware/content checks before enabling
real documents. No production claims, deadlines or statutory requirements are
invented here. Native camera capture can later complement the shared file picker.
## Sendico limits alignment
Inspected Sendico ADR 0001 and `api/proto/limits/v1/limits.proto`
(`ListVisibleLimits`, `VisibleLimitSlot`). No matching Flutter limits provider was
found in that checkout. Follow its ownership boundary: LimitsService.fetch()
returns backend-evaluated tier, visible caps, remaining capacity and upgrade
comparison. LimitsProvider loads/refreshes those models; widgets never derive
active limits from KYC. The dummy service performs the backend stand-in evaluation.
The visible projection does not reserve capacity or authorize payments.
## Implementation and review evidence
- Optional `/identity` demo entry from login and confirmed-email screens. No live
session is implied. GoRouter exit guard and discard confirmation protect drafts;
reload/closing the browser remains destructive to this explicitly transient demo.
- Shared package uses transport DTO → mapper → service → model → provider. Limits
are independently fetched and expose current/remaining/upgrade values.
- Typed analytics separates submission from status observation; picker cancellation
has a neutral cancelled signal. Simulated submission is not real identity approval.
- Review fixed a Flutter Web incompatibility: encoded ImageDescriptor dimensions
are unsupported. Image metadata is now read before bounded decoding using the
cross-platform image package. Actual browser file selection with a generated
640×640 PNG succeeds for both slots and reaches pending review with basic limits.
- EN/RU widget journeys cover approval, correction/resubmission, denial/support,
errors, discard, and 320px width at 1.6 text scale. Controls use theme colors and
labels; headings/errors expose live-region semantics, step changes move focus
and scroll context. Native VoiceOver/TalkBack and device camera QA remain release
checks for future mobile consumers; no camera capture is implemented here.
- Photo previews evict their image-cache entry on replacement/disposal. Providers
release photo references on exit/submission/disposal. No secure-memory-erasure
guarantee or browser-termination telemetry is claimed.
## Measurement definitions for dashboards
The denominator for submission conversion is journeys containing a requested
`kycPreparation` step; status-only refresh journeys are excluded. Numerator is a
terminal `kycSubmission` service outcome, counted once per journey. Exclude
`simulated=true` from production dashboards. Stage failure rate divides failed
operations by requested operations of that stage; cancelled pickers are reported
separately. Compare recovered submissions within the same journey, and calculate
duration from the first preparation request to acceptance. Explicit exit and
settled 30-minute inactivity are separate abandonment categories. Refresh after an
uncertain submission reconciles server status but cannot prove an end-to-end
submission conversion; production correlation needs the backend submission ID.
Final validation: format check (27 Dart files), analyzer in all three affected
packages, `make test-frontend` (86 tests) and release web build passed. The UX
checklist was reviewed against the implemented demo scope; production/backend
and native assistive-technology gaps are recorded above rather than represented
as complete.
## Limits usage correction — task #22
Visible limits include backend-provided committed (`usedMinor`) and reserved
(`reservedMinor`) usage, matching Sendico's `VisibleLimitSlot`. Show both amounts,
the current cap and authoritative remaining capacity for each period. A labeled
theme-based indicator visualizes used plus reserved against the cap; clamp only
the visual ratio, never rewrite the returned monetary values. No capacity is
communicated in text when remaining is zero. Daily/monthly demo fixtures now have
nonzero activity, retained when caps increase after approval.
This is a display correction within the existing KYC journey, so no additional
analytics events or financial data collection are introduced. Tests cover mapping
without inferring remaining, unused/exhausted/over-cap/zero-cap ratios and EN/RU
usage display at 320px with 1.6 text scaling.