# Product implementation record ## Reusable UX guidance — task #10 [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, 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. Validation: both skills passed `quick_validate.py` from the skill-creator skill; root skill links resolve, scaffold checks and `git diff --check` pass. Manual review checked the requested principles and checklist coverage, duplication, contradictions, and actionable wording. The initial validator attempt lacked PyYAML; rerunning in a temporary virtual environment with PyYAML passed. This is documentation-only guidance, not an implementation or verification of product usability or journey instrumentation. Runtime tests and security scans were not run. No application behavior or analytics events changed. ## Scope The public Astro website now lives in `website/`, preserving its source, assets, brand references and hosting identity. `backend/` describes the proposed BFF boundary; no backend service is implemented. The frontend includes: - `sxchnge_theme`: reusable Flutter theme, Onest font/license, light/dark themes, and a consumer example. UI uses ColorScheme and TextTheme roles. - `sxchnge_auth`: shared login, signup, and email-verification contracts, models, providers, and deterministic dummy services, reusable on mobile. - `app`: responsive login/signup, EN/RU localization and saved locale, email-sent and verified screens, expired/invalid/internal-error outcomes, resend/retry, and centralized go_router navigation. ## Review boundaries and task mapping The accumulated work was initially left uncommitted across task branches. Delivery groups the actual final code into three stacked contributions, without claiming that the earlier intermediate implementations were committed: 1. `theme-1` into `main`: website relocation, repository scaffolding and theme. Related task: [#1](https://git.sendico.io/tech/sxchnge/issues/1). 2. `auth-4` into `theme-1`: shared auth and verification package. Related tasks: [#4](https://git.sendico.io/tech/sxchnge/issues/4), [#5](https://git.sendico.io/tech/sxchnge/issues/5). 3. `routing-6` into `auth-4`: integrated application, root test entry point, self-contained frontend guidelines/workflow skills and this delivery record. Related tasks: [#2](https://git.sendico.io/tech/sxchnge/issues/2), [#3](https://git.sendico.io/tech/sxchnge/issues/3), [#5](https://git.sendico.io/tech/sxchnge/issues/5), [#6](https://git.sendico.io/tech/sxchnge/issues/6). Review and merge in that order. Preserve commit ancestry with merge commits, then retarget the next PR to `main` after its dependency merges. With squash merges, rebase the remaining stack before merging. PR links are recorded below once created. Earlier empty task branches are retained for traceability. ## Validation The frontend suite covers 56 tests: 20 shared auth, 3 theme, 3 theme consumer, and 30 app tests. Coverage includes validation, localized layouts at 200% text scale, provider lifecycle/race handling, signup through email confirmation, resend/retry, token changes, transient history extras and URL route updates. Commands used for delivery: - Root: `make test-frontend`. - Flutter packages: formatting checks and `flutter analyze`. - App: `flutter build web --no-wasm-dry-run`. - Website: `npm run test`, `npm run check`, `npm run build`. The localhost preview was manually checked for confirmation deep-link reload, return to login, and browser back/forward. Tests and builds are local validation; no remote CI outcome is implied. Build outputs and dependency caches are ignored. ## Current limitations Authentication and verification are explicitly simulated. No real account, session, email delivery, backend token validation or KYC access guard exists. The three app routes are public; backend authorization remains future work. `demo-valid`, `demo-expired` and `demo-internal` are preview-only confirmation values. Other/missing tokens display invalid confirmation. Signup email is transient and excluded from serialized browser history. Only locale preference is persisted by the application. The website and Flutter app are separate applications. The Flutter app currently has a web runner; the shared packages can be consumed by a future mobile app. ## Published PRs | Order | PR | Branch → base | Implementation commit | | --- | --- | --- | --- | | 1 | [#7: Product layout and theme](https://git.sendico.io/tech/sxchnge/pulls/7) | `theme-1` → `main` | `d931805` | | 2 | [#8: Shared auth and verification](https://git.sendico.io/tech/sxchnge/pulls/8) | `auth-4` → `theme-1` | `27424ed` | | 3 | [#9: Localized app and routing](https://git.sendico.io/tech/sxchnge/pulls/9) | `routing-6` → `auth-4` | `10a278c` | All three implementation commits are pushed. PRs are open, assigned to `tech`, labeled `frontend`, and associated with the SXCHNGE project. Follow-up documentation commits are included in PR #9. Task references point to the delivering branches; older empty branches are historical only. No PR has been merged during delivery. Delivery validation passed: 56 frontend tests; formatting and all four Flutter analyses; 3 website tests, Astro check (zero errors/warnings), and website build. The app web build and browser checks passed during the immediately preceding routing task; delivery changed documentation and Git organization only. ## Onboarding UX fixes and analytics preparation Task [#12](https://git.sendico.io/tech/sxchnge/issues/12) corrects the four UX review findings: measurable submitted journeys, accurate sent recipient state, primary retry on confirmation errors, and prominent/truthful simulated outcomes. The new shared `sxchnge_analytics` package supplies typed events, a bounded dummy sink and a journey recorder; auth service decorators keep collection independent of widgets. A PostHog adapter can replace the sink later; no actual SDK or data transmission is included. The [journey contract](ux/auth-journeys.md) records event semantics, metrics, privacy constraints, windows, validation and limitations. Delivery: [PR #13](https://git.sendico.io/tech/sxchnge/pulls/13), `onboarding-12`. Implementation commit `f1cbf64`; 68 tests and affected-package analysis/formatting 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 extension recommendations and launch configuration. Root `.vscode/` is ignored so personal editor configuration stays local. Development uses the CLI commands in the README. Validation: no tracked root `.vscode` files, ignore rule verified, and diff whitespace check passed. Runtime tests are unnecessary for this change. Delivery: [PR #15](https://git.sendico.io/tech/sxchnge/pulls/15), branch `editor-14`. ## Root README refresh Task [#18](https://git.sendico.io/tech/sxchnge/issues/18), delivered in [PR #19](https://git.sendico.io/tech/sxchnge/pulls/19) on `docs-18`, documents current packages, app/website commands, verification previews, analytics limits, skill location and contribution workflow. Local links and diff checks pass; commands and prerequisites were checked against repository configuration. Documentation only; no runtime tests were run. ## Exchange workspace UX plan — task #24 - Plan-only scope confirmed by the user; no application code changed. - [Exchange workspace plan](ux/exchange-workspace.md) defines accounts, top-up, exchange, payout, Activity, Limits and Settings; account-owned language replaces repeated page selectors in the proposed interface. - Includes authoritative quotes/status/limits, idempotent recovery, account-profile language persistence, accessible/responsive behavior and semantic funnel metrics. - Standalone documentation branch `exchange-shell-24` from main. Future interface 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. ## Data model and provider boundaries — task #30 - `architecture-30`, based on workspace PR #29. Root and frontend agent rules, plus README, now explicitly preserve DTO → mapper → service → data model → provider → UI across app features, shared packages, stubs and future clients. Models cannot be replaced by providers or reused as transport DTOs merely because their fields currently match. - Checked application service access: widgets compose providers with service dependencies; they do not parse DTOs or invoke backend operations directly. KYC and wallet transaction services already map transport data to models. Auth success responses now pass through explicit response DTOs and mappers; wallet profile conversion now accepts a ProfileDTO instead of a raw string. - Existing models, provider state, asynchronous/error behavior and public service contracts are preserved. DTOs/mappers remain service implementation details. No UI, telemetry semantics or backend integration changed. - Frontend review and validation: formatting of all 6 changed Dart files passed; analysis of sxchnge_auth and sxchnge_wallet passed; all 115 frontend tests passed; diff check passed. Existing service, provider and integrated tests exercise the mapping paths. No additional behavioral test was needed for these direct field projections. No security scan requested. - Stack order: KYC #21 → limits #23 → workspace #29 → this contribution; retarget each dependent PR to main after its base is merged. - Delivery: [PR #31](https://git.sendico.io/tech/sxchnge/pulls/31), pushed and unmerged. Task and PR metadata verified: frontend label, tech owner, SXCHNGE project. Retarget after workspace #29 merges. ## Authorized integration — 2026-09-12 The user requested merging all open PRs. Skills #17, KYC #21, limits/workspace #23 and UX plan #25 have merged into main. Workspace #29 had already merged into limits-22 and reached main through #23. Architecture #31 is the final integration PR and carries this record. Resolved documentation conflicts by preserving both contribution histories. Preserved the latest implemented workspace plan rather than restoring the older held-funds design. Skill moves retain the newer simplicity guidance, and root AGENTS.md points to .agents/skills while retaining the architecture requirements. No frontend source was changed by conflict resolution. Older unmerged/stack notes above describe delivery-time state and are superseded by this integration record. Validation of the combined tree: all 115 frontend tests and app analysis passed; diff checks passed. Branches were retained. No checks were bypassed. ## Reusable two-factor verification — task #32 Branch `two-factor-32` adds a SXCHNGE-designed, theme-based code page reused by login, top-up, exchange, payout and verified profile enable/disable. EN/RU copy, one accessible input, keyboard/paste support, resend cooldown, invalid/expired/ locked/unavailable recovery and cancellation preserve context. Transaction verification retains its reviewed funds movement and fees. No Sendico UI or code was copied for this feature. Shared auth owns explicit DTOs, mappers, domain models, service contracts and providers. Method-aware contracts distinguish email and authenticator challenges; the initial email fixture uses code `123456`, sends no email, defaults off and resets on reload. Real TOTP enrollment, method selection, delivery, recovery and backend enforcement remain integration work. Mobile can reuse the page and providers with its own router/localization and service adapters. Login stays pending until approval is consumed. The dummy wallet consumes a purpose/quote-bound, expiring, one-use approval before execution. Concurrent idempotent retries debit once; expired quotes require fresh review; uncertain outcomes retain reconciliation. Timers stop on route/app disposal and late responses are ignored. Settings update only after service confirmation. Analytics retains parent journey correlation and distinguishes verification from actual login/settings/settlement outcomes; codes, grants and targets never enter events. Frontend and UX review covered the complete task diff. Validation passed: `dart format --output=none --set-exit-if-changed` for all 34 changed Dart files; `flutter analyze` in app, sxchnge_auth, sxchnge_wallet and sxchnge_analytics; `make test-frontend` (147 tests); `flutter build web` (including Wasm dry run); `git diff --check`. Browser checks at 1280×720 and 390×844 verified themed layout, invalid-code recovery, keyboard entry and confirmed settings. Widget tests cover Russian at 320px/1.6× text scale and all money entry points. No security scan was requested or run. Earlier validation failures were corrected, including ARB metadata handling, disabled-policy latency, route timer disposal and lint findings. See [the UX and measurement contract](ux/two-factor.md) and [shared auth integration guide](../frontend/packages/sxchnge_auth/README.md). Delivery: [PR #33](https://git.sendico.io/tech/sxchnge/pulls/33) targets `main`; committed and pushed, unmerged. Issue #32 and PR #33 metadata verified: frontend label, tech owner and SXCHNGE project. No stacked dependencies. ## Minimal customer BFF and public Sendico contracts — task #34 [Task #34](https://git.sendico.io/tech/sxchnge/issues/34), branch `bff-34`, [PR #35](https://git.sendico.io/tech/sxchnge/pulls/35) into `main`. The initial copy at `7062672` incorrectly retained Sendico's local tenancy model. The correction removes organization membership, roles, Casbin, policy storage and seeding, invitations and their models/repositories/tests. It also removes unused financial models/errors, ledger/wallet provisioning metadata, platform service names, S3 configuration and WebSocket scaffolding. No default tenant or bypassing authorizer replaces them. Retained Sendico source is pinned to `8bb20dcd622dd8eb92d289b6b34411e7eccab083`: HTTP runtime, local customer/password service and Mongo repository, customer sessions and verification storage, generic repository/transaction code, errors, logging and health. [Provenance](../backend/PROVENANCE.json) covers 232 retained Go files at that cleanup stage; every adaptation is flagged. The later module reorganization below removes the unused public OpenAPI snapshot. The Sendico checkout remains unchanged. Customer creation accepts a raw password, validates/hashes it and commits the customer and activation token together. Token transactions join an active outer customer transaction. Deletion revokes only the selected customer's sessions and deletes its account atomically, including when it is the final local customer. Customer lifecycle and login use the same configured auth collections. Pending, active and blocked customer state and session/client binding remain local. The sole Sendico organization reference belongs to the future public HTTP adapter configuration. [Architecture and capabilities](architecture/bff.md) document server-side customer/resource ownership and the public external-customer contract gaps. No internal service, shared database or provider resource creation is used. Signup/profile HTTP routes, verification delivery/completion, application client setup and live Sendico integration remain subsequent wiring work. Backend completion review covered the retained copied runtime and the full extraction diff. Inactive-customer checks and refresh client/account binding were added after review; explicit response DTOs keep storage fields out of HTTP output. Validation passed: `make test` (race-enabled backend suite, including fresh Mongo replica-set customer lifecycle/runtime tests, plus all frontend suites), `make lint-backend` (architecture, formatting and vet), and `go test -tags integration -run '^$' ./...` from `backend` (compilation of the additional tagged suites; this command does not execute those tests). Provenance/source blobs, public contract references and `git diff --check` passed. Earlier extraction compile errors were corrected. The initial fresh-database test attempt used an unavailable image tag and then hit Docker Desktop replica-set address discovery; it now uses `mongo:8` and a direct connection to the disposable single-node replica set. No security scan was requested or run. PR #35 remains unmerged. There is no deployed-data migration: this bootstrap has not been deployed. Existing experimental databases may retain unused tenancy collections; this change does not delete external database records. Customer HTTP responses now expose only ID, name, last name, login, locale and optional avatar. The frontend still uses dummy services and is unchanged. ### Go module organization correction `backend/` now groups two implemented Go modules: the runnable `product` BFF (`main.go`, `go.mod`, configuration and feature packages) and the `shared` library (its own `go.mod`, generic storage, errors, logging and HTTP helpers). Product uses `replace git.sendico.io/tech/sxchnge/shared => ../shared`. A future backoffice BFF belongs in its own `backend/backoffice` executable module; it is not implemented or silently combined with product in this task. Customer, session and verification models/storage now live with their features. Shared database code no longer knows about customer repositories. Auth and verification configurations belong to their feature packages. The inherited `cmd`, `edge`, `internal`, `pkg`, `scripts` and `contracts` top-level folders are removed. All 112 unused contract files are removed; future HTTP adapters will own only consumed public wire definitions. Provenance retains the pinned upstream source paths while recording the new local module paths. Root Make targets validate both modules independently and run product with `cd backend/product && go run .`. Source behavior remains the previously validated local customer/auth/session bootstrap; frontend and Sendico source are untouched. Validation passed after the module moves: `make test` (both Go modules with the race detector and all frontend suites), `make lint-backend`, product executable build and `-version` smoke check, and `go test -tags integration -run '^$' ./...` in each Go module (compile-only for the additional tagged suites). All 233 provenance source blobs match the pinned revision. `git diff --check` passed. No security scans were requested or run. The correction is delivered on `bff-34` in [PR #35](https://git.sendico.io/tech/sxchnge/pulls/35), which remains unmerged. ## Notifications service (#36) - Added independent `backend/notifications` executable with a separate `interface` Go module. Canonical protobuf source: `backend/notifications/interface/proto/v1/interface.proto`. Go bindings are ignored; Make generates them before validation and packages source/client archives without committing generated code. - Email-first Send/Get contract, caller-scoped durable idempotency, strict template parameters and HTML escaping, immutable rendered snapshots, expiry, and sanitized per-delivery status. Unsupported channels remain explicit in the contract and fail before enqueueing. - SendGrid adapts Sendico's driver to the new rendered-email interface; Resend is a new implementation behind the same shared DriverConfig pattern. No provider managed template or Sendico business-runtime dependency is introduced. - Mongo persistence uses shared DBImp/query/patch/index/connection wrappers. The notification document is the atomic outbox. Shared messaging contains the selected Sendico NATS durable adapters, and the executable consumes their Transport/Subscription interfaces for publication, delivery and acknowledgement. - Tests cover both provider payloads, authentication, parameters, concurrent idempotency/claims, outbox publication failure, lease recovery, expiry and retries, with disposable MongoDB and NATS containers. Final `make test` and `make lint-backend` passed. `make package-notifications-interface` passed; the extracted client archive passed standalone `go test ./...`. No live email or optional security scan was run. - Limitations: email only; no delivery receipts. Ambiguous sends require reconciliation, rather than automatic replay. Initial NATS provisioning uses one replica. Caller services own recipient authorization/preferences. Drain queued work before changing driver/sender configuration. - Delivery is stacked on BFF PR #35 (`bff-34`); merge #35 first, then retarget the notifications PR to main. Do not merge without user authorization.