Skip to content

HBSA100_Signin (운영자 로그인) ​

(Hereby) 시스템 관리 > [[HBSA000]] > Signin

앱System Admin (포트 4100)
부모 화면[[HBSA000]]
대상 사용자플랫폼 운영자(OPERATOR) — 본인 이메일 계정
프로토타입TBU
관련 정책[[POL_권한(RBAC)]]
Statusdraft (코드 기반 — 라이브 실사 불가: dev 라우트 AccessDenied 격리, 2026-08-25 확인)
Owner카나

개요 ​

IP allowlist 통과 후, 콘솔 JWT가 없을 때 노출되는 로그인 화면(!isLoading && !authenticated). redesign Phase 3에서 env 단일 계정을 폐기하고 운영자 본인 이메일 계정 로그인으로 전환됐다. 검증 = 대상 엔드포인트의 account.login + platform.systemWhoAmI로 OPERATOR 확인.

문서 히스토리 ​

날짜작성자팀변경 내용
2026-08-25카나콸최초 작성 (redesign PR #583 코드 census 기반, 라이브 미실사)
2026-09-01카나PM로그인 비밀번호 RSA-OAEP+일회용 챌린지 암호화 반영(cf552d4, 8/29 머지) — 코드 기준
2026-09-21카나PM최초 운영자 계정 부트스트랩 단계 신설 — 계정 0개일 때만 로그인 폼 자리에 「최초 운영자 계정 만들기」 노출, Root·SUPER_ADMIN 생성 + 역할·권한 카탈로그 동일 트랜잭션 시드, 409 BOOTSTRAP_NOT_AVAILABLE·Origin 검사·레이트리밋 반영(85df625b, #800) — 커밋 근거, 라이브 실사 이월(TBU)
2026-09-23카나PM「로그인 상태 유지」 체크박스 신설 — 켜면 유휴 30분 판정을 건너뛰는 30일 persistent 세션 발급(admin_sessions.persistent), 이메일 로그인은 인증 앱 확인 단계·Google 로그인은 /google/start?remember=1 로 선택값 전달, 승인 대기 계정 제외·8시간 재인증 유지(27c905a, #825) — 커밋 근거, 라이브 실사 이월(TBU)
2026-10-02카나PM잠긴 계정 로그인 안내 분리 — 잠금 중 시도는 423 ACCOUNT_LOCKED "로그인 시도가 너무 많아 계정이 잠시 잠겼어요. {N}분 뒤 다시 시도해 주세요."로 응답, 잠금 중 시도로 잠금이 연장되지 않음·재인증 동일(dbecf4b5, #996) — 커밋 근거, 라이브 실사 이월(TBU)

Data I/O ​

Client → Server ​

액션전달 값콘솔 REST권한 게이트
"로그인" 제출{ identifier(email), password, endpoint? }POST /api/auth/loginIP allowlist + OPERATOR
세션 확인(init)콘솔 JWTGET /api/auth/meJWT 유효성

Server → Client ​

변수소스값 없을 때비고
tokenJWT sign (12h)-localStorage 저장 추정(TBU)
usernameoperator.email-헤더에 @{username} 표기
operatorsystemWhoAmI 결과-{lastName+firstName} = operatorName
loginError실패 메시지hide아래 상태 분기

코드 근거: src/views/signin.html, server/index.ts /api/auth/login.


화면 플로우 ​


Signin 사양표 ​

번호항목/기능명타입사양 및 기능 설명연관/영향 범위비고
00화면 진입 조건-조건1 [!isLoading && !authenticated] 시 노출. 조건2 [isLoading] 시 [[HBSA200]] 로딩("연결 중...") 노출, 조건3 [authenticated] 시 [[HBSA200]] Shellinit() GET /api/auth/meIP allowlist 미통과 시 이 화면 자체 도달 불가(403)
01초기 상태Output카드 중앙 정렬. 상단 방패 아이콘("ic-shield-check", orange) + 타이틀 "System Admin" + 부제 "운영자 본인 계정으로 로그인하세요"-
10이메일 입력Input Box• 라벨 "이메일", type=email, placeholder "operator@example.com"
• x-model=loginUsername, required, autocomplete=email
• 로딩 중 disabled
loginUsername → identifier
20비밀번호 입력Input Box• 라벨 "비밀번호", type=password, required, autocomplete=current-password
• 로딩 중 disabled
• 전송 시 평문이 아니라 RSA-OAEP + 일회용 챌린지로 암호화해 전송(login-crypto.ts 클라이언트·서버 쌍, cf552d4 — 8/29 머지)
loginPassword → 암호화 payload인터페이스 계약 변경(8/29) — 코드 기준
25로그인 상태 유지Checkbox• 로그인 폼에 「로그인 상태 유지」 체크박스 신설
• 켜면 유휴 30분 판정을 건너뛰는 30일 persistent 세션 발급(admin_sessions.persistent, 마이그레이션 1894000000010)
• 선택값 전달 경로: 이메일 로그인은 인증 앱 확인 단계(rememberMe), Google 로그인은 /google/start?remember=1 → 쿠키
• 승인 대기 계정은 대상 아님, 8시간 재인증은 그대로 유지
admin_sessions.persistent · [[HBSA200]] 「로그인된 브라우저」신설 (코드 반영: 27c905a, #825) · 인증 앱 확인 단계·Google 로그인 경로는 본 사양서 미기술 — 갱신 대기 · TBU: 라이브 실사 이월
30로그인 버튼Button• 라벨 "로그인" (orange solid)
• 클릭 → doLogin() → POST /api/auth/login
• 로딩 중: 스피너 + "로그인 중..." 표시, disabled
doLogin()엔드포인트 미지정 시 레지스트리 첫 엔드포인트 대상
30-Errㄴ 에러 배너AlertloginError 존재 시 red 박스. 문구는 상태별 분기(40)loginError실측 토스트 아님, 인라인 배너
40로그인 결과 분기-case01 [자격증명 오류] → 401 "아이디 또는 비밀번호가 올바르지 않아요." / case02 [OPERATOR 아님] → 403 "시스템 운영자(OPERATOR) 계정이 아니에요." / case03 [엔드포인트 연결불가] → 502 "엔드포인트에 연결할 수 없어요: {message}" / case04 [성공] → JWT 발급 + 그 엔드포인트 세션 setCredentials 자동등록 → Shellserver/index.ts입력 누락 시 400 "이메일과 비밀번호를 입력해 주세요."
ㄴ41계정 잠김-• 로그인 실패가 누적돼 잠긴 계정의 로그인 시도는 비밀번호가 맞든 틀리든 「잠금」으로 응답(틀린 비밀번호 문구와 구분)
 - CASE05 [계정 잠김]: 423 ACCOUNT_LOCKED "로그인 시도가 너무 많아 계정이 잠시 잠겼어요. {N}분 뒤 다시 시도해 주세요." (남은 시간 분 단위 올림, 최소 1분)
• 잠금 중 시도는 실패 횟수·잠금 시각을 늘리지 않음(예전엔 시도마다 15분씩 연장) — 감사 auth.local.locked_attempt만 기록
• 재인증(8시간)도 동일: 감사 auth.local.reauth_locked_attempt
local-auth.service.ts · security/password.ts신설 (코드 반영: dbecf4b5, #996) · 없는 이메일·틀린 비밀번호는 기존 401 문구 유지 · TBU: 라이브 실사 이월
45최초 운영자 계정 만들기 (부트스트랩)Step• 컨트롤플레인 DB에 시스템 관리자 계정이 하나도 없을 때만 로그인 폼 자리에 나타나는 「최초 운영자 계정 만들기」 단계
• 그 자리에서 Root · SUPER_ADMIN(global) 계정을 생성. 역할·권한 카탈로그가 비어 있으면 같은 트랜잭션에서 시드
 - 효과: 수동 SQL(bootstrap-local.sql)·reconcile CLI 없이 서버 기동 직후 바로 접속해 계정 생성 가능
• 진입 판정: init에서 세션이 없을 때만 GET /api/auth/bootstrap/status 조회 → { required } true면 authStep "bootstrap"
 - required는 계정 0개일 때만 true (삭제된 계정도 점유로 간주)
 - CASE01 [성공]: 201 생성 → 이메일 프리필로 로그인 화면 복귀
 - CASE02 [이미 계정 있음]: 409 BOOTSTRAP_NOT_AVAILABLE
• POST /api/auth/bootstrap에 Origin 검사·레이트리밋 적용. 이후 계정은 기존대로 접근 관리에서 생성
 - 로컬 dev 프록시 changeOrigin 제거(Host가 바뀌어 assertRequestOrigin이 로그인 POST를 ORIGIN_INVALID로 막던 문제 동반 수정)
GET/POST /api/auth/bootstrap · [[HBSA210_Organizations (목록·상세·설정·역할·관리자)]]신설 (코드 반영: 85df625b, #800) · TBU: 라이브 실사 이월
50푸터Text"hereby System Admin" (패밀리 서비스명 미부착 — 마스터 영역 주석)-
60권한별 차이-조건1 [OPERATOR] 로그인 성공 / 조건2 [일반 회원/SUPPORT] → 403 거부(콘솔 로그인은 OPERATOR 게이트). SUPPORT의 콘솔 진입 가능 여부는 코드상 systemWhoAmI OPERATOR 판정만 확인됨-TBU: SUPPORT 콘솔 로그인 허용 여부

권한 / 상태 요약 ​

시나리오트리거결과비고
case01 [자격증명 오류]틀린 이메일/비번401 배너
case02 [비-OPERATOR]일반 계정 로그인403 배너
case03 [엔드포인트 다운]연결 실패502 배너
case04 [성공]OPERATOR 검증Shell 진입 + 세션 자동연결볼트 설정 시 자격증명 영속
CASE05 [계정 잠김]잠긴 계정으로 로그인·재인증423 배너 "…{N}분 뒤 다시 시도해 주세요."잠금 연장 없음 (#996)

OQ ​

  • 성공/실패 시 실제 UI 전환·토스트 실측 = TBU (라이브 격리)
  • 다중 엔드포인트 환경에서 로그인 대상 엔드포인트 선택 UI 존재 여부 = 코드상 body.endpoint 지원하나 signin.html에 셀렉터 없음 TBU