Skip to content

User Login Flow

Plan Metadata

  • Plan type: sub-plan
  • Parent plan: auth-system.md
  • Depends on:
  • mobile-signin-flow.md
  • mobile-auth-gating.md
  • frontend-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-path
    render 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.md and auth-system.md.

After all stages are approved, apply .agent/skills/reconcile-plans/SKILL.md to propagate contract updates across linked plans.