User Login Flow
Plan Metadata
- Plan type:
sub-plan - Parent plan:
auth-system.md - Depends on:
mobile-signin-flow.mdmobile-auth-gating.mdfrontend-logging.md- Status:
documentation
Status semantics: - draft: Plan is being created or updated and is not final. - approved: Plan is approved but not yet applied in code. - documentation: Code currently exists and matches the plan contract.
Update rule: - When an existing plan is edited, set status to draft until re-approved.
System Intent
- What is being built: User-facing mobile login and verify experience contract.
- Primary consumer(s):
main/app/app/(auth)/_layout.tsx,main/app/app/(auth)/login.tsx,main/app/app/(auth)/verify.tsx. - Boundary (black-box scope only): What the user sees and does across login and verify screens, and the required auth-provider support behavior behind those interactions.
Stage Gate Tracker
- [x] Stage 1 Mermaid approved
- [x] Stage 2 I/O contracts approved
- [x] Stage 3 pseudocode/technical details approved or skipped
1. Mermaid Diagram
Reference: .agent/skills/create-mermaid-diagram/SKILL.md
flowchart TD
A[Auth Stack Layout - main/app/app/(auth)/_layout.tsx] --> B[Login Screen - main/app/app/(auth)/login.tsx]
B -->|Continue with email| C[Mobile Signin Contract Boundary - docs/plans/mobile-signin-flow.md]
C -->|request accepted| D[Verify Screen - main/app/app/(auth)/verify.tsx]
D -->|6-digit code| C
C -->|session completed| E[Auth Gating Boundary - docs/plans/mobile-auth-gating.md]
D -->|Change email| B 2. Black-Box Inputs and Outputs
Keep this short. Define types in JSON-style blocks and capture each flow with path-level rows. - Flow naming rule: each flow uses this format: - ### Flow: `<flowname>` - - Test files: <path/to/test_file.ext>, ... (or N/A when no automated test is required) - - Core files: <path/to/core_file.ext>, ... - N/A means explicit no-test-required waiver for that flow (not a missing mapping).
Global Types
Define shared types used across multiple flows.
LoginFormInput {
email: string
}
LoginUiState {
submitting: boolean
error?: string | null
}
VerifyFormInput {
code: string (6 digits)
}
VerifyUiState {
submitting: boolean
success: boolean
error?: string | null
}
StandardError {
status?: number
code?: string
message: string
}
Flow: main/app/app/(auth)/_layout.tsx.AuthLayout
- Test files:
N/A - Core files:
main/app/app/(auth)/_layout.tsx
Type Definitions
AuthLayoutInput {
route: "/(auth)/login" | "/(auth)/verify"
}
AuthLayoutOutput {
stack_header_hidden: boolean
logging_flow: "auth"
}
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
|---|---|---|---|---|---|
auth-layout.login-route | AuthLayoutInput route=/(auth)/login | AuthLayoutOutput stack_header_hidden=true logging_flow=auth | happy path | login screen is rendered under shared auth logging context | Y |
auth-layout.verify-route | AuthLayoutInput route=/(auth)/verify | AuthLayoutOutput stack_header_hidden=true logging_flow=auth | happy path | verify screen is rendered under same auth stack boundary | Y |
Flow: main/app/app/(auth)/login.tsx.LoginScreen
- Test files:
N/A - Core files:
main/app/app/(auth)/login.tsx
Type Definitions
LoginScreenInput {
form: LoginFormInput
}
LoginScreenOutput {
ui_state: LoginUiState
navigation_target?: "/(auth)/verify"
navigation_params?: { email: string }
}
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
|---|---|---|---|---|---|
login-screen.continue-success | LoginScreenInput form.email valid | LoginScreenOutput ui_state.submitting=false navigation_target=/(auth)/verify | happy path | requires requestPasswordlessSignIn support from mobile-signin-flow.md | Y |
login-screen.continue-failure | LoginScreenInput form.email invalid or auth request failure | LoginScreenOutput ui_state.error set | error | user sees actionable error text and remains on login screen | Y |
login-screen.legal-links | LoginScreenInput user taps terms/privacy links | LoginScreenOutput navigation_target omitted | subpath | launches external link flow without auth state mutation | Y |
Flow: main/app/app/(auth)/verify.tsx.VerifyScreen
- Test files:
N/A - Core files:
main/app/app/(auth)/verify.tsx
Type Definitions
VerifyScreenInput {
email_param?: string
form: VerifyFormInput
}
VerifyScreenOutput {
ui_state: VerifyUiState
change_email_target?: "/(auth)/login"
}
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
|---|---|---|---|---|---|
verify-screen.auto-submit-success | VerifyScreenInput form.code valid 6-digit code | VerifyScreenOutput ui_state.success=true | happy path | requires completePasswordlessSignInWithCode support from mobile-signin-flow.md | Y |
verify-screen.invalid-code | VerifyScreenInput form.code invalid | VerifyScreenOutput ui_state.error="That code is not correct." | error | validation failure without route change | Y |
verify-screen.change-email | VerifyScreenInput user presses Change email | VerifyScreenOutput change_email_target=/(auth)/login | subpath | user restarts login with a different email | Y |
3. Pseudocode / Technical Details for Critical Flows (Optional)
- Flow name::
user-login-happy-pathrender auth layout stack user enters email on login screen and presses Continue call requestPasswordlessSignIn(email) if successful, navigate to verify with email param user enters 6-digit code auto-submit code when complete call completePasswordlessSignInWithCode(code) if successful, auth session is materialized and gating flow continues - Implementation notes:
- This sub-plan documents UI-facing behavior only.
- API and backend auth contracts are owned by
mobile-signin-flow.mdandauth-system.md.
4. Handoff to Related Plan Reconciliation
After all stages are approved, apply .agent/skills/reconcile-plans/SKILL.md to propagate contract updates across linked plans.