244 lines
11 KiB
Markdown
244 lines
11 KiB
Markdown
# SXCHNGE
|
||
|
||
Product repository for the sxchnge public website, Flutter consumer app, reusable
|
||
packages, and a backend for frontend (BFF) bootstrapped from Sendico.
|
||
|
||
## Current state
|
||
|
||
The consumer app includes responsive login/signup, English and Russian
|
||
localization, email verification and recovery screens, and URL-based navigation
|
||
with `go_router`. Its interface uses the shared theme's colors and typography.
|
||
|
||
**Authentication, email verification and analytics use dummy services.** No real
|
||
account or session is created, no email is delivered, and no analytics data is
|
||
transmitted by those app services. The backend now contains locally owned copies
|
||
of Sendico’s BFF runtime, auth/session stack and account service. The app is not
|
||
connected to that backend or to Sendico yet.
|
||
|
||
## Repository structure
|
||
|
||
| Location | Purpose |
|
||
| --- | --- |
|
||
| [`website/`](website/README.md) | Astro public website, assets, brand references and hosting configuration |
|
||
| [`frontend/app/`](frontend/app/README.md) | Flutter consumer app with a web runner |
|
||
| [`sxchnge_theme`](frontend/packages/sxchnge_theme/README.md) | Reusable light/dark themes and bundled Onest font |
|
||
| [`sxchnge_auth`](frontend/packages/sxchnge_auth/README.md) | Shared auth contracts, providers, two-factor page and dummy services |
|
||
| [`sxchnge_analytics`](frontend/packages/sxchnge_analytics/README.md) | Typed journey events, recorder and bounded in-memory dummy analytics |
|
||
| [`backend/`](backend/README.md) | Copied BFF/auth/account foundation and isolated public Sendico contracts |
|
||
| [`.agents/skills/`](.agents/skills) | Repository agent skills |
|
||
| [`docs/`](docs/implementation.md) | Implementation records and UX measurement contracts |
|
||
|
||
Each application owns its dependencies and build configuration. Shared Dart and
|
||
Flutter packages can be reused by a future mobile app; mobile runners are not
|
||
currently included. Local `.vscode/` configuration is ignored.
|
||
|
||
## Run the consumer app
|
||
|
||
Requires Flutter **3.47.0 or later** with Dart **3.13.0 or later** (below Dart 4), matching
|
||
the application's package constraints, and Chrome for this run command.
|
||
|
||
```sh
|
||
cd frontend/app
|
||
flutter pub get
|
||
flutter gen-l10n
|
||
flutter run -d chrome
|
||
```
|
||
|
||
Build the web app from the same directory:
|
||
|
||
```sh
|
||
flutter build web --no-wasm-dry-run
|
||
```
|
||
|
||
Output is `frontend/app/build/web/`. To inspect that build locally, from the
|
||
repository root:
|
||
|
||
```sh
|
||
python3 -m http.server 5123 --bind 127.0.0.1 --directory frontend/app/build/web
|
||
```
|
||
|
||
Open [the local app](http://127.0.0.1:5123/). The language selector supports EN/RU
|
||
and saves the language preference. Edit translations in `frontend/app/lib/l10n/`
|
||
and regenerate with `flutter gen-l10n`; do not edit generated translations.
|
||
|
||
## Preview email verification
|
||
|
||
Signup leads to the simulated email-sent screen. Its demo confirmation button
|
||
previews completion. Direct confirmation URLs use hash routing:
|
||
|
||
| URL suffix | Preview outcome |
|
||
| --- | --- |
|
||
| `/#/verification-sent` | Request an email; a direct visit asks for the address |
|
||
| `/#/verify-email?token=demo-valid` | Simulated verification complete |
|
||
| `/#/verify-email?token=demo-expired` | Expired link with recovery |
|
||
| `/#/verify-email?token=demo-internal` | Internal error with primary retry |
|
||
| `/#/verify-email` or an unknown token | Invalid confirmation |
|
||
|
||
Signup email stays transient and is excluded from serialized browser history.
|
||
The sent recipient is read-only until **Change email** is selected. All current
|
||
routes are public; these previews do not establish authentication or authorization.
|
||
|
||
## Analytics and PostHog preparation
|
||
|
||
The app accepts an injectable `AnalyticsService` and defaults to
|
||
`DummyAnalyticsService`. It keeps up to 500 semantic events in memory and never
|
||
captures form contents, confirmation tokens or raw errors. Events cover submitted
|
||
auth journeys, service outcomes, retries and known abandonment; simulated outcomes
|
||
are distinguished from real conversion.
|
||
|
||
A future PostHog adapter can replace the sink. No PostHog SDK or credentials are
|
||
configured. Read the [auth journey contract](docs/ux/auth-journeys.md) for event
|
||
properties, attempt and timing rules, metric definitions, privacy requirements,
|
||
and cross-device/termination measurement limitations.
|
||
|
||
## Run the public website
|
||
|
||
Requires Node.js **22.12.0 or later** and npm, matching `website/package.json`.
|
||
From the repository root:
|
||
|
||
```sh
|
||
cd website
|
||
npm ci
|
||
npm run dev -- --background --host 127.0.0.1
|
||
```
|
||
|
||
Manage the background server from `website/`:
|
||
|
||
```sh
|
||
npm exec astro dev status
|
||
npm exec astro dev logs
|
||
npm exec astro dev stop
|
||
```
|
||
|
||
Website builds go to `website/dist/`. Use `website/` as the working directory
|
||
for hosting tools; the existing hosting identity lives in
|
||
`website/.openai/hosting.json`. The website and consumer app are separate builds.
|
||
|
||
## Validate changes
|
||
|
||
From the repository root, run all shared-package and app tests:
|
||
|
||
```sh
|
||
make test-frontend
|
||
```
|
||
|
||
From each changed Flutter package, run formatting and analysis. For example:
|
||
|
||
```sh
|
||
cd frontend/app
|
||
dart format --output=none --set-exit-if-changed lib test
|
||
flutter analyze
|
||
```
|
||
|
||
Validate the website independently:
|
||
|
||
```sh
|
||
cd website
|
||
npm run test
|
||
npm run check
|
||
npm run build
|
||
```
|
||
|
||
Rendering and passing tests do not alone establish UX completion. Review
|
||
usability, accessibility and journey measurement under the repository's UX rules.
|
||
|
||
## Product boundaries
|
||
|
||
The integration is: **consumer app → sxchnge BFF → Sendico public HTTP API**.
|
||
SXCHNGE is one organization in Sendico; its customers are owned locally.
|
||
Local accounts have no organization tenancy, membership, roles or policy engine.
|
||
|
||
- sxchnge will own consumer registration/sessions, onboarding and exchange UX,
|
||
and mappings from local customers to organization-scoped platform resources.
|
||
- Sendico remains authoritative for payment execution, KYC records and
|
||
verification, policy decisions and limit enforcement.
|
||
- The sxchnge organization, backend integration principal and individual customer
|
||
references are distinct identities. Consumers must not share the integration
|
||
account's customer identity.
|
||
- The BFF uses only the public HTTP API. Existing BFF/auth/account components
|
||
are copied into SXCHNGE-owned code; private transports and sibling module
|
||
dependencies are not used.
|
||
Integration credentials belong in the backend.
|
||
|
||
Before backend integration, agree on the customer, KYC, eligibility/limits and
|
||
customer-scoped payment contracts for one complete transaction flow. These are
|
||
intended boundaries, not claims that the required operations already exist.
|
||
|
||
## Client architecture
|
||
|
||
Keep **DTO → mapper → service → data model → provider → UI** boundaries in every
|
||
feature and shared package. Services return mapped domain models; providers sit
|
||
on services and expose loading/error/data state. Widgets render models and call
|
||
provider actions. DTO serialization and backend calls belong below this boundary.
|
||
Shared packages own reusable domain logic for web and mobile; stub replacements
|
||
must preserve the same contracts. See the standing rules in `AGENTS.md` and
|
||
`frontend/AGENTS.md`.
|
||
|
||
## Contribution workflow
|
||
|
||
Follow [`AGENTS.md`](AGENTS.md) and the applicable scoped guidelines, including
|
||
[`frontend/AGENTS.md`](frontend/AGENTS.md). Repository skills belong under
|
||
[`.agents/skills/`](.agents/skills).
|
||
|
||
Implementation work uses a Gitea task and linked branch, validation, commits,
|
||
a push and a PR. Merge only when authorized. Record scope, validation and known
|
||
limitations in the task and [implementation record](docs/implementation.md).
|
||
|
||
## Identity verification preview
|
||
|
||
Open `/#/identity` or use **Limits → Verify identity** in the workspace. The optional flow covers passport and selfie selection, review,
|
||
submission, pending review, approval, correction requests and denial in EN/RU.
|
||
Use sample images only: photos are never uploaded and drafts are not persisted.
|
||
|
||
The shared [sxchnge_kyc package](frontend/packages/sxchnge_kyc/README.md) provides
|
||
identity and limits services/providers for web and future mobile clients. Limits
|
||
are fetched through `LimitsProvider → LimitsService`; fixture amounts and simulated
|
||
review decisions demonstrate the future backend contract. Higher limits apply
|
||
only when returned by that service. Production review/storage/support and financial
|
||
authorization are not connected. See the [UX plan](docs/ux/kyc.md) for state, error,
|
||
privacy and measurement details.
|
||
|
||
## Exchange workspace preview
|
||
|
||
Choose **Explore your accounts** on login/email confirmation, or open `/#/accounts`.
|
||
Currency cards show only available funds. Select an account, then top up, exchange
|
||
or pay out through input → review → status. Review shows fees and actual debit and
|
||
credit; status explains where the money is, including processing and failed returns.
|
||
Activity, account balances and limits use one coherent demo ledger.
|
||
|
||
Settings owns English/Russian account language. Limits links to optional KYC;
|
||
no verification remains a valid account state with basic limits.
|
||
|
||
The shared [wallet package](frontend/packages/sxchnge_wallet/README.md) is reusable
|
||
by mobile clients. Transactions, rates, fees, recipients and profile storage are
|
||
explicitly simulated and reset on reload. No real money moves. See the
|
||
[workspace UX plan](docs/ux/exchange-workspace.md) and
|
||
[implementation record](docs/implementation.md) for scope and validation.
|
||
|
||
## Two-factor verification
|
||
|
||
Account **Settings → Two-factor verification** enables or disables protection
|
||
with a confirmed code. When enabled, login, top-ups, exchanges and payouts use a
|
||
shared SXCHNGE-themed challenge page. Money challenges retain the reviewed fees
|
||
and funds movement; cancelling preserves the transaction draft.
|
||
|
||
The initial service uses email-code fixtures: **123456** is the local test code.
|
||
No email is sent and settings reset on reload. Method-aware contracts and page
|
||
instructions also support authenticator challenges; actual TOTP enrollment,
|
||
validation and recovery remain backend integration work. See the
|
||
[two-factor UX contract](docs/ux/two-factor.md) and
|
||
[shared auth package](frontend/packages/sxchnge_auth/README.md).
|
||
|
||
## Backend integration plan
|
||
|
||
The [BFF architecture and Sendico service audit](docs/architecture/bff.md) defines
|
||
consumer identity, financial-provider boundaries, reusable components, contract
|
||
gaps and delivery phases. Selected Sendico code has been adapted with recorded
|
||
[provenance](backend/PROVENANCE.md); the projects share no runtime modules.
|
||
|
||
Run `make test-backend`, `make lint-backend` or `make run-backend` from the root.
|
||
The copied runtime installs local authentication transport and initializes its
|
||
account service. Signup/profile endpoints, verification delivery/completion,
|
||
Flutter HTTP adapters and live Sendico operations remain to be wired. See the
|
||
[backend run guide](backend/README.md) for local MongoDB configuration.
|