
# SCIM 프로비저닝 시뮬레이션

`POST /v1/directories/{directory_id}:simulate` · 권한 `directories:write` · 개발 및 스테이징 환경에서만 사용 가능

디렉터리의 실제 SCIM 엔드포인트를 대상으로 SCIM 시뮬레이터 시나리오를 하나 실행합니다. 실행 중에만 KeenAuth가 실제 SCIM 토큰을 발급하여 사용한 뒤 폐기합니다.
토큰 검사, 속도 제한, 대량 프로비저닝 해제 차단기, 프로비저닝 로그는 ID 공급자의 요청과 동일하게 모두 실행됩니다. 사용자는 고정된 가상 데이터 세트로, `example.test` 도메인의 25명이 5개 그룹에 속합니다. 실제 개인 데이터는 포함되어 있지 않습니다.

시뮬레이터는 개발용 도구이며 디렉터리를 변경합니다. 시뮬레이터가 생성한 사용자와 그룹은 다른 프로비저닝 레코드와 마찬가지로 디렉터리에 남아 있습니다. 테스트용으로 직접 만든 디렉터리를 사용하십시오.

| 시나리오 | 수행 작업 |
|---|---|
| `seed` | 25명의 사용자와 5개의 그룹, 그리고 각 그룹의 구성원 관계를 생성합니다. 이미 데이터가 있는 디렉터리에서는 첫 번째 사용자에 대해 SCIM `409`가 반환되고 실행이 `failed`가 됩니다. |
| `bulk_deactivate` | 사용자의 60%(25명 중 15명)에 대해 `active=false`를 전송합니다. 차단기는 디렉터리의 `mass_deprovision_guard.absolute_min` 값이 15 이하일 때만 작동합니다. 기본값 25에서는 작동하지 않습니다. |
| `group_churn` | 사용자 한 명을 한 그룹에서 다른 그룹으로 이동합니다. |
| `attribute_update` | 모든 사용자의 표시 이름과 성을 변경합니다. |
| `conflict_email` | 기존 `userName`을 가진 사용자를 생성하고 SCIM `409 uniqueness` 응답을 기대합니다. |

디렉터리가 비어 있으면 `seed`를 제외한 모든 시나리오는 먼저 `seed`를 실행합니다.

시뮬레이션 토큰은 목록에 표시되지 않으며 유효한 토큰 2개에 포함되지 않습니다. 이 토큰을 사용해도 ID 공급자 토큰의 교체가 시작되지 않습니다. 디렉터리당 한 번에 하나의 실행만 진행할 수 있습니다. 실행은 `directory.simulation_started`와 `directory.simulation_finished`로 감사 기록됩니다.

## 요청

| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| `directory_id` | 경로 | 예 | SCIM 디렉터리 ID(`dir_…`)입니다. |
| `scenario` | 본문, 문자열 | 예 | `seed`, `bulk_deactivate`, `group_churn`, `attribute_update` 또는 `conflict_email`입니다. |
| `Idempotency-Key` | 헤더 | 아니요 | 재시도된 요청에 대해 첫 응답을 다시 반환하며, 시나리오는 다시 실행되지 않습니다. |

```json
{"scenario": "bulk_deactivate"}
```

## 응답

실행 결과와 함께 `200 OK`를 반환합니다. SCIM 오류 응답이 와도 요청 자체는 실패하지 않습니다. 대신 실행이 `failed`가 되고 `failure`가 채워지며, 개수는 오류 발생 전까지 성공한 값으로 유지됩니다. 결과에는 개수와 상태만 포함되며 사용자, SCIM ID, 토큰은 포함되지 않습니다.

```json
{
  "directory_id": "dir_01j9xm2n4p6q8r0s2t4v6w8y0z",
  "scenario": "bulk_deactivate",
  "status": "completed",
  "users_created": 0,
  "groups_created": 0,
  "users_updated": 0,
  "groups_updated": 0,
  "users_deactivated": 15,
  "conflicts": 0,
  "circuit_breaker_tripped": true,
  "deprovision_hold": {"id": "0191e9b2-6f3a-7c4d-8e5f-0a1b2c3d4e5f", "pending_count": 6},
  "failure": null,
  "started_at": "2026-10-28T09:31:00.123456Z",
  "completed_at": "2026-10-28T09:31:01.654321Z"
}
```

| 필드 | 설명 |
|---|---|
| `status` | `completed`이거나, 엔드포인트가 SCIM 오류를 반환했거나, 실행 시간이 너무 길었거나, 응답이 시나리오의 기대와 다른 경우 `failed`입니다. |
| `users_updated` | 비활성화를 제외한 사용자 PATCH 요청 수입니다. |
| `users_deactivated` | 엔드포인트가 수락한 `active=false` PATCH 요청 수이며, 보류된 요청도 포함합니다. |
| `conflicts` | 예상된 `409 uniqueness` 응답 수(`conflict_email`)입니다. |
| `circuit_breaker_tripped` | 실행 중 대량 프로비저닝 해제 보류가 열렸는지 여부입니다. |
| `deprovision_hold` | 실행 후 디렉터리에 열려 있는 보류 항목이며, 없으면 `null`입니다. `deprovision-holds` 엔드포인트로 승인하거나 거부할 수 있습니다. |
| `failure` | `completed`인 경우 `null`입니다. 그 외에는 `reason`(`scim_error`, `timeout` 또는 `unexpected_response`)이 포함되며, `scim_error`인 경우 `scim_status`(HTTP 상태)와 `scim_type`(SCIM `scimType`, 없으면 `null`)도 포함됩니다. |

## 오류

| HTTP | code | 발생 조건 |
|---|---|---|
| 400 | `unknown_field` | 본문에 `scenario` 외의 필드가 포함되어 있습니다. |
| 403 | `test_feature_not_in_production` | 환경이 운영 환경입니다. |
| 404 | `not_found` | 이 환경에 디렉터리가 존재하지 않습니다. |
| 409 | `conflict` | 같은 디렉터리에서 다른 실행이 진행 중이거나, 디렉터리가 비활성화되었거나 삭제 중입니다. |
| 422 | `validation_failed` | `scenario`가 없거나 알 수 없는 값입니다(`/scenario`). |
| 422 | `idempotency_key_reuse` | `Idempotency-Key`가 다른 요청에 사용되었습니다. |
| 401 | `unauthenticated` | 자격 증명이 없거나, 유효하지 않거나, 폐기되었습니다. |
| 403 | `insufficient_permissions` | 자격 증명에 필요한 권한이 없습니다. |
| 429 | `rate_limited` | 속도 제한을 초과했습니다. `Retry-After` 기간 이후에 다시 시도하십시오. |
| 503 | `service_unavailable` | 디렉터리 동기화 또는 시뮬레이터를 일시적으로 사용할 수 없거나 이 배포 환경에 설정되어 있지 않습니다. `Retry-After` 기간 이후에 다시 시도하십시오. |

## 예시

```bash
curl -X POST "https://api.eu.keenauth.com/v1/directories/dir_01j9xm2n4p6q8r0s2t4v6w8y0z:simulate" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scenario": "seed"}'
```

```bash
keenauth directories simulate dir_01j9xm2n4p6q8r0s2t4v6w8y0z --scenario bulk_deactivate
```
