86 lines
3.8 KiB
Markdown
86 lines
3.8 KiB
Markdown
---
|
|
status: stable
|
|
page_id: A06_Login
|
|
related_pages: ["[[A06_Login/A06_backend]]", "[[A07_Register/A07_frontend]]", "[[auth_rbac]]"]
|
|
last_updated: 2026-07-12
|
|
---
|
|
|
|
# A06_Login — Frontend
|
|
|
|
로그인 화면. 이메일+비밀번호 1차 → 필요 시 OTP 입력으로 전환하는 단일 폼.
|
|
|
|
## 파일 구조
|
|
|
|
| 파일 | 위치 | 역할 |
|
|
|---|---|---|
|
|
| `A06_Login_UI_Auth_Page.ts` | `A06_Login/A06_Login_UI_Auth_Page.ts:1-80` | 로그인 폼 렌더링 + 제출 로직 |
|
|
| `A06_Login_UI_Style.css` | `A06_Login/A06_Login_UI_Style.css:1-52` | 스타일 (theme.css 변수만 사용) |
|
|
| `A06_Login_Api_Fetch.ts` | `A06_Login/A06_Login_Api_Fetch.ts:1-57` | 인증 API 클라이언트 (`credentials: "include"`) |
|
|
|
|
## 컴포넌트 / 함수
|
|
|
|
| 함수 | 위치 | 역할 |
|
|
|---|---|---|
|
|
| `renderA06Login(root)` | `A06_Login/A06_Login_UI_Auth_Page.ts:17` | 카드+폼(email/password/otp/submit) 조립 |
|
|
| `onA06_Login_Submit_Click(event)` | `A06_Login/A06_Login_UI_Auth_Page.ts:34` | 폼 제출 핸들러(검증→요청→OTP 전환/성공) |
|
|
|
|
## API 클라이언트 함수
|
|
|
|
| 함수 | 위치 | 역할 |
|
|
|---|---|---|
|
|
| `requestLogin(email, password)` | `A06_Login/A06_Login_Api_Fetch.ts:30` | `POST /auth/login/request` |
|
|
| `verifyLogin(email, otpCode)` | `A06_Login/A06_Login_Api_Fetch.ts:34` | `POST /auth/login/verify` |
|
|
| `fetchSession()` | `A06_Login/A06_Login_Api_Fetch.ts:38` | `GET /auth/session` → boolean(로그인 여부) |
|
|
| `fetchSessionUser()` | `A06_Login/A06_Login_Api_Fetch.ts:43` | `GET /auth/session` → SessionUser 객체 |
|
|
| `logout()` | `A06_Login/A06_Login_Api_Fetch.ts:54` | `POST /auth/logout` |
|
|
|
|
- `SessionUser` 타입: id, email, name?, role?, company_id?, is_master?
|
|
- `fetchSession`/`fetchSessionUser`/`logout`은 [[a00_app_shell_framework]]에서도 사용 (공유 자원)
|
|
|
|
## 제출 로직 (2단계 폼 전환)
|
|
|
|
1. 이메일 유효성 검사 (isBlank/isValidEmail) → 실패 시 필드 에러
|
|
2. OTP 미요구 상태면 비밀번호 필수, OTP 요구 상태면 6자리 숫자 검증
|
|
3. `otpRequired` false → `requestLogin`, true → `verifyLogin`
|
|
4. 응답 `status === "otp_required"`:
|
|
- otp 필드 노출, password 필드 숨김
|
|
- 제출 버튼 라벨 → `A06_Login_Verify`
|
|
- 토스트 안내(`A06_Login_OtpSent`)
|
|
5. 로그인 성공 → 토스트 후 `navigateTo(ROUTES.B01_ACCOUNT)`
|
|
|
|
## 로컬라이제이션
|
|
|
|
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
|
|
|
|
| UI 요소 | 로케일 키 |
|
|
|---|---|
|
|
| 제목 | `A06_Login_Title` |
|
|
| 이메일/비번/OTP 필드 | `A06_Login_Field_Email`, `A06_Login_Field_Password`, `A06_Login_Field_Otp` |
|
|
| 제출/인증 버튼 | `A06_Login_Submit`, `A06_Login_Verify` |
|
|
| 회원가입 이동 | `A06_Login_ToRegister` |
|
|
| 안내/성공 | `A06_Login_OtpSent`, `A06_Login_Success` |
|
|
| 오류 | `A06_Login_Error_Email`, `A06_Login_Error_Required`, `A06_Login_Error_Request` |
|
|
|
|
## 스타일 (CSS)
|
|
|
|
- `.a06-login` — 페이지 래퍼 (중앙 정렬, 상단 정렬)
|
|
- `.a06-login__card` — 로그인 카드 (max-width: 400px, surface 배경, border)
|
|
- `.a06-login__title` — heading-sm, deep-iris, 중앙 정렬
|
|
- `.a06-login__form` — flex 열 (gap: spacing-16)
|
|
- `.a06-login__submit` / `.a06-login__link` — 전체 너비 버튼
|
|
|
|
## 이벤트 핸들러
|
|
|
|
| 함수 | 위치 | 동작 |
|
|
|---|---|---|
|
|
| `onA06_Login_Submit_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:34` | 로그인/OTP 제출 |
|
|
| (인라인) 회원가입 버튼 | `A06_Login/A06_Login_UI_Auth_Page.ts:75` | A07_REGISTER로 이동 |
|
|
|
|
## 의존성
|
|
|
|
- [[a00_app_shell_framework]] — `navigateTo()` 라우팅
|
|
- `config_frontend.ts` — `ROUTES`, `API_BASE_URL`
|
|
- `common_util_validate` — `isBlank`, `isValidEmail`
|
|
- [[ui_templates]] — `createButton`, `createInputField`, `showLoadingOverlay`/`hideLoadingOverlay`, `showToast`
|
|
- 백엔드 API → [[A06_Login/A06_backend]]
|