Registration via API + client-owned email verification
Android UI Tests / ui-tests (push) Has been cancelled

register() now calls POST /auth/register (admin-create) then logs in for a
session, replacing Kratos self-service registration — which never returns the
verification flow id, so the emailed code could never be matched. The verify
screen now starts its own verification flow and sends the single code on
appear; verifyEmail submits the code to that exact stored flow.

- AuthApi: register -> our API + immediate login; startEmailVerification;
  verifyEmail targets DataManager.pendingVerificationFlowId (no codeless fallback)
- DataManager.pendingVerificationFlowId; KratosLoginSuccess.continue_with
- iOS verify screens (standalone + onboarding) send the code on appear + Resend

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-06-03 17:46:43 -05:00
parent 90a1d98322
commit 7c892d2bb6
7 changed files with 244 additions and 51 deletions
@@ -109,6 +109,24 @@ object DataManager : IDataManager {
private val _currentUser = MutableStateFlow<User?>(null)
override val currentUser: StateFlow<User?> = _currentUser.asStateFlow()
/**
* Flow ID of a pending Kratos verification flow.
*
* Set in [AuthApi] right after a registration response carries a
* `continue_with` item of action `show_verification_ui`. Cleared on
* successful verification. While set, [AuthApi.verifyEmail] posts the
* 6-digit code to this exact flow rather than initialising a fresh one
* (the auto-emailed code is bound to a specific flow ID — posting it
* to a new flow always fails).
*
* In-memory only. Kratos's default verification flow lifespan is 1h,
* which is plenty for the user to receive the email and enter the
* code. If they kill the app between sign-up and entering the code
* they'll need a fresh code (handled by the resend path).
*/
private val _pendingVerificationFlowId = MutableStateFlow<String?>(null)
val pendingVerificationFlowId: StateFlow<String?> = _pendingVerificationFlowId.asStateFlow()
// ==================== APP PREFERENCES ====================
private val _themeId = MutableStateFlow("default")
@@ -302,6 +320,16 @@ object DataManager : IDataManager {
persistToDisk()
}
/**
* Set the in-flight Kratos verification flow ID. AuthApi calls this with
* the value pulled out of the registration response's `continue_with`
* `show_verification_ui` item. Pass `null` to clear (e.g. on successful
* verification or sign-out).
*/
fun setPendingVerificationFlowId(flowId: String?) {
_pendingVerificationFlowId.value = flowId
}
// ==================== THEME UPDATE METHODS ====================
fun setThemeId(id: String) {