Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/handbook-build-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ jobs:
set -euo pipefail
bash scripts/assemble-handbook-screenshots.sh /tmp/handbook-shots
count=$(ls -1 /tmp/handbook-shots/*.png | wc -l | tr -d ' ')
if [ "$count" != "278" ]; then
echo "expected 278 screenshots, got $count" >&2
if [ "$count" != "279" ]; then
echo "expected 279 screenshots, got $count" >&2
exit 1
fi

Expand Down Expand Up @@ -149,11 +149,11 @@ jobs:
exit 1
fi

# Screenshots dir must contain all 278 PNGs assembled from Goldens.
# Screenshots dir must contain all 279 PNGs assembled from Goldens.
# Hit one of them through the auth gate to verify wiring end-to-end.
# Mix of the original 01-61 range and the 62-268 batch (every Golden
# Mix of the original 01-61 range and the 62-269 batch (every Golden
# baseline) so a regression in either half surfaces here.
for name in 01-welcome 11-dashboard 26-terms 35-dashboard-with-balance 46-buy-kyc-required 52-sell-unknown-error 53-buy-payment-details 61-kyc-registration-tax-tin-error 62-welcome-page-android 219-settings-security-page-default 268-phone-number-field-default; do
for name in 01-welcome 11-dashboard 26-terms 35-dashboard-with-balance 46-buy-kyc-required 52-sell-unknown-error 53-buy-payment-details 61-kyc-registration-tax-tin-error 62-welcome-page-android 219-settings-security-page-default 268-phone-number-field-default 269-dashboard-insider-unlocked; do
code=$(curl -s -o /dev/null -w '%{http_code}' -u "${HANDBOOK_USER:-x}:${HANDBOOK_PASS:-x}" "http://127.0.0.1:8080/screenshots/${name}.png")
# 200 (auth happens to match) or 401 (auth fails but file exists)
# both prove the file is on disk. 404 means it was not assembled.
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The auto-opened promotion PRs are idempotent — only one is open per branch pai
- **No third-party APIs**: no direct Ethereum JSON-RPC calls (Infura, Alchemy, public nodes, etc.), no block explorer APIs (Etherscan, …), no price feeds, no analytics endpoints, no third-party SDKs that call out over the network.
- If a feature needs on-chain data (e.g. native ETH balance, transaction status, token balance), add a new endpoint to [`DFXswiss/api`](https://github.com/DFXswiss/api) and let the app call that endpoint. The API is the single gateway.
- All network calls must go through `AppStore.httpClient` with `buildUri(_host, …)` — `_host` resolves to the DFX API host via `ApiConfig`. Do not instantiate `http.Client`/`Dio`/`Web3Client` against other hosts.
- **One scoped exception — crash reporting.** Builds that inject `--dart-define=SENTRY_DSN=...` deliver crash reports to the company-operated crash-reporting service ([`lib/setup/error_handling/crash_reporting.dart`](lib/setup/error_handling/crash_reporting.dart)). This is first-party infrastructure telemetry, not a third-party service: without an injected DSN (all local and test builds) the SDK never starts and produces no network traffic, and the delivered data is limited to error events — no PII, no screenshots, no performance tracing, no session telemetry (the exact pinned option surface lives in `crash_reporting.dart`). Widening what is sent (breadcrumbs with request URLs, user context, attachments) is a review-blocking change, not a config tweak.

## API as Decision Authority — CRITICAL

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.handbook
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Build context is the repo root; only docs/handbook/, scripts/, and
# test/goldens/ are copied in.
#
# The 61 screenshots (`screenshots/NN-name.png`) are assembled from the
# The handbook screenshots (`screenshots/NN-name.png`) are assembled from the
# visual-regression Golden baselines under `test/goldens/screens/` via
# scripts/assemble-handbook-screenshots.sh — one Golden per handbook
# entry, see the mapping in that script. `docs/handbook/screenshots/` is
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ The transport is USB on Android and Bluetooth on iOS; the original BitBox 02 has
| Sell — DFX fiat off-ramp (IBAN) | always | mvp | widget (`sell/sell_page_test.dart`) + golden (`sell/sell_golden_test.dart`, `sell/sell_bank_account_selection_golden_test.dart`); added via [#321](https://github.com/RealUnitCH/app/pull/321) |
| KYC: Email + 2FA gate | always | mvp | widget (`kyc_email_page_test.dart`, `kyc_2fa_page_test.dart`) + golden (`kyc/kyc_email_golden_test.dart`, `kyc/kyc_email_verification_golden_test.dart`, `kyc/kyc_2fa_golden_test.dart`); cubit added via [#319](https://github.com/RealUnitCH/app/pull/319) |
| KYC: Registration + BitBox EIP-712 sign | always | mvp | widget (`kyc_registration_page_test.dart`) + golden (`kyc/kyc_registration_golden_test.dart`) + unit (`eip712_signer_test.dart`); cubit / `registration_submit` / sign-flow integration tests added via [#319](https://github.com/RealUnitCH/app/pull/319) + [#320](https://github.com/RealUnitCH/app/pull/320) |
| KYC: Personal data (correction after an ident data mismatch) | always | mvp | widget (`kyc_personal_data_page_test.dart`) + golden (`kyc/kyc_personal_data_golden_test.dart`) + cubit (`kyc_personal_data_cubit_test.dart`) |
| KYC: Nationality | always | mvp | widget (`kyc_nationality_page_test.dart`) + golden (`kyc/kyc_nationality_golden_test.dart`) |
| KYC: Financial data | always | mvp | widget (`kyc_financial_data_page_test.dart`) + golden (`kyc/kyc_financial_data_golden_test.dart`, `kyc/kyc_financial_data_failure_golden_test.dart`, `kyc/kyc_financial_data_loading_golden_test.dart`, `kyc/kyc_financial_data_questions_golden_test.dart`) |
| KYC: Ident | always | mvp | widget (`kyc_ident_page_test.dart`) + golden (`kyc/kyc_ident_golden_test.dart`) |
| KYC: Pending / Completed / Failure | always | mvp | widget (`kyc/subpages/kyc_*_page_test.dart`) + golden (`kyc/kyc_pending_golden_test.dart`, `kyc/kyc_completed_golden_test.dart`, `kyc/kyc_failure_golden_test.dart`, `kyc/kyc_loading_golden_test.dart`) |
| KYC: AccountMergeRequested / UnsupportedStepFailure | always | mvp | golden (`kyc/kyc_account_merge_golden_test.dart`); cubit paths added via [#319](https://github.com/RealUnitCH/app/pull/319) |
| KYC: AccountMergeRequested / UnsupportedStepFailure | always | mvp | widget (`kyc/subpages/kyc_unsupported_step_page_test.dart`) + golden (`kyc/kyc_account_merge_golden_test.dart`, `kyc/kyc_unsupported_step_golden_test.dart`); cubit paths added via [#319](https://github.com/RealUnitCH/app/pull/319) |
| `DFXAuthService` (lazy auth + 401 retry) | always | mvp | — (unit tests added via [#319](https://github.com/RealUnitCH/app/pull/319) + [#321](https://github.com/RealUnitCH/app/pull/321)) |
| `balance_service` (balance fetch + cache) | always | mvp | unit (`balance_service_test.dart`) |
| `format_fixed` / `parse_fixed` (decimal helpers) | always | mvp | unit (`format_fixed_test.dart`, `parse_fixed_test.dart`) |
Expand Down
9 changes: 6 additions & 3 deletions assets/languages/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,12 @@
"kycMergeProcessingTitle": "Konten werden zusammengeführt",
"kycPending": "Daten werden geprüft",
"kycPendingDescription": "Ihr folgender Schritt ist gerade noch unter Prüfung: ${step}. Bitte haben Sie noch ein wenig Geduld und schauen Sie zu einem späteren Zeitpunkt nochmal rein.",
"kycPersonalDataDescription": "Bitte überprüfen Sie Ihre Angaben und korrigieren Sie alles, was nicht mit Ihrem Ausweisdokument übereinstimmt.",
"kycPersonalDataFailed": "Persönliche Daten konnten nicht gespeichert werden:\n${message}",
"kycSignatureUnsupportedDescription": "Dieses Feature erfordert eine EIP-712-Signatur. Im Debug-Modus (Adresse + Signatur) ist dies technisch nicht möglich. Bitte verwenden Sie eine Software-Wallet oder BitBox, um RealUnit zu nutzen.",
"kycSignatureUnsupportedTitle": "Signatur nicht verfügbar",
"kycUnsupportedStepDescription": "Der aktuelle KYC-Schritt (${step}) kann in dieser App nicht abgeschlossen werden. Bitte kontaktieren Sie den Support.",
"kycUnsupportedStepDescription": "Der nächste Schritt Ihrer Verifizierung kann in dieser App nicht abgeschlossen werden. Aktualisieren Sie, um zu prüfen, ob er weitergelaufen ist, oder wenden Sie sich an unser Support-Team, das dann übernimmt.",
"kycUnsupportedStepTitle": "Dieser Schritt wird anderswo fortgesetzt",
"label": "Bezeichnung",
"languageEnglish": "Englisch",
"languageGerman": "Deutsch",
Expand Down Expand Up @@ -160,7 +163,6 @@
"legalDocumentLoadFailedDescription": "Beim Laden des Dokuments ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
"legalDocuments": "Rechtsdokumente",
"location": "Ort",
"logout": "Abmelden",
"max": "Max",
"month": "Monat",
"name": "Name",
Expand Down Expand Up @@ -372,6 +374,7 @@
"settingsCurrencyLoadFailed": "Währungsliste konnte nicht geladen werden",
"settingsCurrencyLoadFailedDescription": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.",
"settingsDeleteWallet": "Wallet zurücksetzen",
"settingsInsiderFeaturesUnlocked": "Insider-Funktionen freigeschaltet",
"settingsLanguageLoadFailed": "Sprachliste konnte nicht geladen werden",
"settingsLanguageLoadFailedDescription": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.",
"settingsLanguages": "Sprachen",
Expand Down Expand Up @@ -461,4 +464,4 @@
"youPay": "Sie bezahlen",
"youReceive": "Sie erhalten",
"youSell": "Sie verkaufen"
}
}
9 changes: 6 additions & 3 deletions assets/languages/strings_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,12 @@
"kycMergeProcessingTitle": "Merging your accounts",
"kycPending": "Data is being verified",
"kycPendingDescription": "Your next step is currently being reviewed: ${step}. Please be patient and check back later.",
"kycPersonalDataDescription": "Please check your details and correct anything that does not match your identity document.",
"kycPersonalDataFailed": "Could not save your personal data:\n${message}",
"kycSignatureUnsupportedDescription": "This feature requires an EIP-712 signature. The Debug mode (address + signature) cannot produce one. Please use a Software Wallet or a BitBox to use RealUnit.",
"kycSignatureUnsupportedTitle": "Signature not available",
"kycUnsupportedStepDescription": "The current KYC step (${step}) cannot be completed in this app. Please contact support.",
"kycUnsupportedStepDescription": "The next step of your verification cannot be completed in this app. Refresh to check whether it has moved on, or contact our support team and they will take it from here.",
"kycUnsupportedStepTitle": "This step continues elsewhere",
"label": "Label",
"languageEnglish": "English",
"languageGerman": "German",
Expand Down Expand Up @@ -160,7 +163,6 @@
"legalDocumentLoadFailedDescription": "Something went wrong while loading this document. Please try again.",
"legalDocuments": "Legal documents",
"location": "Location",
"logout": "Logout",
"max": "Max",
"month": "Month",
"name": "Name",
Expand Down Expand Up @@ -372,6 +374,7 @@
"settingsCurrencyLoadFailed": "Failed to load currencies",
"settingsCurrencyLoadFailedDescription": "Please check your internet connection and try again.",
"settingsDeleteWallet": "Reset wallet",
"settingsInsiderFeaturesUnlocked": "Insider features unlocked",
"settingsLanguageLoadFailed": "Failed to load languages",
"settingsLanguageLoadFailedDescription": "Please check your internet connection and try again.",
"settingsLanguages": "Languages",
Expand Down Expand Up @@ -461,4 +464,4 @@
"youPay": "You pay",
"youReceive": "You receive",
"youSell": "You sell"
}
}
2 changes: 1 addition & 1 deletion docs/handbook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ deployten Image (`handbook.realunit.app` / `dev-handbook.realunit.app`).

## Screenshots regenerieren

Es gibt keinen separaten Regeneration-Schritt: Die 278 Handbook-Screenshots
Es gibt keinen separaten Regeneration-Schritt: Die 279 Handbook-Screenshots
sind direkt die Golden-Baselines unter `test/goldens/` (gemappt in
`scripts/assemble-handbook-screenshots.sh`). Eine UI-Änderung an einer der
gemappten Pages produziert beim `flutter test test/goldens` einen Diff —
Expand Down
107 changes: 107 additions & 0 deletions docs/handbook/de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@
justify-content: center;
padding: 14px;
}
.test .img.img-multi {
flex-wrap: wrap;
gap: 12px;
}
.test .img img {
max-width: 220px;
height: auto;
Expand Down Expand Up @@ -1002,6 +1006,9 @@
<li>
<a href="#spec-78"><span class="spec-num">78</span>Telefonnummer-Eingabe</a>
</li>
<li>
<a href="#spec-79"><span class="spec-num">79</span>Insider-Freischaltung — Bezahlen &amp; Senden</a>
</li>
<li>
<a href="#spec-web"><span class="spec-num">W</span>Web · realunit.app</a>
</li>
Expand Down Expand Up @@ -7942,6 +7949,106 @@ <h2><span class="num">78</span>Telefonnummer-Eingabe</h2>

<hr class="sep" />

<details id="spec-79" class="spec" open>
<summary>
<div class="spec-head">
<div class="lhs">
<h2><span class="num">79</span>Insider-Freischaltung — Bezahlen &amp; Senden</h2>
<div class="file">test/goldens/screens/dashboard/</div>
</div>
<div class="rhs">
<b>2 Screens</b>
<div class="links">
<a
href="https://github.com/RealUnitCH/app/tree/develop/test/goldens/screens/dashboard"
>Goldens ↗</a
>
</div>
</div>
</div>
</summary>
<p class="spec-intro">
Die Funktionen <b>Bezahlen</b> (OpenCryptoPay) und <b>Senden</b> (REALU-Transfer
an eine andere Wallet) sind bewusst versteckt (Soft-Launch) und erscheinen erst
nach einer einmaligen Freischaltung auf dem Gerät.
</p>

<div class="tests cols-2">
<div class="test" id="insider-unlock">
<div class="head">
<a class="name permalink" href="#insider-unlock">insider-unlock</a>
<button class="copy-link" type="button" data-target="insider-unlock" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">settings_page_default.png · dashboard_with_balance.png · dashboard_insider_unlocked.png</span>
</div>
<div class="img img-multi">
<div>
<img
src="../screenshots/12-settings.png"
alt="Einstellungen mit Versionsnummer unten"
/>
<p><em>Einstellungen — die Versionsnummer ganz unten ist der Tap-Auslöser.</em></p>
</div>
<div>
<img
src="../screenshots/35-dashboard-with-balance.png"
alt="Dashboard vor der Freischaltung — nur Kaufen und Verkaufen"
/>
<p><em>Vorher: nur „Kaufen" und „Verkaufen".</em></p>
</div>
<div>
<img
src="../screenshots/269-dashboard-insider-unlocked.png"
alt="Dashboard nach der Freischaltung — alle vier Aktionen"
/>
<p><em>Nachher: alle vier Aktionen.</em></p>
</div>
</div>
<div class="desc">
<p>Anleitung:</p>
<ol>
<li>Einstellungen öffnen (Hamburger-Icon rechts oben im Dashboard).</li>
<li>Ganz nach unten scrollen bis zur Versionsnummer.</li>
<li>Siebenmal kurz hintereinander auf die Versionsnummer tippen.</li>
<li>Es erscheint die Bestätigung „Insider-Funktionen freigeschaltet".</li>
<li>
Zurück im Dashboard stehen neben <b>Kaufen</b> und <b>Verkaufen</b> neu
<b>Bezahlen</b> und <b>Senden</b>.
</li>
</ol>
<p>
Die Freischaltung bleibt dauerhaft auf dem Gerät erhalten (auch nach
App-Neustart) — sie wird lokal per <code>SharedPreferences</code>
gespeichert. Eine Neuinstallation der App setzt sie zurück.
OpenCryptoPay-Zahlungslinks funktionieren unabhängig von der
Freischaltung — der Deeplink bleibt bewusst immer offen. Tippen auf die
Versionsnummer nach erfolgter Freischaltung hat keine Wirkung mehr.
</p>
</div>
</div>
<div class="test" id="269-dashboard-insider-unlocked">
<div class="head">
<a class="name permalink" href="#269-dashboard-insider-unlocked">269-dashboard-insider-unlocked</a>
<button class="copy-link" type="button" data-target="269-dashboard-insider-unlocked" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">screens/dashboard/goldens/macos/dashboard_insider_unlocked.png</span>
</div>
<div class="img">
<img
src="../screenshots/269-dashboard-insider-unlocked.png"
alt="Dashboard mit freigeschalteten Insider-Aktionen"
/>
</div>
<div class="desc">
Dashboard mit freigeschalteter Insider-Ansicht: neben <b>Kaufen</b> und
<b>Verkaufen</b> erscheinen zusätzlich <b>Bezahlen</b> und <b>Senden</b>.
Golden-Quelle: <code>dashboard_insider_unlocked.png</code> aus
<code>dashboard_golden_test.dart</code>.
</div>
</div>
</div>
</details>

<hr class="sep" />

<details id="spec-web" class="spec" open>
<summary>
<div class="spec-head">
Expand Down
4 changes: 2 additions & 2 deletions docs/screens.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Column meaning:
screen, or `—` if the screen has no Golden baseline. Each slot is a
Visual-Regression Golden under `test/goldens/`, mapped to its handbook
position by `scripts/assemble-handbook-screenshots.sh`. The handbook now
covers **all 278 Golden baselines** — every screen **plus every tested
covers **all 279 Golden baselines** — every screen **plus every tested
state variant** (Default / Loading / Error / Snackbar / Dropdown /
Validation / Confirm / Success / Failure …), including the areas that were
previously absent: Support (email capture, tickets, chat), Settings
Expand Down Expand Up @@ -136,7 +136,7 @@ one shared form-widget baseline (`PhoneNumberField`), which is not a screen.
`243`–`245`. `SetupPinPage` also backs the `settingsChangePin` route
(`/settings/security/changePin`) via a second constructor; that reuse has no
separate Golden and is not given its own row.
- **Handbook numbering.** Each of the 278 handbook slots is a Visual-Regression
- **Handbook numbering.** Each of the 279 handbook slots is a Visual-Regression
Golden under `test/goldens/`, mapped to its handbook position by
`scripts/assemble-handbook-screenshots.sh`. A parallel Tier-3 Maestro flow
(`.maestro/handbook/NN-*.yaml`) covers navigation/tap-routing smoke for the
Expand Down
Loading
Loading