Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/handbook-build-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,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" != "299" ]; then
echo "expected 299 screenshots, got $count" >&2
if [ "$count" != "301" ]; then
echo "expected 301 screenshots, got $count" >&2
exit 1
fi

Expand Down Expand Up @@ -177,10 +177,10 @@ jobs:
exit 1
fi

# Spot-check handbook screenshots assembled from Goldens (299 PNGs).
# Spot-check handbook screenshots assembled from Goldens (301 PNGs).
# Mix of original 01-61 slots, later Golden batches, and referral
# baselines so a regression in any range 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 269-dashboard-insider-unlocked 270-handbook-persona-dca 275-handbook-persona-exit-1j 276-referral-overview 282-referral-payout-row 283-referral-terms-readonly 287-kyc-registration-referral-recognized 288-transaction-history-referral-payout 289-dashboard-referral-entry-and-payout 290-kyc-registration-referral-promo; 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 270-handbook-persona-dca 275-handbook-persona-exit-1j 276-referral-overview 282-referral-payout-row 283-referral-terms-readonly 287-kyc-registration-referral-recognized 288-transaction-history-referral-payout 289-dashboard-referral-entry-and-payout 290-kyc-registration-referral-promo 291-referral-bind-error-invalid 292-referral-bind-error-already-registered; do
# Auth is checked before the file exists: a missing PNG also
# returns 401, so HTTP status cannot prove assembly. Look on disk.
if ! docker exec handbook test -f "/usr/share/nginx/html/screenshots/${name}.png"; then
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ The app supports three wallet modes (`software`, `bitbox`, `debug`) with differe
```bash
rg "^//\s*@no-integration-test:" lib/
```
- Visual-regression Goldens under `test/goldens/screens/` and `test/goldens/widgets/` are also the source of the 299 screenshots served at `handbook.realunit.app`. When you add a handbook page, you MUST add a matching Golden test AND a row in the mapping table at `scripts/assemble-handbook-screenshots.sh` — the handbook will not pick up a Maestro-captured PNG anymore. The `Handbook Build Check` workflow on every PR runs the assembly script and fails loudly if a mapped Golden is missing.
- Visual-regression Goldens under `test/goldens/screens/` and `test/goldens/widgets/` are also the source of the 301 screenshots served at `handbook.realunit.app`. When you add a handbook page, you MUST add a matching Golden test AND a row in the mapping table at `scripts/assemble-handbook-screenshots.sh` — the handbook will not pick up a Maestro-captured PNG anymore. The `Handbook Build Check` workflow on every PR runs the assembly script and fails loudly if a mapped Golden is missing.
- Why: single source of truth — a UI regression that breaks a Golden also breaks the handbook image before either ships; eliminates the previous "two pipelines, two truths" problem.
- See: [`docs/visual-regression-tests.md`](docs/visual-regression-tests.md) section "Handbook screenshots are sourced from Goldens".

Expand Down
27 changes: 15 additions & 12 deletions assets/languages/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -268,45 +268,48 @@
"receiver": "Empfänger",
"recoveryWords": "Wiederherstellungs-Wörter",
"recoveryWordsInvalid": "Wiederherstellungs-Wörter ungültig",
"referralAlreadyBound": "Du hast bereits einen Einladungs- oder Promo-Code eingelöst.",
"referralAlreadyRegistered": "Diese Einladung gilt nur für neue Kundinnen und Kunden.",
"referralAlreadyBound": "Sie haben bereits einen Einladungs- oder Promo-Code eingelöst.",
"referralAlreadyBoundTitle": "Bereits ein Code eingelöst",
"referralAlreadyRegistered": "Einladungs- und Promo-Codes müssen vor dem ersten REALU-Kauf eingelöst werden.",
"referralAlreadyRegisteredTitle": "Nur für neue Kundinnen und Kunden",
"referralChfAtSharePrice": "≈ ${chf} zum ${label}",
"referralCodeChecking": "Code wird geprüft…",
"referralCodeDescription": "Optional. Über den Einladungslink wird der Code automatisch übernommen; hier kannst du ihn auch manuell eingeben.",
"referralCodeHeading": "Hast du einen Empfehlungscode?",
"referralCodeDescription": "Optional. Über den Einladungslink wird der Code automatisch übernommen; hier können Sie ihn auch manuell eingeben.",
"referralCodeHeading": "Haben Sie einen Empfehlungscode?",
"referralCodeHint": "Einladungs- oder Promo-Code",
"referralCodeInvalid": "Dieser Code ist ungültig oder abgelaufen.",
"referralCodeInvalidTitle": "Link ungültig oder abgelaufen",
"referralCodeOptional": "Einladungs- oder Promo-Code (optional)",
"referralCodeSpent": "Dieser Einladungs- oder Promo-Code wurde bereits verwendet.",
"referralCodeSpentTitle": "Code bereits eingelöst",
"referralCodeUnavailable": "Wir konnten den Code gerade nicht prüfen. Bitte versuche es später erneut.",
"referralCodeUnavailable": "Wir konnten den Code gerade nicht prüfen. Bitte versuchen Sie es später erneut.",
"referralCopied": "Kopiert",
"referralCopyInviteLink": "Einladungslink kopieren",
"referralCreateInvite": "Einladungslink erstellen",
"referralCreateInviteDescription": "Gib den Vornamen der Person ein, die du einladen möchtest.",
"referralCreateInviteDescription": "Geben Sie den Vornamen der Person ein, die Sie einladen möchten.",
"referralCreating": "Einladung wird erstellt…",
"referralGuestName": "Name der eingeladenen Person",
"referralGuestNameRequired": "Bitte den Vornamen der eingeladenen Person eingeben.",
"referralInviteRecognized": "Einladung von ${inviter} erkannt. ${inviter} erhält seine Prämie automatisch, sobald du verifiziert bist und deinen ersten Kauf abgeschlossen hast.",
"referralInviteRecognized": "Einladung von ${inviter} erkannt. ${inviter} erhält seine Prämie automatisch, sobald Sie verifiziert sind und Ihren ersten Kauf abgeschlossen haben.",
"referralInvitesLoading": "Offene Einladungen werden geladen…",
"referralInviteUrlLabel": "Persönlicher Einladungslink",
"referralLoading": "Empfehlungen werden geladen…",
"referralNotEligible": "Das Empfehlungsprogramm steht verifizierten Aktionären mit dem erforderlichen Bestand zur Verfügung.",
"referralOpenInvitesExpire": "Offene Einladungen verfallen nach 3 Monaten.",
"referralOverviewHint": "20 REALU pro Weiterempfehlung, sobald der erste Kauf erfolgreich abgewickelt ist.",
"referralOverviewTitle": "Deine Empfehlungen",
"referralOverviewTitle": "Ihre Empfehlungen",
"referralPayout": "Empfehlungsprämie",
"referralPayoutChf": "CHF ${chf} zum Zeitpunkt der Gutschrift",
"referralPromoTitle": "Aktion",
"referralQuarterCap": "In diesem Quartal sind keine weiteren Prämien möglich.",
"referrals": "Empfehlungen",
"referralSelfReferral": "Du kannst deine eigene Einladung nicht einlösen.",
"referralSelfReferral": "Sie können Ihre eigene Einladung nicht einlösen.",
"referralSelfReferralTitle": "Eigene Einladung",
"referralShareInviteLink": "Einladungslink versenden",
"referralSharePrice": "Aktienkurs",
"referralShareText": "Hey ${guestName}, ${hostName} lädt dich ein zu RealUnit: ${url}",
"referralShareTextNoName": "${hostName} lädt dich ein zu RealUnit: ${url}",
"referralsSubtitle": "Erhalte 20 REALU pro Weiterempfehlung",
"referralsSubtitle": "Erhalten Sie 20 REALU pro Weiterempfehlung",
"referralStatusCredited": "Gutgeschrieben",
"referralStatusOpen": "Offen",
"referralTermsAccepting": "Teilnahmebedingungen werden akzeptiert…",
Expand All @@ -315,8 +318,8 @@
"referralTermsRequired": "Bitte zuerst die Teilnahmebedingungen akzeptieren.",
"referralTermsTitle": "Teilnahmebedingungen Referral-Programm",
"referralTotalReceived": "Insgesamt erhalten",
"referralYourInvite": "Deine Einladung",
"referralYourInviteFor": "Deine Einladung für ${guestName}",
"referralYourInvite": "Ihre Einladung",
"referralYourInviteFor": "Ihre Einladung für ${guestName}",
"refresh": "Aktualisieren",
"registerAccountType": "Kontotyp",
"registerCitizenship": "Staatsangehörigkeit",
Expand Down
5 changes: 4 additions & 1 deletion assets/languages/strings_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@
"recoveryWords": "recovery words",
"recoveryWordsInvalid": "Recovery words invalid",
"referralAlreadyBound": "You have already applied an invite or promo code.",
"referralAlreadyRegistered": "This invitation is only for new customers.",
"referralAlreadyBoundTitle": "Code already applied",
"referralAlreadyRegistered": "Invite and promo codes must be applied before the first REALU purchase.",
"referralAlreadyRegisteredTitle": "Only for new customers",
"referralChfAtSharePrice": "≈ ${chf} at ${label}",
"referralCodeChecking": "Checking code…",
"referralCodeDescription": "Optional. The invite link fills this automatically; you can also enter the code here.",
Expand Down Expand Up @@ -302,6 +304,7 @@
"referralQuarterCap": "No further prizes can be credited this quarter.",
"referrals": "Referrals",
"referralSelfReferral": "You cannot apply your own invitation.",
"referralSelfReferralTitle": "Your own invitation",
"referralShareInviteLink": "Share invite link",
"referralSharePrice": "Share price",
"referralShareText": "Hey ${guestName}, ${hostName} is inviting you to RealUnit: ${url}",
Expand Down
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`).

## Screenshots regenerieren

Es gibt keinen separaten Regeneration-Schritt: Die 299 Handbook-Screenshots
Es gibt keinen separaten Regeneration-Schritt: Die 301 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
71 changes: 57 additions & 14 deletions docs/handbook/de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1186,14 +1186,14 @@ <h1>RealUnit Wallet — Handbook</h1>
<span>📱 <b>App:</b> RealUnit Wallet (Flutter)</span>
<span>📂 <b>Code:</b>
<a href="https://github.com/RealUnitCH/app">RealUnitCH/app</a></span>
<span>🧪 <b>Tests:</b> 350 Visual-Regression Goldens (299 davon im Handbook) · 26 Tier-3 Smoke-Flows</span>
<span>🧪 <b>Tests:</b> 355 Visual-Regression Goldens (301 davon im Handbook) · 26 Tier-3 Smoke-Flows</span>
</div>
</section>

<section id="architecture" style="margin-top: 40px">
<h3 style="margin-top: 0">Single Source of Truth</h3>
<p>
Die 299 App-Screenshots dieser Seite sind Goldens aus
Die 301 App-Screenshots dieser Seite sind Goldens aus
<code>test/goldens/{screens,widgets}/&lt;feature&gt;/goldens/macos/&lt;file&gt;.png</code>.
Welcher Golden welcher Handbook-Slot ist, definiert die Mapping-Tabelle in
<code>scripts/assemble-handbook-screenshots.sh</code>. Der Docker-Build
Expand Down Expand Up @@ -1233,7 +1233,7 @@ <h3 style="margin-top: 0">Single Source of Truth</h3>
<b>Pipeline:</b> Page-Edit → <code>flutter test --update-goldens test/goldens/</code>
auf dem self-hosted Runner (Hardware-Determinismus) → neue Baseline committen →
<code>handbook-deploy.yaml</code> baut das Docker-Image aus dem gepushten Branch
und assembliert die 299 Slots aus <code>test/goldens/</code> → Push auf
und assembliert die 301 Slots aus <code>test/goldens/</code> → Push auf
<code>staging</code> deployt das Handbook-Image nach Produktion, via
Cloudflare Tunnel.
</p>
Expand Down Expand Up @@ -11025,7 +11025,7 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
<p class="spec-intro">
Verifizierte Aktionäre mit mindestens 70 REALU im Wallet (geprüft bei
der Einladung und bei der Qualifikation) sehen auf dem Dashboard
die Karte <b>Empfehlungen</b> («Erhalte 20 REALU pro Weiterempfehlung»)
die Karte <b>Empfehlungen</b> («Erhalten Sie 20 REALU pro Weiterempfehlung»)
und denselben Einstieg in den Einstellungen. Sichtbarkeit, Mindestbestand
und Auszahlung entscheidet die DFX API; die App rendert
<code>eligible</code> 1:1. Die Prämie von 20 REALU wird dem Empfehler
Expand Down Expand Up @@ -11100,10 +11100,14 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
Deeplink-Stash stehen. Ein abgelehnter Bind (4xx) zeigt einmal einen
Dialog: Titel <b>Code bereits eingelöst</b> mit Body <b>Dieser Einladungs- oder
Promo-Code wurde bereits verwendet.</b> (Einlösungslimit erreicht);
Titel <b>Link ungültig oder abgelaufen</b> für die übrigen Fälle
<b>Du hast bereits einen Einladungs- oder Promo-Code eingelöst.</b>
(ein Code pro Konto) oder <b>Diese Einladung gilt nur für neue Kundinnen
und Kunden.</b> (Eingabe nur vor dem ersten REALU-Kauf).
Titel <b>Bereits ein Code eingelöst</b> mit Body
<b>Sie haben bereits einen Einladungs- oder Promo-Code eingelöst.</b>
(ein Code pro Konto); Titel <b>Nur für neue Kundinnen und Kunden</b>
mit Body <b>Einladungs- und Promo-Codes müssen vor dem ersten
REALU-Kauf eingelöst werden.</b> (Eingabe nur vor dem ersten Kauf);
Titel <b>Eigene Einladung</b> bei Selbst-Einlösung;
Titel <b>Link ungültig oder abgelaufen</b> nur für unbekannte oder
abgelaufene Codes.
Promo-Codes legt RealUnit unter app.dfx.swiss/realunit an: je Code
ein Gültigkeitsfenster, ein Mindestkauf (Default 200 REALU) und ein
Einlösungslimit als Anzahl Einlösungen (Pflichtfeld, ganze Zahl ab 1,
Expand Down Expand Up @@ -11187,7 +11191,8 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
TB nach Annahme (`283`), Namenseingabe (`284`), Einstellungen-Karte
(`285`), Rechtliche Dokumente letzter Eintrag (`286`), Einladung
erkannt (`287`), Historie mit Prämie (`288`), Dashboard-Einstieg
(`289`), Promo-Aktionstext (`290`).
(`289`), Promo-Aktionstext (`290`), Bind-Overlay ungültig (`291`),
Bind-Overlay nur für neue Kundinnen (`292`).
</p>
<div class="test" id="276-referral-overview">
<div class="head">
Expand Down Expand Up @@ -11238,7 +11243,7 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
/>
</div>
<div class="desc">
Karte <b>Empfehlungen</b> mit «Erhalte 20 REALU pro Weiterempfehlung»,
Karte <b>Empfehlungen</b> mit «Erhalten Sie 20 REALU pro Weiterempfehlung»,
nur wenn die API <code>eligible</code> setzt.
</div>
</div>
Expand Down Expand Up @@ -11359,7 +11364,7 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
</div>
<div class="desc">
Einstieg «Empfehlungen» in den Einstellungen, nur wenn die API
<code>eligible</code> setzt. Kartentext «Erhalte 20 REALU pro
<code>eligible</code> setzt. Kartentext «Erhalten Sie 20 REALU pro
Weiterempfehlung».
</div>
</div>
Expand Down Expand Up @@ -11412,8 +11417,6 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
<div class="desc">
Historie: Prämie mit ganzer Anzahl (20 REALU), Datum und
Frankenwert, fixiert im Zeitpunkt der Gutschrift (TB Ziff. 6).
Im Golden liegt die Prämie ausserhalb des angezeigten Datumsfilters
(Testdaten).
</div>
</div>
<div class="test" id="289-dashboard-referral-entry-and-payout">
Expand All @@ -11429,7 +11432,7 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
/>
</div>
<div class="desc">
Einstieg «Empfehlungen» («Erhalte 20 REALU pro
Einstieg «Empfehlungen» («Erhalten Sie 20 REALU pro
Weiterempfehlung») und Prämie in den letzten Transaktionen.
</div>
</div>
Expand All @@ -11450,6 +11453,46 @@ <h2><span class="num">R</span>Empfehlungen &amp; Promo-Code</h2>
Aktionstext in einem eigenen Fenster (Schließen oder Tippen daneben).
</div>
</div>
<div class="test" id="291-referral-bind-error-invalid">
<div class="head">
<a class="name permalink" href="#291-referral-bind-error-invalid">291-referral-bind-error-invalid</a>
<button class="copy-link" type="button" data-target="291-referral-bind-error-invalid" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">referral_bind_error_dialog_golden_test.dart</span>
</div>
<div class="img">
<img
src="../screenshots/291-referral-bind-error-invalid.png"
alt="Dashboard-Overlay: Link ungültig oder abgelaufen"
/>
</div>
<div class="desc">
Nach einem Bind-4xx für unbekannten oder abgelaufenen Code:
Overlay auf dem Dashboard, Titel <b>Link ungültig oder abgelaufen</b>,
Body <b>Dieser Code ist ungültig oder abgelaufen.</b>,
<b>Schließen</b> mit Tastaturfokus, nicht per Barrier schliessbar.
API-Codes <code>EXPIRED</code> / <code>NOT_FOUND</code>.
</div>
</div>
<div class="test" id="292-referral-bind-error-already-registered">
<div class="head">
<a class="name permalink" href="#292-referral-bind-error-already-registered">292-referral-bind-error-already-registered</a>
<button class="copy-link" type="button" data-target="292-referral-bind-error-already-registered" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">referral_bind_error_dialog_golden_test.dart</span>
</div>
<div class="img">
<img
src="../screenshots/292-referral-bind-error-already-registered.png"
alt="Dashboard-Overlay: Nur für neue Kundinnen und Kunden"
/>
</div>
<div class="desc">
Nach einem Bind-4xx, weil das Konto schon einen REALU-Kauf hat:
derselbe Overlay, Titel <b>Nur für neue Kundinnen und Kunden</b>,
Body <b>Einladungs- und Promo-Codes müssen vor dem ersten REALU-Kauf
eingelöst werden.</b> — nicht «Link ungültig».
API-Code <code>ALREADY_REGISTERED</code>.
</div>
</div>
</details>

<hr class="sep" />
Expand Down
Loading
Loading