forked from baron/baron-sso
테넌트 목록 조회 cursor기반으로 재구성. 사용자 metadata 미사용 필드 제거
This commit is contained in:
142
docs/tenant-maintenance-procedures.md
Normal file
142
docs/tenant-maintenance-procedures.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Tenant 유지보수 절차
|
||||
|
||||
이 문서는 관리자가 비정기적으로 수행할 수 있는 tenant 데이터 정합성 점검 및 정리 절차를 정리한다.
|
||||
|
||||
## Orphan 사용자 tenant 소속정보 정리
|
||||
|
||||
### 대상
|
||||
|
||||
다음 중 하나에 해당하는 활성 Baron 사용자는 orphan 소속정보 정리 대상이다.
|
||||
|
||||
- `users.tenant_id`가 존재하지 않거나 soft-deleted 된 `tenants.id`를 가리킨다.
|
||||
- `users.company_code`가 활성 `tenants.slug`와 매칭되지 않는다.
|
||||
- `users.company_codes` 배열 중 하나 이상이 활성 `tenants.slug`와 매칭되지 않는다.
|
||||
|
||||
정리 시 다음 필드를 비운다.
|
||||
|
||||
- `tenant_id`
|
||||
- `company_code`
|
||||
- `company_codes`
|
||||
|
||||
### 사전 확인
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.email,
|
||||
u.tenant_id,
|
||||
u.company_code,
|
||||
u.company_codes
|
||||
FROM users AS u
|
||||
WHERE u.deleted_at IS NULL
|
||||
AND (
|
||||
(
|
||||
u.tenant_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tenants AS t
|
||||
WHERE t.id = u.tenant_id
|
||||
AND t.deleted_at IS NULL
|
||||
)
|
||||
)
|
||||
OR (
|
||||
NULLIF(BTRIM(u.company_code), '') IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tenants AS t
|
||||
WHERE LOWER(t.slug) = LOWER(BTRIM(u.company_code))
|
||||
AND t.deleted_at IS NULL
|
||||
)
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM UNNEST(COALESCE(u.company_codes, ARRAY[]::text[])) AS code(value)
|
||||
WHERE NULLIF(BTRIM(code.value), '') IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tenants AS t
|
||||
WHERE LOWER(t.slug) = LOWER(BTRIM(code.value))
|
||||
AND t.deleted_at IS NULL
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Kratos identity traits도 같은 기준으로 정리한다.
|
||||
|
||||
- `traits.tenant_id`
|
||||
- `traits.companyCode`
|
||||
- `traits.companyCodes`
|
||||
|
||||
### Baron users만 실행
|
||||
|
||||
```bash
|
||||
docker exec -i baron_postgres psql -U baron -d baron_sso < scripts/clear_orphan_user_tenant_memberships.sql
|
||||
```
|
||||
|
||||
실행 결과에는 정리된 사용자와 기존 소속정보가 출력된다.
|
||||
|
||||
### Baron users와 Kratos identity traits 함께 실행
|
||||
|
||||
로컬 Docker Compose 기준 기본 컨테이너명은 다음과 같다.
|
||||
|
||||
- Baron DB: `baron_postgres`
|
||||
- Kratos DB: `ory_postgres`
|
||||
|
||||
```bash
|
||||
scripts/clear_orphan_tenant_memberships.sh
|
||||
```
|
||||
|
||||
컨테이너명이나 DB 접속 정보가 다르면 환경변수로 override 한다.
|
||||
|
||||
```bash
|
||||
BARON_CONTAINER=baron_postgres \
|
||||
BARON_DB_USER=baron \
|
||||
BARON_DB_NAME=baron_sso \
|
||||
KRATOS_CONTAINER=ory_postgres \
|
||||
KRATOS_DB_USER=ory \
|
||||
KRATOS_DB_NAME=ory_kratos \
|
||||
scripts/clear_orphan_tenant_memberships.sh
|
||||
```
|
||||
|
||||
### 사후 확인
|
||||
|
||||
사전 확인 쿼리를 다시 실행했을 때 결과가 0건이어야 한다.
|
||||
|
||||
Kratos identity traits는 다음 쿼리로 확인한다.
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
id,
|
||||
traits->>'email' AS email,
|
||||
traits->>'tenant_id' AS tenant_id,
|
||||
traits->>'companyCode' AS company_code,
|
||||
traits->'companyCodes' AS company_codes
|
||||
FROM identities
|
||||
WHERE COALESCE(traits->>'tenant_id', '') <> ''
|
||||
OR COALESCE(traits->>'companyCode', '') <> ''
|
||||
OR traits ? 'companyCodes';
|
||||
```
|
||||
|
||||
## Soft-deleted tenant slug 점검
|
||||
|
||||
`tenants.slug`는 DB unique index이므로 soft-deleted row도 slug를 점유한다. 현재 삭제 로직은 삭제 전에 slug에 `-deleted-...` suffix를 붙여 재사용 가능하게 만들지만, 과거 데이터나 수동 변경으로 삭제된 row가 원래 slug를 계속 점유하면 AdminFront 검색에는 보이지 않으면서 생성은 unique violation으로 실패할 수 있다.
|
||||
|
||||
### legacy 점유 row 확인
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
id,
|
||||
slug,
|
||||
name,
|
||||
deleted_at
|
||||
FROM tenants
|
||||
WHERE deleted_at IS NOT NULL
|
||||
AND slug NOT LIKE '%-deleted-%'
|
||||
ORDER BY deleted_at DESC;
|
||||
```
|
||||
|
||||
### 정책
|
||||
|
||||
- 활성 tenant가 같은 slug를 가지고 있으면 생성 실패가 정상이다.
|
||||
- soft-deleted tenant만 같은 slug를 점유하고 있으면 생성 직전에 해당 deleted row의 slug를 release 한다.
|
||||
- `FindBySlug`와 검색 API는 활성 tenant만 반환하므로, 생성 제약도 활성 tenant 기준으로 체감되도록 맞춘다.
|
||||
Reference in New Issue
Block a user