```mermaid flowchart TD A[1. backend/main.go 실행] --> B[.env 로드, Logger/DB/IDP 초기화] B --> C[API 라우트 등록] C --> D[/api/v1/auth/*, /api/v1/user/me 등] E[2. userfront/main.dart 실행] --> F[Flutter 앱 초기화] F --> G[GoRouter 생성] G --> H[/ko/connect 또는 /ko/signin 진입] H --> I[LoginScreen 생성] I --> J[phoneOnly 모드 여부 결정] J --> K[사용자 입력] K --> L{로그인 타입} L -->|비밀번호| M[_handlePasswordLogin] L -->|전화번호 connect| N[_handlePhoneOnlyLogin] M --> O[AuthProxyService.loginWithPassword] N --> P[AuthProxyService.loginWithPhoneOnly] O --> Q[POST /api/v1/auth/password/login] P --> R[POST /api/v1/auth/phone-login] Q --> S[backend AuthHandler.PasswordLogin] R --> T[backend PhoneLogin] S --> U[IDP 인증] T --> U U --> V{login_challenge 있음?} V -->|예| W[Hydra/OIDC accept 처리] V -->|아니오| X[sessionJwt/token 응답] W --> Y[redirectTo + token 응답] X --> Z[userfront 성공 처리] Y --> Z Z --> AA[_onLoginSuccess] AA --> AB[AuthTokenStore.setToken] AB --> AC{redirectTo 있음?} AC -->|예| AD[webWindow.redirectTo] AC -->|아니오| AE[profile load] AE --> AF[dashboard 이동] ``` ```mermaid sequenceDiagram participant Browser as Browser participant App as userfront (Flutter) participant Store as AuthTokenStore participant Proxy as AuthProxyService participant API as backend /api/v1/auth participant IDP as IDP/Hydra/Kratos Browser->>App: /ko/connect 또는 /ko/signin 진입 App->>App: GoRouter가 LoginScreen 생성 App->>Browser: 로그인 UI 렌더링 Browser->>App: 로그인 정보 입력 후 제출 alt 비밀번호 로그인 App->>Proxy: loginWithPassword(loginId, password, loginChallenge?) Proxy->>API: POST /api/v1/auth/password/login API->>IDP: 자격 증명 검증 IDP-->>API: 세션 토큰/쿠키 API-->>Proxy: sessionJwt, token, provider, redirectTo? else connect 전화번호 로그인 App->>Proxy: loginWithPhoneOnly(phoneNumber, loginChallenge?) Proxy->>API: POST /api/v1/auth/phone-login API->>IDP: 전화번호 기반 인증 IDP-->>API: 세션 토큰/쿠키 API-->>Proxy: sessionJwt, token, provider, redirectTo? end Proxy-->>App: JSON 응답 App->>App: _onLoginSuccess(token, provider, redirectTo) App->>Store: setToken(token, provider) alt redirectTo 있음 App->>Browser: redirectTo로 이동 else OIDC challenge 있음 App->>Proxy: acceptOidcLogin(login_challenge, token) Proxy->>API: POST /api/v1/auth/oidc/login/accept API->>IDP: login accept 처리 IDP-->>API: OIDC redirect URL API-->>App: redirectTo + token App->>Store: setToken(...) App->>Browser: OIDC redirect else 일반 로그인 App->>App: profile load App->>Browser: /{locale}/dashboard 이동 end ``` 핵심 요약: * `backend/main.go`가 API를 열고 * `userfront/main.dart`가 `/ko/connect`를 `LoginScreen(phoneOnly: true)`로 연결하고 * `login_screen.dart`가 `AuthProxyService`를 통해 `/api/v1/auth/password/login` 또는 `/api/v1/auth/phone-login`을 호출한 뒤 * 백엔드가 토큰을 주면 `AuthTokenStore`에 저장하고 * `redirectTo`가 있으면 그쪽으로, 없으면 `dashboard`로 이동합니다.