다크모드
SignIn 화면 — FE 메인테이너 매뉴얼
라우트
| 문맥 | 정본 route |
|---|---|
| 조직 | /auth/sign-in/organization |
| 워크스페이스 | /auth/sign-in/workspace |
이전 로그인 route alias는 제공하지 않는다.
루트 /의 최초 진입은 /auth/sign-in/organization으로 정규화되며 조직 로그인이 선택됩니다. 보호 경로의 미인증 fallback과 계정 종류가 불명확한 일반 로그아웃도 조직 로그인을 기본으로 사용합니다.
Supabase 브라우저 런타임
브라우저 Supabase client는 VITE_SUPABASE_URL과 VITE_SUPABASE_PUBLISHABLE_KEY가 모두 있을 때만 활성화합니다. publishable key는 공개 클라이언트용 저권한 애플리케이션 키이며 사용자 access token이나 서버 secret을 대신하지 않습니다. 다른 public key 환경변수 이름을 alias나 fallback으로 받지 않습니다.
Prototype 샘플 자격증명
| 식별자 유형 | 코드 | 식별자 | 패스워드 | 권한 문맥 |
|---|---|---|---|---|
EMAIL | — | leysys@leysys.com | abcd1234 | organization.owner |
ORGANIZATION_USERNAME | org-a1 | leysys | abcd1234 | organization.admin |
WORKSPACE_USERNAME | ws-a1 | leysys | abcd1234 | workspace.admin |
세 자격증명은 Prototype provider의 유일한 샘플 계약이며 이전 자격증명 alias를 제공하지 않습니다.
컴포넌트
- 조직 페이지:
src/components/auth/sign-in/OrganizationSignInPag.vue - 워크스페이스 페이지:
src/components/auth/sign-in/WorkspaceSignInPag.vue - 계정 유형 navigation:
src/components/auth/sign-in/SignInAccountContextNavigation.vue - 공용 패스워드 field:
src/components/auth/sign-in/SignInPasswordField.vue - 계정 문맥 회귀 계약:
src/components/auth/sign-in/SignInAccountContext.spec.js - 로그인 브랜드 회귀 계약:
src/components/navigation/__tests__/globalHeaderConsistency.spec.js
SSOT 정본은 leysys-design pattern-app/blocks/auth/SignIn의 SignIn 06 — Account context + organization email sign-in switch와 SIGN-IN-ACCOUNT-CONTEXT-NAVIGATION-2026-07-25 결정 문서입니다.
SSOT provenance
- Design PR:
leysys-design#523 - Design merge SHA:
18a7adeaffe42b30eab4db7284c3ba1819562ce5 - EDS exact package:
@leysys/eds@2.28.11(@leysys/eds@2.28.11tag) - Copied registry item: N/A — native
nav/RouterLink에 게시된 EDS segmented class recipe를 적용하며 ToggleGroup wrapper를 복사하지 않습니다. - Migration: ButtonGroup 외형을 segmented route navigation으로 교체하고, SignIn 06의 장식성 supportive copy를 제거합니다.
- Proof boundary: design 실제 route browser contract와 제품
/auth/sign-in/organization,/auth/sign-in/workspace검증 범위까지 proven입니다. - Intentional consumer divergence: 제품은 실제 IAM submit·오류·session flow를 소유하며 design Pattern은 이 동작을 대체하지 않습니다.
정보 구조
계정 문맥 이동과 같은 화면의 로그인 방식 전환 semantics를 섞지 않습니다.
- 계정 유형은 route navigation입니다.
nav안의RouterLink를 사용합니다.- 현재 route에서 파생한 문맥 하나에만
aria-current="page"를 제공합니다. - EDS segmented visual recipe로 두 링크를 하나의 문맥 navigation으로 보이게 합니다.
ESegmentedToggleGroup wrapper는 사용하지 않고nav와 link semantics를 유지합니다.ETabs의tablist/tab/tabpanelsemantics를 붙이지 않습니다.- 유형 선택 아래에 대상 사용자 설명을 반복하지 않습니다.
- 로그인 방식은 조직 route의 한 form 안에서 자격증명 field를 전환하는 보조 action입니다.
- 기본은 Organization 최고관리자/중간관리자/조회자용 조직 코드 + 아이디입니다.
- 이메일 form은 active Organization Owner용 인증 방법입니다. 이메일이 Role을 부여하지 않으며 서버가 인증 후 Owner Role을 재검증합니다.
- 조직 코드 label row 우측의 가시
이메일로 로그인switch는 OFF에서 조직 코드를 활성화하고 아이디를 표시합니다. ON에서는 조직 코드 field를로그인 후 조직 선택placeholder로 비활성화하고 같은 두 번째 field 자리를 이메일로 전환합니다. - switch는
role="switch",aria-checked,aria-label="이메일로 로그인",aria-controls="organization-sign-in-panel"로 현재 상태와 form을 연결합니다. - 카드 푸터는 왼쪽
계정 찾기, 오른쪽계정 생성을 두 로그인 방식에서 같은 위치에 표시합니다.계정 찾기는 기존 Organization Owner 이메일 패스워드 재설정 route로 이동하며 username self-service 복구를 새로 제공하지 않습니다. - ON 전환 후 이메일, OFF 전환 후 조직 코드로 focus를 옮깁니다. 숨은 credential field는 DOM에서 제거하고 두 방식의 입력값·오류·autocomplete section은 분리합니다.
계정 유형은 segmented-looking route navigation, 로그인 방식은 low-emphasis same-screen action입니다. 두 방식을 같은 plane tabs로 반복하거나 route link에 tab role을 붙이지 않습니다.
문구 밀도
헤더는 Leyve Cloud만 표시합니다. 내비게이션의 accessible name은 aria-label="계정 유형"으로 유지하되 가시 계정 유형 라벨은 반복하지 않습니다. 계정 유형별 대상 사용자 설명, 이메일 대상 설명, 비활성 조직 코드 아래의 반복 설명, username 패스워드 문의 helper, 로그인 방식 가시 제목, 운영자 포털 안내는 로그인 결정이나 입력에 필요하지 않으므로 표시하지 않습니다. 조직 코드 label row에는 이메일로 로그인 switch를, 조직 카드 푸터에는 계정 찾기와 계정 생성을 두 mode 모두에서 함께 표시합니다. 워크스페이스 로그인에는 빈 푸터를 만들지 않습니다.
조직 route의 기본 mode는 Organization Username입니다. Owner 계정 생성 확인과 이메일 패스워드 변경 완료 뒤에는 각각 ?sign-up=confirmed, ?password=changed로 이메일 mode를 복원합니다. 계정 생성·패스워드 재설정 화면의 직접 복귀는 ?method=email을 사용합니다.
폼과 자동완성
브라우저 credential 자동완성 충돌을 줄이기 위해 다음 section을 고정합니다.
| 경로 | 사용자명 autocomplete | 패스워드 autocomplete |
|---|---|---|
| 조직 이메일 | section-organization-email username | section-organization-email current-password |
| 조직 Username | section-organization-username username | section-organization-username current-password |
| 워크스페이스 Username | section-workspace-username username | section-workspace-username current-password |
조직 코드와 워크스페이스 코드는 HTML organization autocomplete token의 본래 의미인 회사명과 다르므로 autocomplete="organization"을 사용하지 않습니다. 코드 입력은 autocomplete="off", autocapitalize="none", spellcheck="false"를 유지합니다. 이메일 로그인 mode의 비활성 조직 코드 placeholder 로그인 후 조직 선택은 인증 payload가 아니라 로그인 후 조직 선택을 안내하는 유일한 cue이며 별도 description은 두지 않습니다. 이메일 input placeholder는 샘플 계정 leysys@leysys.com입니다. Username input의 사용자 노출 label은 아이디, placeholder는 예시 값 leysys입니다. 패스워드 input은 placeholder 없이 label만 사용합니다. 이메일 IAM 요청에는 조직 코드를 보내지 않습니다. 워크스페이스 코드 입력은 IAM 계약과 동일한 ^ws-[0-9a-hjkmnp-tv-z]{10}$만 허용하고 레거시 무접두 코드를 위한 별도 분기는 두지 않습니다.
패스워드는 EDS input-group → input + inline-end addon → icon button 합성을 사용합니다. 페이지 전용 CSS나 input padding 보정은 추가하지 않습니다.
오류와 focus
- 모든 입력 오류는
aria-invalid와aria-describedby로 연결합니다. - 오류 문구와 인증 오류는
role="alert"로 알립니다. - submit 검증 실패 후 첫 오류 입력의 exposed
focus()를 호출합니다. - 사용자가 입력을 수정하면 해당 field 오류만 해제합니다.
- 서버 인증 오류는 사용자 존재 여부나 내부 Auth 식별자를 노출하지 않는 일반 문구를 사용합니다.
문구 계약
내부 canonical entity는 Organization, Workspace지만 한국어 UI는 다음 어휘를 사용합니다.
- 조직 계정
- 워크스페이스 계정
- 조직 코드
- 워크스페이스 코드
- 아이디
Organization, Workspace, Organization ID, Workspace 로그인처럼 언어와 계층이 섞인 문구를 새로 추가하지 않습니다.
인증·계정 동작 용어 경계
| 경계 | 한국어 UI | 영어 가시 동작 | 내부 canonical 코드 |
|---|---|---|---|
| 세션 시작 | 로그인 | Sign in | SignIn / signIn |
| 세션 종료 | 로그아웃 | Sign out | SignOut / signOut |
| 가입 journey/page | 계정 생성 | Sign up | SignUp / signUp |
| 계정 리소스 생성 command | 계정 생성 | Create account | CreateAccount / createAccount |
| 계정 영구 삭제 | 계정 삭제 | Delete account | DeleteAccount / deleteAccount |
| 계정 비활성화 | 계정 비활성화 | Deactivate account | DeactivateAccount / deactivateAccount |
| 계정 재활성화 | 계정 재활성화 | Reactivate account | ReactivateAccount / reactivateAccount |
SignIn은 인증 page·pattern·domain, signIn/signOut은 세션 실행 동작입니다. SignUp은 가입 journey/page이며, 가입 과정에서 실제 계정 리소스를 만드는 command/result만 CreateAccount/createAccount로 구분합니다. 제품 소유 영문 이름은 위 표의 canonical identifier만 사용합니다. Supabase SDK가 강제하는 auth.signInWithPassword(), auth.signUp(), auth.signOut()만 adapter 내부 외부 경계로 허용하고 wrapper의 canonical 역할과 섞지 않습니다. DeleteAccount는 복구를 전제로 하지 않는 실제 영구 삭제에만 사용합니다.
식별자 명명 계약
id는 불변 PK/FK에만 사용합니다:principalId,organizationId,workspaceId,authUserId.- 사람이 입력하는 조직·워크스페이스 아이디는 각각
organizationUsername,workspaceUsername을 사용합니다. - 이메일과 username을 함께 처리하는 추상 경계에서만
signInIdentifier를 사용할 수 있습니다. - 요청 secret은
password, 저장 secret은 인증 공급자가 소유합니다.signInPassword는 사용하지 않습니다. Login,loginId,signInId,ORGANIZATION_SIGN_IN_ID,WORKSPACE_SIGN_IN_ID는 폐기 어휘이며 public URL·Edge Function·DB·DTO 어디에도 alias를 두지 않습니다.