feat(frontend): 12단계 계정 보안 화면 — 로그인 코드 단계 · 2단계 인증 · 앱 비밀번호 · 로그인 기록

로그인은 비밀번호가 맞고 2단계를 켠 직원만 코드 단계로 간다. 설정 › 계정에 2단계 인증 · 앱 비밀번호 · 로그인 기록을 더하고,
비밀번호 화면에 2단계를 켠 직원의 코드 칸을 둔다.
비밀(코드 단계의 비밀번호 · 2단계 키 · 앱 비밀번호 값)은 화면 메모리에만 두고, 세션이 바뀌면 그 창을 모두 닫는다 —
12단계부터 다른 기기의 로그아웃이 이 세션을 바로 끊는다. 비밀이 드는 요청은 Pinia 액션 밖에서 보낸다(devtools 기록).
QR 은 uqr 0.1.3(MIT · 의존성 없음 — 2단계 인증 화면 청크에만)으로 SVG 를 그린다(v-html 없음).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 17:25:53 +09:00
parent f9e3b1c57a
commit c31442e639
55 changed files with 8475 additions and 115 deletions
+21 -2
View File
@@ -96,8 +96,8 @@ export const routes: RouteRecordRaw[] = [
],
},
{
// 설정 — 왼쪽 메뉴(계정 › 비밀번호 / 메일 › 서명 · 부재중 자동 응답 · 필터 · 보내기 · 읽기 · 차단한 주소 · 대용량 첨부 · 알림) + 하위 화면.
// /settings 는 첫 메뉴(계정 › 비밀번호)로 바꿔 끼운다 (앱 레일의 "설정")
// 설정 — 왼쪽 메뉴(계정 › 비밀번호 · 2단계 인증 · 앱 비밀번호 · 로그인 기록 / 메일 › 서명 · 부재중 자동 응답 · 필터 · 보내기 · 읽기 ·
// 차단한 주소 · 대용량 첨부 · 알림) + 하위 화면. /settings 는 첫 메뉴(계정 › 비밀번호)로 바꿔 끼운다 (앱 레일의 "설정")
path: '/settings',
component: () => import('@/pages/settings/SettingsLayout.vue'),
meta: { requiresAuth: true, title: '설정' },
@@ -109,6 +109,25 @@ export const routes: RouteRecordRaw[] = [
component: () => import('@/pages/settings/AccountPasswordPage.vue'),
meta: { title: '비밀번호' },
},
{
// 2단계 인증 · 앱 비밀번호 · 로그인 기록 (12단계 — 디자인 README "12단계 — 계정 보안", 계약 5절)
path: 'account/two-factor',
name: SETTINGS_ROUTES.twoFactor,
component: () => import('@/pages/settings/AccountTwoFactorPage.vue'),
meta: { title: '2단계 인증' },
},
{
path: 'account/app-passwords',
name: SETTINGS_ROUTES.appPasswords,
component: () => import('@/pages/settings/AccountAppPasswordsPage.vue'),
meta: { title: '앱 비밀번호' },
},
{
path: 'account/login-history',
name: SETTINGS_ROUTES.loginHistory,
component: () => import('@/pages/settings/AccountLoginHistoryPage.vue'),
meta: { title: '로그인 기록' },
},
{
path: 'mail/signature',
name: SETTINGS_ROUTES.signature,