Skip to content

HBEA100_로그인 ​

(Hereby) 직원 앱 > 로그인

앱직원 앱 (Employee App / ESS, 포트 4002)
대상 사용자미인증 방문자 → 조건1 [직원(self scope)] 발급 대상
프로토타입TBU
관련 정책[[POL_권한(RBAC)]]
Statusreview
Owner카나 (PM)

개요 ​

직원 앱 로그인 화면(/employee-app/signin). 타이틀 "hereby 웍스" + 서브타이틀 = 조직명("hereby Medical") + 앱 로고 (2026-08-19 라이브 실증 — 구 "직원 앱에 로그인하세요" 타이틀은 미현행). 인증 방식 탭 2종: "비밀번호"(ID/비밀번호) / "휴대폰 인증"(ID → 인증번호 발송 → SMS OTP). "로그인" 버튼은 입력 전 disabled, 하단 "비밀번호 찾기" 링크. 인증 성공 시 근무 탭 홈(self scope). 휴대폰 인증 OTP는 LoginOtpCode에 발급·검증된다. 계정 레이어 전환(7/16 코드)은 라이브 반영 확인됨(브랜딩·탭 구성 실측 일치).

문서 히스토리 ​

날짜작성자팀변경 내용
2026-07-06카나PM최초 작성
2026-07-13카나PM버튼 행동 명세 보강
2026-07-21카나PMGC700 깊이 재작성
2026-07-21카나PM셀 스타일 확정판 적용 (콸 승인)
2026-08-19카나PM라이브 실증(세션 만료 계기): 타이틀 "hereby 웍스"·조직명 서브타이틀·로그인 disabled·"비밀번호 찾기" 확인, 계정 레이어 ⚠ 해소
2026-09-11카나PM로그인 식별자 대소문자 무시 동작 규칙 반영(#647 머지) — 이메일·사번 대소문자 미구분 조회, 입력 표기 우선→대소문자 무시 폴백. 근거 = 커밋(#647)
2026-10-02카나PM첫 로그인 강제 비밀번호 변경 안내·검사를 병원 설정(userPasswordPolicy)으로 + 규칙 변경 안내(권한자만) 행 추가(ㄴ23-1)(c6347029·382eec17, #995) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
2026-10-03카나PMworks 가입 링크 진입 규칙 신설 00-1 — /works/join?code= 랜딩(스토어 자동 이동/PC 버튼)·조직 선택 자동 입력·연결 확인 전 서버 미전환·환경별 허용 호스트(87f779d7·74360092·99444bb5, #1018) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
2026-10-14카나PM키 로그인(패스키·기기 키) 50~ㄴ55 신설 + 로그인 보안 규칙 60~ㄴ63(계정 잠금·이상 로그인 캡차·패스키 넛지·패스키 전용 거부) + 안내 문자 로그인 링크 프리필 00-2 — 10/13 인증 스택(#1227·#1234~#1236·#1239, 5826f16·e4932b0·731d1fb·ffc824c·9f5e7b2·42d28f7 외) 반영. 커밋 근거, 키 로그인 UI는 키 등록 기기 필요라 라이브 실사 이월(TBU). 잠금 정책 Open Question 해소 - 카나/PM

Data I/O ​

Server → Client ​

변수DB 엔티티.컬럼값 없을 때비고
$LoginOtpCode (발급 상태 파생)idle(초기)"발송 중..." / 입력 대기 상태 표시
$인증 세션 (self scope)없음(로그인 폼 유지)⚠ 계정 레이어 전환(7/16 코드) 반영 여부 라이브 확인 필요

Client → Server ​

액션전달 값tRPC procedure권한 토큰
비밀번호 로그인id, passwordsdk.auth.signin() (추정)(미인증 → 세션 발급)
인증번호 받기idsdk.auth.requestOtp() (추정)(미인증)
인증번호 검증id, otpsdk.auth.verifyOtp() (추정)(미인증 → 세션 발급)

발급/생성: 비밀번호·OTP 검증 → ${employee_session} 발급 / 인증번호 받기 → LoginOtpCode 생성. procedure 명 확정값 = TBU. ⚠ 계정 레이어 전환(7/16 코드)으로 세션 발급 경로가 바뀌었는지 라이브 확인 필요.

외부 통합 (해당 시) ​

외부 시스템데이터동기/비동기비고
SMS 발송휴대폰 인증 OTP 문자비동기발송사·재발송 정책 = TBU

화면 플로우 ​


로그인 사양표 ​

번호항목/기능명타입사양 및 기능 설명연관/영향 범위비고
00화면 진입 조건-미인증 방문자 공통 노출.
 - CASE01 [세션 보유]: 근무 탭 홈으로 이동(로그인 화면 skip)
$⚠ 계정 레이어 전환(7/16 코드) 반영 여부 라이브 확인 필요
00-1works 가입 링크 진입 (로그인 이전 단계)Rule• 병원 코드가 든 링크 https://{랜딩 호스트}/works/join?code={병원코드} 로 앱 설치·조직 자동 연결을 지원 — 네이티브 앱(hereby Works) 전용
• 앱 설치 상태: App Link/Universal Link로 hereby Works가 열리고, 코드를 기기에 보관(hereby.pending-hospital-code) → 조직 선택 화면에 코드 자동 입력·조회. 앱이 이미 떠 있어도 같은 흐름
 - CASE01 [찾은 API 서버 = 현재 서버]: 보관 코드 폐기, 전환 없음
 - CASE02 [다른 서버]: 연결 확인을 거친 뒤에만 API 서버 전환(확인 전 전환 없음)
 - CASE03 [다른 환경·비https·다른 경로 링크]: 무시 — 보관 중인 코드를 지우지 않음. 허용 호스트는 빌드 환경과 짝(medical.hereby.me / medical.dev.hereby.me / medical.stg.hereby.me)
• 앱 미설치: /works/join 랜딩이 휴대폰은 스토어로 자동 이동(App Store/Play), 컴퓨터는 제목 "hereby Works 설치" + "휴대폰에서는 앱 스토어로 이동합니다. 컴퓨터에서는 사용 중인 기기에 맞는 버튼을 눌러 주세요." + 버튼 "iPhone (App Store)" / "Android (Google Play)"
랜딩 /works/join · apple-app-site-association/assetlinks.json · [[HBSA200]] 20-12 병원 코드신설 (코드 반영: 87f779d7·74360092·99444bb5, #1018) · 조직 선택(백엔드 디스커버리) 화면은 전용 사양서 미작성 — 세부 사양 = 갱신 대기 · 링크 동작은 랜딩 배포 + 스토어 1.0.5 빌드 선행 필요 · TBU: 라이브 실사 이월
01초기 상태Output"비밀번호" 탭 활성. 타이틀 "hereby 웍스" + 서브타이틀 조직명("hereby Medical") + 앱 로고 (2026-08-19 실증)
10인증 방식 탭Tab• 인증 방식을 "비밀번호" / "휴대폰 인증" 2탭으로 전환하는 컨트롤
• 클릭 시: 해당 인증 폼으로 전환("비밀번호"=초기 활성, "휴대폰 인증"=전환 표시)
⚠ 계정 레이어 7/16 로 탭 노출·순서 변동 여부 확인
20비밀번호 탭-ID·비밀번호 입력 후 로그인
ㄴ21IDInput• 직원 ID(이메일·사번)를 입력받는 필드
• 입력 → 직원 ID 반영. 빈 입력 유지 가능
 - 식별자 대소문자 무시(#647, 9/11): 이메일·사번은 대소문자를 구분하지 않고 조회(Foo@x.com=foo@x.com). 입력 표기 그대로 매칭을 우선하고, 없으면 대소문자 무시 매칭으로 폴백(기존 공존 데이터 보존)
findEmployeeByIdentifierTBU: 형식 검증 UI
ㄴ22비밀번호Input• 비밀번호를 마스킹 입력받는 필드
• 입력 → 마스킹 반영
 - "비밀번호 표시" 클릭 → 마스킹/평문 토글
ㄴ23로그인Button• 입력 자격으로 세션을 발급받아 홈으로 진입하는 기능
• 클릭 → 성공 시 근무 탭 홈 전환
 - CASE01 [ID/비밀번호 미입력]: disabled(무반응 정상)
 - CASE02 [자격 불일치]: 실패 처리
${employee_session} 발급⚠ 세션 발급 계정 레이어 7/16 확인
TBU: 실패 메시지·잠금 정책
ㄴ23-1첫 로그인 비밀번호 변경 (강제)Rule• 임시 비밀번호로 로그인한 직원은 홈 대신 공용 「비밀번호 변경」 화면(제목 "비밀번호 변경", 부제 "보안을 위해 새 비밀번호를 설정해주세요.")으로 이동 — 8개 앱 공통(ChangePasswordForm)
• 새 비밀번호 칸 placeholder = 병원 설정(일반 비밀번호 규칙) — 예: 기본 "8자 이상, 대문자·소문자·숫자·특수문자 포함" / 4자·필수 문자 해제 시 "4자 이상". 같은 규칙으로 화면이 먼저 검사(로그인 응답의 passwordPolicy 사용)
 - CASE01 [길이 미달]: "비밀번호는 {min}자 이상이어야 해요." · CASE02 [필수 문자 누락]: "비밀번호에 {누락 종류}를 포함해야 해요."
 - CASE03 [병원 설정 수정 권한(setting:update.*) 또는 시스템 관리자]: 칸 아래 "비밀번호 규칙은 이후 설정에서 변경할 수 있어요." 추가 노출(일반 직원은 미노출)
Organization.settings.userPasswordPolicy · [[HBAD270_설정 (조직 설정·내 정보)]] ㄴ51 · [[HBEA510_내 정보·근무 설정]] ㄴ51변경 (코드 반영: c6347029·382eec17, #995) · 구버전은 8자 고정이라 병원이 4자로 낮춰도 화면이 막았음 · TBU: 라이브 실사 이월
ㄴ24비밀번호 찾기Link• 비밀번호 재설정 동선으로 이동하는 링크
• 클릭 → TBU(재설정 동선 미확인)
TBU: 재설정 동선
30휴대폰 인증 탭-ID → 인증번호 받기 → SMS OTP 검증LoginOtpCode
ㄴ31IDInput• 직원 ID를 입력받는 필드
• 입력 → 직원 ID 반영
ㄴ32인증번호 받기Button• 입력한 ID로 SMS OTP 발송을 요청하는 기능
• 클릭 → SMS OTP 발송, 발송 중 "발송 중..." 표시
 - CASE01 [ID 미입력]: disabled
LoginOtpCode 생성TBU: 발송 실패 UI·재발송 쿨다운
ㄴ33인증번호 입력Input• SMS OTP를 입력·검증해 로그인하는 필드
• 입력 → 검증 통과 시 근무 탭 홈 전환
${employee_session} 발급⚠ 계정 레이어 7/16 확인
TBU: OTP 불일치·만료 처리
40푸터Text"© 2026 Hereby Platform"원문 카피
00-2안내 문자 로그인 링크 (로그인 이전 단계)Rule• 앱 설치 안내 문자의 새 플레이스홀더 {로그인링크} 가 랜딩 /works/login?code=&t= 로 치환 — 한 번 누르면 앱이 열리고 회사 코드로 서버 연결 뒤, 로그인 폼이 뜨는 순간 auth.loginPrefill 로 토큰을 풀어 ID·임시 비밀번호를 자동으로 채우고 바로 로그인
 - 대상: 임시 비밀번호가 있는 직원만 · 기한 = 임시 비밀번호 유효기간 또는 14일
 - CASE01 [이미 비밀번호 변경·퇴직·패스키 전용]: 프리필 거부(null) — 일반 로그인 폼 그대로
 - CASE02 [앱 미설치]: 랜딩이 스토어로 이동
• 토큰은 서버 비밀로 봉인(AES-256-GCM)·서버 미저장
랜딩 /works/login · [[HBAD270_설정 (조직 설정·내 정보)]] 안내 문구 템플릿신설 (코드 반영: a16a5c4, #1227) · iOS가 문자를 읽지 못해 링크 방식 채택 · TBU: 라이브 실사(문자 발송 필요)
50키 로그인 (패스키·기기 키)-비밀번호 없이 「이 기기의 키」로 로그인 — 웹 = 패스키(WebAuthn), 직원 앱 = 기기 키(ECDSA P-256, Keychain/Keystore + 생체·기기 PIN 관문). 서버에는 공개키만 저장, 챌린지 2분 1회용auth_device_credentials · [HBEA520] 인증/보안 설정신설 (코드 반영: 5826f16·e4932b0, #1227)
ㄴ51키 전용 모드Rule• 기기 키가 등록된 기기는 로그인 화면 진입 즉시 생체/기기 잠금 프롬프트 — 통과 시 바로 세션 발급
 - CASE01 [프롬프트 거부]: 비밀번호 폼으로 복귀
 - CASE02 [「아이디·비밀번호로 로그인」 선택]: 키는 그대로 두고 비밀번호 폼 열림, 「지문·기기 잠금으로 로그인」 으로 되돌아갈 수 있음 — 구 「다른 계정으로 로그인」(키 삭제)은 폐기, 다른 계정 로그인 시 그 사람 키로 재등록
 - CASE03 [로그아웃 직후]: 자동 프롬프트 생략(한 번짜리 sessionStorage 표시) — 키 블록·아이디 링크만 보여 사용자가 고름. 앱 재시작 시 평소대로 자동
ㄴ23신설 (코드 반영: e4932b0·731d1fb·9f5e7b2, #1227·#1239) · TBU: 키 등록 기기 실사
ㄴ52패스키로 로그인 (웹)Button• 공용 로그인 폼의 「패스키로 로그인」 — 브라우저 WebAuthn(discoverable 또는 식별자별)으로 세션 발급ㄴ51신설 (코드 반영: e4932b0) · 10/14 실사: admin 로그인 화면에 미노출(헤드리스 WebAuthn 한계 추정) — TBU
ㄴ53첫 로그인 뒤 패스키 등록 제안 (웹)Modal• 비밀번호·SMS 로그인 직후 패스키 지원 브라우저면 한 번 「이 브라우저에 패스키를 등록할까요?」 확인
 - CASE01 [동의]: 바로 등록 · CASE02 [거절]: 그 브라우저·계정엔 다시 묻지 않음
• 직원 앱은 첫 로그인 뒤 기기 키 자동 등록(짝 동작)
신설 (코드 반영: ffc824c) · TBU: 라이브 실사
ㄴ54미지원 빌드 가드 (직원 앱)Rule• 생체·보안 저장소 네이티브 플러그인이 없는 빌드는 「이 앱 버전은 지문·기기 잠금 로그인을 지원하지 않아요. 스토어에서 업데이트해 주세요」 안내, 등록·자동 등록 생략
• 판정은 네이티브 브리지 PluginHeaders 기준(JS 등록만으로 true 되는 isPluginAvailable 미사용) · 보안 저장소 15초/본인 확인 120초 상한
신설 (코드 반영: 42d28f7·0b44431·29eb525, #1234~#1236) · Android 네이티브 릴리즈 3 선행
60로그인 보안 규칙-반복 실패 잠금·이상 로그인 감지 — 서버 공통(auth.login·account.login·loginWithCode)신설 (코드 반영: e6ceb8e·f08c1ae, #1227)
ㄴ61계정 잠금Rule• 비밀번호·2단계 인증 코드 5회 오류 → 계정 15분 잠금(맞는 비밀번호도 거부) · 한 IP가 식별자를 바꿔 30회 실패 → 10분 차단
 - 잠기기 2회 전부터 남은 횟수 안내 · 잠기면 그 직원에게 인앱·푸시 「계정이 잠겼어요 · 본인이 아니면 비밀번호 변경·패스키 등록」
신설 (코드 반영: e6ceb8e) · TBU: 실패 메시지 원문 실사
ㄴ62이상 로그인 감지Rule• 최근 90일 기록(IP 대역·기기 종류·국가)과 비교해 새로운 국가, 또는 새로운 네트워크+새로운 기기면 「평소와 다른 로그인」
 - ① TURNSTILE 설정 운영 환경이면 캡차 선요구(captchaToken 재시도) ② 세션 발급 뒤 그 직원에게 인앱·푸시·이메일 알림 ③ 로그인 폼이 패스키 등록 재권유(unusualLogin)
신설 (코드 반영: f08c1ae) · TBU: 라이브 재현 불가 — 커밋 근거
ㄴ63패스키·기기 키 전용 로그인 거부Rule• 직원이 [HBEA520] 인증/보안 설정에서 「패스키·기기 키로만 로그인」을 켜면 비밀번호·SMS 인증 로그인 전부 거부
 - 해제: 관리자가 직원 수정 패널 계정·보안에서(관리자는 해제만 가능) — [[HBAD201_직원 추가·수정 모달]]
employees.passkeyOnlyLogin신설 (코드 반영: d35e4e3, #1227)

서브 화면 / 모달 ​

현재 라이브에서 로그인 화면에 딸린 별도 모달·바텀시트·팝업은 관찰되지 않음. 비밀번호 찾기 재설정 화면 존재 여부 = TBU(별도 문서 승격 대상 후보).

권한·상태 분기 요약 ​

시나리오트리거결과 화면비고
CASE01 [비밀번호 로그인]ID+비밀번호 입력 → 로그인근무 탭 홈(self scope)
CASE02 [휴대폰 인증]ID → 인증번호 받기 → OTP 검증근무 탭 홈LoginOtpCode
CASE03 [입력 미완]ID/비밀번호 공란로그인 버튼 disabled무반응 정상(버그 아님)

Open Question ​

  • 계정 레이어 전환(7/16 코드) 라이브 재확인 → 해소(2026-08-19 실증): 브랜딩("hereby 웍스"+조직명)·탭 2종·disabled 로그인·비밀번호 찾기 실측 확인. 세션 발급 procedure 확정값은 여전히 TBU
  • 비밀번호 찾기 동선(재설정 방식) = TBU
  • OTP 유효시간·재발송 정책(LoginOtpCode expiry·쿨다운) = TBU
  • 로그인 실패 잠금 정책 → 해소(2026-10-14, #1227): 5회 실패 15분 계정 잠금 + IP 버스트 차단 — ㄴ61
  • 가입(신규 계정 생성) 동선의 EA 내 존재 여부 = TBU (직원 계정은 Admin 등록 경로 추정)