Skip to content

Render merge-processing waiting state on RealUnit registration#709

Closed
TaprootFreak wants to merge 1 commit into
stagingfrom
fix/kyc-merge-processing-registration
Closed

Render merge-processing waiting state on RealUnit registration#709
TaprootFreak wants to merge 1 commit into
stagingfrom
fix/kyc-merge-processing-registration

Conversation

@TaprootFreak

Copy link
Copy Markdown
Contributor

Summary

After an account merge (a new wallet signs up with an email that already belongs to an existing account), the app showed a red "Wallet registration not complete" error — even though the merge had succeeded server-side. Cause: right after the merge the registration endpoint briefly returns no userData (the merge is still propagating), and the app inferred a hard failure from the absent userData.

This consumes the new API MergeProcessing registration state and renders a waiting state instead of an error — aligning with "API as Decision Authority" (render the API's state, don't infer business meaning locally).

Changes

  • RealUnitRegistrationState: add mergeProcessing (mirror of the new API value). fromJson is now tolerant (unknown → mergeProcessing) so a future additively-introduced backend state never crashes the client — mirrors SupportIssueState's tolerant parsing.
  • KycEmailVerificationCubit._completeRegistration: when state == mergeProcessing, emit the new KycEmailVerificationMergeProcessing state (no registerWallet, no error). The userData == null branch now only fires for a genuine non-processing failure. The existing _mergeDetected retry path lets the user re-check; once propagation completes it proceeds to registerWallet → success.
  • KycEmailVerificationPage: render a CupertinoActivityIndicator + kycMergeProcessingDescription for the new state; the confirm button stays tappable for re-check. The red error SnackBar no longer fires for the propagation window.
  • KycCubit._runCheckKyc: handle mergeProcessing → emit the existing KycMergeProcessing waiting screen (Refresh → re-check). Keeps the registration-state switch exhaustive.
  • Tests: enum fromJson (known values + unknown fallback), email cubit (mergeProcessing → waiting state, no registerWallet), KYC cubit (registration state mergeProcessing → KycMergeProcessing).

Pair-PR

Backend half: DFXswiss/api#3848 (adds MergeProcessing to GET /v1/realunit/registration when an account merge is still propagating). The API PR should land on develop for the new state to appear on DEV; this app PR is backwards-tolerant (unknown state → waiting) so it is safe regardless of rollout order.

i18n

Reuses existing kycMergeProcessing* keys — no new keys, no arb changes.

Test plan

  • flutter analyze (changed files) clean
  • flutter test — enum, email cubit, KYC cubit, and the email-verification golden (default state, no regression) all pass
  • DEV end-to-end after API#3848 lands: trigger an account merge → during propagation the app shows the merge-processing waiting state (not the red error), then proceeds automatically once propagated

@TaprootFreak TaprootFreak marked this pull request as ready for review June 9, 2026 11:37
@TaprootFreak TaprootFreak marked this pull request as draft June 9, 2026 11:59
@TaprootFreak

Copy link
Copy Markdown
Contributor Author

Closing: the runtime root cause turned out to be different. PROD App Insights shows GET /v1/realunit/registration returns 200 (state=NewRegistration) and POST /v1/realunit/register/wallet returns 400 'No RealUnit registration found' — the merged account has no prior RealUnit registration, so the email-verification flow calls the wrong endpoint (register/wallet instead of the full register/complete form). This is an app-only fix in the email-verification cubit; the MergeProcessing approach here does not address it. A corrected PR follows.

TaprootFreak added a commit that referenced this pull request Jun 9, 2026
## Summary
Fixes the post-account-merge "Wallet registration not complete" error
(red banner) in the RealUnit app, the CONTRIBUTING-aligned way.

When a new wallet signs up with an email that already belongs to an
existing **DFX** account (account merge) and that account has **no prior
RealUnit registration**, `GET /v1/realunit/registration` returns
`state=NewRegistration`. The email-verification step, however, called
`registerWallet` (`POST /register/wallet`) **unconditionally** — that
endpoint only *adds* a wallet to an **existing** registration, so the
API returns `400 "No RealUnit registration found"`.

## Root cause — runtime-confirmed (PROD App Insights)
- `GET /v1/realunit/registration` → **200** (state=NewRegistration,
userData present from existing KYC)
- `POST /v1/realunit/register/wallet` → **400 `{"message":"No RealUnit
registration found"}`** (×4 retries)
- recovery: the user reached the KYC registration form → `POST
/v1/realunit/register/complete` → **201**
- DB: the merged account had no `RealUnitRegistration` step until
`register/complete` created it. 7-day breadth: 7× this 400 (affects
every merge into a DFX account without a prior RealUnit registration).

## Fix (app-only) — single source of registration routing
The email-verification flow is reduced to its actual job: **confirm the
merge** (detect the JWT account change) and hand back to the KYC flow.
`KycCubit` is now the only place that interprets the registration
`state` and routes it (addWallet → link wallet, NewRegistration → full
registration form, AlreadyRegistered → forward) — per CONTRIBUTING.md
"API as Decision Authority". This removes the duplicated, unconditional
`register/wallet` call.

Dead code removed accordingly: `_completeRegistration`,
`_mergeDetected`, the `RealUnitRegistrationService` dependency, the
`KycEmailVerificationRegistrationFailure` state, and the now-unused i18n
key `registerEmailVerificationRegistrationFailed` (de + en).

## Tests
- email cubit (simplified): same account → Failure (link not visited);
changed account → Success (merge confirmed; no registration here); retry
(Failure → Success).
- `kyc_step_states_test` updated for the removed state.

## Test plan
- [x] `flutter analyze` clean
- [x] `flutter test --exclude-tags golden` — full suite passes (2312)
- [x] Coverage Floor Gate replicated locally — scoped **lines 100.0%**
(floor 100)
- [ ] DEV end-to-end: merge into a DFX account without RealUnit
registration → no red error → lands on the registration form →
register/complete

Supersedes #711 (minimal variant) and the earlier incorrect
MergeProcessing PRs DFXswiss/api#3848 + #709.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant