1
0
forked from baron/baron-sso
Files
baron-sso/docs/works-only-user-recovery-2026-06-09.md

113 lines
4.8 KiB
Markdown

# WORKS only 사용자 복구 보고서
관련 이슈: #1037
## 요약
- 작업 시각: 2026-06-09 KST
- 대상: WORKS 비교 결과에서 `missing_in_baron`으로 보이던 사용자 row
- 최신 후보 수: 189명
- 조치: Baron `users.deleted_at` soft-delete 해제
- Kratos 조치: 직접 삽입/수정 없음. 189개 Kratos identity가 모두 현재 DB에 active 상태로 존재함을 확인함
- 최종 결과: WORKS 사용자 비교의 `missing_in_baron` 0건
## 원인
이전 사용자 legacy sync 코드가 Kratos `ListIdentities()` 결과를 전체 identity 목록으로 간주했습니다. 해당 API 결과는 제한된 페이지 결과였고, 그 목록에 없던 기존 사용자가 Baron `users`에서 soft-delete 처리되었습니다.
이로 인해 WORKS에는 사용자가 남아 있고 `externalKey`도 Baron 사용자 UUID를 가리키지만, Baron 비교 로직에서는 soft-deleted 사용자가 visible 사용자로 조회되지 않아 `missing_in_baron`으로 표시되었습니다.
## 대조 결과
복구 전 후보 189건 기준:
| 구분 | 현재 Baron | 과거 Baron 백업 | 현재 Kratos | 과거 Kratos 백업 |
| --- | ---: | ---: | ---: | ---: |
| 후보 | 189 | 189 | 189 | 189 |
| visible 사용자 | 0 | 189 | - | - |
| soft-delete 사용자 | 189 | 0 | - | - |
| 누락 사용자 | 0 | 0 | 0 | 0 |
| active identity | - | - | 189 | 189 |
| credential 보유 identity | - | - | 189 | 189 |
확인한 백업:
- `backups/pre-saman-works-users-20260608-063605Z`
- `backups/pre-works-only-user-recovery-20260609-083105KST`
상세 리포트:
- `reports/works-only-user-recovery-20260609-0832/missing_in_baron_external_keys.csv`
- `reports/works-only-user-recovery-20260609-0832/current_baron_candidate_status.csv`
- `reports/works-only-user-recovery-20260609-0832/pre_saman_baron_candidate_status.csv`
- `reports/works-only-user-recovery-20260609-0832/current_kratos_candidate_status.csv`
- `reports/works-only-user-recovery-20260609-0832/pre_saman_kratos_candidate_status.csv`
- `reports/works-only-user-recovery-20260609-0832/post_recovery_baron_candidate_status.csv`
## 조치 내용
복구 전 DB 백업을 생성했습니다.
- `make dump DUMP_SERVICES=postgres,ory-postgres BACKUP=backups/pre-works-only-user-recovery-20260609-083105KST`
이후 후보 189건에 대해 현재 Baron DB에서 다음 조건으로만 soft-delete를 해제했습니다.
- WORKS `missing_in_baron` row의 `externalKey`가 UUID여야 함
- 해당 UUID가 현재 Baron `users.id`에 존재해야 함
- 해당 Baron row가 `deleted_at IS NOT NULL`이어야 함
- 해당 UUID가 현재 Kratos `identities.id`에 active 상태로 존재해야 함
복구 결과:
- 복구된 Baron 사용자: 189명
- 전체 Baron `users`: 2114명
- visible 사용자: 2106명
- soft-delete 사용자: 8명
- 후보 189명 중 Kratos active identity: 189명
- 후보 189명 중 credential 보유 identity: 189명
## 최종 검증
실제 Kratos admin 세션으로 로컬 게이트웨이를 경유해 검증했습니다.
- `GET /api/v1/admin/users?limit=5000&offset=0`
- HTTP 200
- `total=2106`
- `items=2106`
- `GET /api/v1/admin/tenants/038326b6-954a-48a7-a85f-efd83f62b82a/worksmobile/comparison?includeMatched=true`
- HTTP 200
- 사용자 비교 총 2110건
- `matched=2073`
- `missing_in_baron=0`
- `missing_in_worksmobile=30`
- `needs_update=1`
- `missing_external_key=6`
- 조직/그룹 비교 총 187건
- 조직/그룹 `missing_in_baron=1`
테스트:
- `GOCACHE=/tmp/baron-sso-go-cache go test ./internal/service -run 'TestWorksmobileSyncServiceSkipsSoftDeletedUsersInComparison' -count=1`
- `GOCACHE=/tmp/baron-sso-go-cache go test ./internal/handler ./internal/repository -run 'Test.*User|Test.*SoftDeleted|Test.*ListUsers' -count=1`
- `BASE_URL=http://127.0.0.1:5173 npm --prefix adminfront test -- worksmobile.spec.ts --project=chromium`
결과:
- Go service 테스트 통과
- Go handler/repository 테스트 통과
- adminfront Worksmobile Playwright 4개 테스트 통과
## 재발 방지
이미 적용된 코드 변경으로 다음 조건을 방어합니다.
- admin 사용자 목록은 Kratos 250개 제한 결과가 아니라 Backend cursor API와 identity mirror 상태를 기준으로 조회합니다.
- legacy replace sync는 Kratos partial list에 없는 사용자를 삭제 처리하지 않습니다.
- WORKS 비교 로직은 soft-deleted Baron 사용자를 visible 사용자로 취급하지 않습니다.
- WORKS 비교 UI에는 필터링 후 표시 row와 전체 row 수를 함께 표시합니다.
남은 확인 항목:
- 조직/그룹 비교의 `missing_in_baron=1`은 사용자 복구와 별개 항목입니다. 별도 이슈로 원인 확인이 필요합니다.
- `missing_external_key=6` 사용자 row는 WORKS 측 externalKey가 없으므로 자동 복구 대상에서 제외했습니다.