
# ID 설정 업데이트

`PATCH /v1/identity-settings` · 권한 `identity-settings:write`

JSON 병합 패치로 환경의 사용자 이름 설정을 업데이트합니다 (`application/merge-patch+json`, RFC 7396). `If-Match`는 필수입니다. 누락되면 `428`, 버전이 오래되면 `412`가 반환됩니다. 설정이 한 번도 기록되지 않았다면 버전은 `"0"`이며 첫 번째 쓰기가 행을 만듭니다. 아무것도 변경하지 않는 패치는 아무것도 저장하지 않으며 버전을 유지합니다.

## 요청

| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| `If-Match` | header | 예 | 마지막으로 읽은 설정의 `ETag` (한 번도 기록되지 않았다면 `"0"`). 누락: `428`; 만료: `412`. |
| `username_identifier` | string | 아니오 | `required`, `optional` 또는 `off`. `null`일 수 없습니다. |
| `username_min_length` | integer | 아니오 | 3~64이며 `username_max_length`보다 클 수 없습니다. `null`일 수 없습니다. |
| `username_max_length` | integer | 아니오 | 3~64이며 `username_min_length`보다 작을 수 없습니다. `null`일 수 없습니다. |
| `reserved_usernames` | string[] \| null | 아니오 | 최대 1000개 이름. 목록 전체를 대체합니다 (RFC 7396은 배열을 병합하지 않음). `null` 또는 `[]`는 목록을 비웁니다. 각 항목은 정규화되고 중복은 제거되며 목록은 정렬되어 저장됩니다. |
| `verification_policy` | string | 아니요 | `before_sign_in` (기본값) 또는 `after_sign_in`. `after_sign_in`은 미인증 계정 정리를 중지합니다. `null`일 수 없습니다. |
| `unverified_account_ttl_days` | integer | 아니요 | 1~30 (기본값 7): `before_sign_in` 환경에서 미인증 가입을 삭제하기 전까지 보관하는 일수입니다. `null`일 수 없습니다. |

사용자 이름 설정은 이후의 쓰기에만 적용되며 기존 사용자를 변경하지 않습니다. 인증 설정은 기존 가입에도 적용됩니다 (아래 참조).

## 적용 규칙

- `off` (기본값): 사용자 이름을 쓰는 요청 (`POST /v1/users`, `PATCH /v1/users/{id}`)은 `422` 및 `identifier_type_disabled` 코드 (포인터 `/username`)로 실패합니다. 기존 사용자 이름을 지우는 것은 계속 허용되며, 사용자 이름을 건드리지 않는 사용자 패치는 다시 검사하지 않습니다. 로그인은 사용자 이름으로 계정을 찾지 않습니다.
- `optional`: 사용자 이름을 설정할 수 있습니다. `required`: 관리 API로 사용자 이름 없이 사용자를 만들면 `422` (`required`)로 실패하며 관리 패치로 지울 수 없습니다. 가입 양식에서 사용자 이름을 요구하는 것은 호스팅 로그인의 몫이며, 소셜 및 JIT(Just-in-Time) 생성은 사용자 이름을 요구하지 않습니다.
- 길이: `username_min_length`보다 짧거나 `username_max_length`보다 긴 사용자 이름은 `422` (`invalid`)로 실패합니다.
- 예약된 이름: 정규화된 형태가 `reserved_usernames`에 있는 사용자 이름은 `422` 및 `username_reserved` 코드로 실패합니다. 잘못된 목록 항목은 `422` 및 `/reserved_usernames/<i>` 포인터로 실패합니다.
- 설정이 바뀌어도 기존 사용자는 변경되지 않으며, 규칙은 이후의 쓰기에만 적용됩니다.

## 미인증 계정 정리

`verification_policy`와 `unverified_account_ttl_days`는 한 번도 인증되지 않은 가입의 자동 정리를 제어합니다. 정리는 이메일 주소 (또는 전화번호)가 필수 식별자일 때만 실행되며, 이메일은 기본적으로 필수입니다.

- `before_sign_in` (기본값): 가입으로 생성된 사용자는 필수 식별자를 인증하기 전에는 토큰을 받을 수 없습니다. 가입 후 `unverified_account_ttl_days`일 (1~30, 기본값 7)이 지나도 인증된 이메일 주소나 전화번호가 없고, 토큰을 한 번도 받지 않았으며, 소셜 또는 엔터프라이즈 (SAML/OIDC) ID가 없는 가입 사용자는 영구 삭제됩니다. 정리는 주기적으로 (기본값은 매시간) 실행됩니다.
- `after_sign_in`: 사용자는 인증 전에 토큰을 받습니다 (`email_verified: false`). 정리는 실행되지 않으며 어떤 사용자도 삭제되지 않습니다.
- 삭제되지 않는 사용자: 관리 API, 가져오기, SCIM, 초대 또는 JIT 페더레이션으로 생성된 사용자, 차단된 사용자, 삭제가 이미 시작된 사용자. 환경에서 정리가 시작된 이후에 생성된 가입만 대상이 됩니다.
- 삭제는 되돌릴 수 없습니다. 사용자는 하드 삭제되고, 사유가 `unverified_expired`인 툼스톤이 보관되며 `user.deleted` 이벤트가 게시됩니다.
- 정책이나 기간 변경은 다음 실행부터 적용됩니다. `unverified_account_ttl_days`를 줄이면 더 오래된 미인증 가입이 즉시 대상이 되고, `after_sign_in`에서 `before_sign_in`으로 되돌리면 기간이 지난 미인증 가입이 다음 실행에서 삭제됩니다.

## 응답

`200 OK`와 함께 업데이트된 설정 및 새 `ETag`가 반환됩니다.

```json
{
  "username_identifier": "optional",
  "username_min_length": 3,
  "username_max_length": 32,
  "reserved_usernames": ["admin", "root", "support"],
  "verification_policy": "before_sign_in",
  "unverified_account_ttl_days": 7,
  "updated_at": "2026-10-05T09:30:00.123456Z"
}
```

## 오류

| HTTP | code | 조건 |
|---|---|---|
| 400 | `unknown_field` | 패치에 알 수 없는 필드 또는 읽기 전용 필드가 있거나 JSON 객체가 아닙니다 (`malformed_request`). |
| 412 | `precondition_failed` | `If-Match`가 현재 버전과 일치하지 않습니다. |
| 415 | `unsupported_media_type` | 콘텐츠 유형이 `application/merge-patch+json`이 아닙니다. |
| 422 | `validation_failed` | 값이 유효하지 않거나, `min`이 `max`보다 크거나, `null`일 수 없는 필드가 `null`로 설정되었습니다 (`code: invalid`). |
| 428 | `precondition_required` | `If-Match` 헤더가 누락되었습니다. |
| 401 | `unauthenticated` | 자격 증명이 누락되었거나, 잘못되었거나, 취소되었습니다. |
| 403 | `insufficient_permissions` | 자격 증명에 필요한 권한이 없습니다. |
| 429 | `rate_limited` | 속도 제한을 초과했습니다. `Retry-After` 기간 후에 다시 시도하세요. |
| 503 | `service_unavailable` | 종속성을 일시적으로 사용할 수 없습니다. `Retry-After` 기간 후에 다시 시도하세요. |

## 예제

```bash
curl -X PATCH https://api.eu.keenauth.com/v1/identity-settings \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/merge-patch+json" \
  -H 'If-Match: "0"' \
  -d '{"username_identifier":"optional","username_max_length":32,"reserved_usernames":["admin","root","support"]}'
```
