125 lines
12 KiB
Markdown
125 lines
12 KiB
Markdown
# AdminFront 운영 가이드
|
|
|
|
## 대상
|
|
|
|
Tenant와 사용자를 조회·관리하고 권한, WORKS, API Key, 데이터 정합성 화면을 사용하는 운영자를 위한 가이드다. 실제로 보이는 menu와 action은 actor의 System Role, Tenant relation, 기능별 capability에 따라 달라진다.
|
|
|
|
## 권한을 읽는 법
|
|
|
|
- `super_admin`은 전역 System Role이다.
|
|
- Tenant owner/admin과 기능별 view/edit/manage는 Tenant 범위의 relation이다.
|
|
- 사용자의 소속과 관리자가 관리할 수 있는 Tenant 집합은 서로 다르다.
|
|
- 메뉴가 보이거나 button이 활성화되었다는 사실만으로 mutation이 허용되지는 않는다. Backend가 요청 시점의 권한과 대상을 다시 검사한다.
|
|
|
|
용어는 [`CONTEXT.md`](../../CONTEXT.md), 관계 원칙은 [Tenant and Authorization Principles](../principles/tenancy-and-authorization.md)를 따른다.
|
|
|
|
시스템 상태, 의존 서비스, 작업·진단 및 성능 비교는 super admin 전용 [운영 센터 사용법](admin-operations-center.md)을 참고한다.
|
|
|
|
## 긴 목록 탐색
|
|
|
|
긴 표에 내부 스크롤이 있으면 표 영역 안에서 행을 탐색합니다. 열이 화면보다 넓으면 같은 영역에서 가로로 스크롤합니다. 표 헤더는 스크롤 영역의 상단에 유지됩니다. 페이지 스크롤을 사용하는 표는 앱 헤더 아래에 표 헤더를 유지합니다. 추가 조회 버튼이 보이면 선택하여 다음 목록을 불러옵니다. 검색과 필터는 화면에서 제공하는 조회 조건으로 사용합니다.
|
|
|
|
사용자·Tenant 목록에서 이름이나 날짜로 정렬하려면 검색어를 지우고 열 제목을 선택하세요. 검색어를 입력하면 관련도 순서로 표시합니다. 검색어를 지우면 검색 전 정렬로 돌아갑니다. 검색 정렬 정책은 [UI Design Policy](https://gitea.hmac.kr/baron/baron-sso/wiki/UI-Design-Policy#fuzzy-검색의-기본-정렬)를 따릅니다.
|
|
|
|
## Tenant 작업
|
|
|
|
검색어가 없으면 목록의 기본 분류 순서는 한맥가족 → 파트너사 → 일반회사 → 공공기관 → 교육/학생 → 해외기관 → Personal입니다. 이때 트리와 평면 보기는 같은 기본 순서를 사용하고, 하위 Tenant는 이름순으로 표시합니다. 사용자가 열 정렬을 선택하면 해당 정렬을 우선 적용합니다.
|
|
|
|
구현은 [정렬 코드](../../adminfront/src/lib/tenantTree.ts)와 [목록 화면](../../adminfront/src/features/tenants/routes/TenantListPage.tsx)에 있습니다. [단위 테스트](../../adminfront/src/lib/tenantTree.test.ts)와 [화면 회귀 테스트](../../adminfront/tests/tenant-default-order.issue-2206.spec.ts)는 정렬 동작을 검증합니다.
|
|
|
|
1. Tenant 목록에서 이름, slug, 유형, 상위 Tenant를 확인한다.
|
|
2. `COMPANY`의 사업자등록번호는 선택 입력이며 `000-00-00000` 형식으로 표시된다. 번호 검색 결과가 범위 안이면 기존 회사를 확인하고, 범위 밖 일치이면 상세 없이 검토 요청을 남긴다.
|
|
3. 하위 Tenant 생성 시 선택 가능한 parent만 사용한다. 부모와 자식 `COMPANY`가 각각 사업자등록번호를 갖는 것은 정상이다.
|
|
4. CSV import/export에서는 `type` 다음의 `business_registration_number` 컬럼을 사용한다. import는 기존 영문·한글 alias도 읽지만 export는 canonical header만 출력한다. legacy CSV에 이 컬럼이 없으면 기존 번호를 변경하지 않으며, 컬럼이 있고 셀이 비어 있을 때만 명시적 clear로 처리한다. export는 Tenant page permission을 가진 actor에게만 열리고 Backend가 계산한 Tenant scope를 벗어나지 않는다.
|
|
5. Organization Read/Write/Manage 표시를 단일 저장 role로 해석하지 않는다.
|
|
6. child create와 delete capability는 독립적으로 거부될 수 있다.
|
|
7. seed 또는 protected Tenant는 일반 Tenant와 삭제 조건이 다르므로 화면 경고와 Backend 결과를 따른다.
|
|
8. Exact Super Admin은 Tenant 상세의 인증 정책 화면에서 AAL2 강제를 즉시 켜거나 끌 수 있다. 사용자의 모든 canonical 소속 중 가장 높은 요구사항이 적용되며, 재활성화할 때 과거 대상자를 제외하지 않는다.
|
|
9. 정책을 꺼도 이미 등록된 TOTP credential은 자동 삭제하지 않는다. 개인이 선택해 등록한 TOTP도 계속 사용할 수 있다.
|
|
|
|
## 사용자 작업
|
|
|
|
1. 사용자 목록의 현재 Tenant filter와 조회 범위를 확인한다.
|
|
2. 계정 생성, profile 변경, Membership 추가·제거, 대표 Tenant 변경, status 변경을 서로 다른 작업으로 취급한다.
|
|
3. bulk action 전에 선택 대상과 action 종류를 다시 확인한다.
|
|
4. Membership 제거를 계정 삭제로 오인하지 않는다.
|
|
5. identity 영구 삭제는 제한된 별도 command이며 self/protected guard를 우회하지 않는다.
|
|
6. Exact Super Admin 전용 `Stealth 식별자` 화면에서만 `stealth` 노출 정책을 관리한다. Stealth 식별자는 일반 검색, CSV, 조직도, org-context, AdminFront 통계, WORKS projection에서 제외한다.
|
|
7. `identity_visibility_policies`가 visibility 권한 원장이고 `users.identity_visibility`는 같은 transaction에서 갱신하는 조회 projection이다. 기존 public identity의 policy row가 없으면 canonical `public`으로 해석한다. 두 값이 불일치하면 더 제한적인 값을 적용하고, 저장소 장애는 public으로 완화하지 않고 요청을 닫는다. 이 필터는 AdminFront 일반 통계의 기존 집계 의미를 바꾸지 않는다.
|
|
|
|
### 사용자 소속 선택
|
|
|
|
루트는 조직 계층의 최상위 테넌트입니다.
|
|
한맥가족, 파트너사, 일반회사, 공공기관, 교육/학생, 해외기관은 같은 검색 트리 선택기를 사용합니다.
|
|
사용자 추가와 수정 화면 모두 테넌트 이름이나 식별자(slug)로 검색할 수 있습니다.
|
|
|
|
선택기는 서버가 허용한 테넌트만 표시합니다.
|
|
하위 조직을 검색하면 응답에 포함된 상위 조직도 함께 표시합니다.
|
|
상위 조직이 권한 범위에 없으면 해당 하위 조직부터 표시합니다.
|
|
소속 선택에는 OrgFront 로그인이나 조직도 조회 권한이 필요하지 않습니다.
|
|
|
|
1. 사용자 추가 또는 수정 화면에서 소속 루트 탭을 선택하세요.
|
|
2. 한맥가족 탭에 소속 행이 없으면, 추가 버튼을 누르세요.
|
|
3. 한맥가족 탭이면, 소속 행의 선택 버튼을 누르세요.
|
|
4. 다른 조직 탭이면, 대표 소속 항목의 버튼을 누르세요.
|
|
5. 필요하면 검색창에 테넌트 이름이나 식별자를 입력하세요.
|
|
6. 트리에서 허용된 테넌트를 선택하세요.
|
|
7. 화면에 반영된 테넌트 이름을 확인하세요.
|
|
8. 사용자 생성 또는 저장 버튼을 누르세요.
|
|
|
|
Personal은 전용 테넌트를 자동으로 사용하므로 트리에서 선택하지 않습니다.
|
|
한맥가족의 여러 소속을 지정하려면 소속 행을 추가하세요.
|
|
저장할 소속은 하나의 루트 아래에 속해야 합니다.
|
|
|
|
권한을 처음 불러오는 중이거나 조회에 실패하면 선택할 수 없습니다.
|
|
검색어가 없는데 선택기가 비어 있으면 현재 루트에서 선택할 수 있는 테넌트가 없는 상태입니다.
|
|
서버는 저장할 때 권한을 다시 검사합니다.
|
|
|
|
권한 원칙은 [Tenant and Authorization Principles](../principles/tenancy-and-authorization.md)를 따릅니다.
|
|
선택기 구현은 [MembershipTenantPicker](../../adminfront/src/features/users/components/MembershipTenantPicker.tsx)에 있습니다.
|
|
|
|
## 권한 위임
|
|
|
|
- 읽기, 편집, 관리 단계를 대상 기능과 Tenant scope별로 부여한다.
|
|
- `self`와 `subtree`를 구분한다.
|
|
- preview의 현재 상태와 결과 상태를 확인한 뒤 저장한다.
|
|
- accepted 또는 pending 상태를 effective 완료로 표시하지 않는다.
|
|
- 저장 후 권한 목록이 원장 상태로 수렴했는지 다시 확인한다.
|
|
|
|
## 데이터 정합성
|
|
|
|
`데이터 정합성` 화면의 기본 조회는 진단이다. repair 후보가 표시되어도 자동 삭제하지 않는다.
|
|
|
|
1. 실패 항목과 candidate의 UUID·Tenant·사유를 확인한다.
|
|
2. 원장 장애인지 실제 orphan인지 구분한다.
|
|
3. repair가 필요하면 [Data Integrity Runbook](../runbooks/data-integrity.md)을 따른다.
|
|
4. Kratos/Keto 조회 실패 중에는 삭제를 재시도하지 않는다.
|
|
5. 사업자등록번호 검토 요청은 번호·요청자·대상 부모·전역 일치 Tenant를 확인하고 필수 의견과 함께 처리한다.
|
|
6. 중복 회사 병합은 exact duplicate 그룹 전체에서 생존 Tenant와 모든 source Tenant를 확인한 뒤 plan을 생성하고, 생존 slug와 사유를 입력해 적용한다. 여러 그룹 중 일부만 실패하면 완료 영수증은 유지하고 실패 operation만 같은 `Idempotency-Key`로 재시도한다.
|
|
7. 일반 삭제가 거부된 경우에만 `super_admin` 화면에서 강제 영구 삭제를 선택한다. plan의 Tenant 이름·slug·parent와 orphan Membership, Login ID, User Group, domain, Shared Link, Developer Request, lifecycle schedule, Client Consent reference, credential 수, blocker를 확인하고 exact slug와 사유를 입력한다.
|
|
8. 강제 삭제 영수증에 외부 cleanup residual이 남으면 재시도하거나, 책임자가 사유를 남겨 잔여 문제를 수용하기 전까지 완료로 취급하지 않는다.
|
|
9. 브라우저 reload나 담당자 변경으로 미완료 병합·강제 삭제가 남으면 operation 복구 목록에서 대상을 확인하고 새 감사용 `Idempotency-Key`와 복구 사유로 재개한다.
|
|
|
|
## 사용자를 생성한 관리자 찾기
|
|
|
|
1. 감사 로그 화면에서 **대상 UUID**에 생성된 사용자의 UUID 전체를 입력한다. **수행자 UUID**는 작업한 관리자 ID이므로 대상 사용자와 구분한다.
|
|
2. 작업에 `CREATE_USER`를 입력해 생성 업무 이벤트를 찾는다. `creat_user` 같은 한 글자 오타도 허용하지만 UUID는 전체 값이 정확히 일치해야 한다.
|
|
3. 행의 수행자 ID와 대상을 확인하고 상세의 `operation_id`, `commit_outcome`을 대조한다. 사용자 삭제 후에도 이 생성 이벤트는 조회할 수 있다.
|
|
|
|
액션 텍스트는 부분 문자열·초성·한 글자 오타로 검색할 수 있다. 검색 결과는 [공통 fuzzy 검색 순서](https://gitea.hmac.kr/baron/baron-sso/wiki/UI-Design-Policy#fuzzy-검색의-기본-정렬)를 따르고 추가 조회에도 같은 조건을 유지한다. 텍스트 검색을 지우면 기존 시간순 조회로 돌아간다.
|
|
|
|
`USER_CREATED`는 실제 생성 commit 기록이며 HTTP 요청의 성공·실패 로그와 구분한다. 일괄 요청의 일부가 실패했어도 commit된 사용자마다 생성 이벤트가 남는다. `creation_audit_pending` 응답은 생성 후 감사 전달이 지연된 상태이므로 새 키로 생성하지 말고 기존 `Idempotency-Key`를 유지한다. API 계약은 [OpenAPI](../../backend/docs/openapi.yaml)를 따른다.
|
|
|
|
`CLIENT_EVENT`의 `received`는 클라이언트 보고를 수신했다는 뜻이다. 상세의 `client_status`가 `success`여도 서버에서 사용자 생성이 완료됐다는 증거로 사용하지 않는다.
|
|
|
|
이전 버전의 생성 로그에 대상 UUID가 없으면 해당 UUID 검색으로 찾을 수 없다. 이름과 시각만 일치하는 로그를 UUID로 직접 연결된 증거처럼 취급하지 않는다.
|
|
|
|
## 다른 운영 화면
|
|
|
|
- 운영 센터의 런타임, 의존성, 큐, 작업, 진단, 성능 비교: [운영 센터 사용법](admin-operations-center.md)
|
|
- WORKS 사용자 상태와 동기화: [WORKS 인사 가이드](works-hr.md)
|
|
- Integration credential: [Directory API 가이드](directory-api.md)
|
|
- RP와 DevFront: [RP 통합 가이드](rp-integration.md)
|
|
- Exact Super Admin bootstrap과 credential reset: [Account Remediation Runbook](../runbooks/account-remediation.md)
|
|
- 정책 정본: [Gitea Wiki](https://gitea.hmac.kr/baron/baron-sso/wiki)
|