7.0.9 페이로드 대비 버전이 오른 패키지 31종과 코어의 CHANGELOG 최상단 절 날짜를 2026-09-04 로 맞췄다. 이어서 릴리즈 스크립트의 게이트를 브랜치 생성 없이 전수 실행한 결과, 파일 본문 누출 검사가 error 25건으로 릴리즈를 막고 있었다. 전부 이번 사이클에 들어온 것이다. - 확장 문서·코어 주석 20건이 공개 배포본에 없는 를 가리켰다. 공개되는 AGENTS.md 참조로 바꾸고, 참조된 9개 절의 실재를 전수 확인했다. 유일하게 빠져 있던 「독립 레이아웃의 글로벌 호스트 컴포넌트」절은 원래 동기화 대상이었으므로 AGENTS.md 에 반영했다. - 시나리오 매니페스트의 내부 문서 포인터는 소비자가 하나도 없어 제거했다. - 공개 테스트 3건이 내부 검사 스크립트를 열어 도구 간 리터럴을 대조하고 있었다. tests/** 는 배포 페이로드에 포함되고 는 제외되므로 배포본에서 원리상 성립할 수 없는 검사다. 대조를 그 도구 옆으로 옮기고 공개 테스트에는 자기 동작 단언만 남겼다. 존재 가드로 무마하지 않은 것은 그 경우 배포본에서 검사가 조용히 건너뛰어져 "검사하지 않음" 과 "통과" 가 구분되지 않기 때문이다. 옮긴 대조는 돌지 않으면 잠그지 못하므로 대상 파일 편집 시 자동 실행되도록 등록했다. 누출 검사 자체도 릴리즈 시점에만 돌아 위반이 다음 릴리즈까지 드러나지 않았으므로, 룰을 복제하지 않고 실행 시점만 세션 종료로 앞당겼다. 같은 검증 중 드러난 선행 결함 하나(이커머스 문서의 집계 블록 드리프트)도 함께 정리했다.
5.6 KiB
KG이니시스 본인인증 — 데이터 모델
모델·소유 테이블·마이그레이션·Enum · 진입점: AGENTS.md
모델
| 모델 | 테이블 | fillable | 관계 | 특성 |
|---|---|---|---|---|
InicisChallengeMapping |
inicis_challenge_mappings |
2 | challenge→IdentityVerificationLog | - |
InicisIdentityRecord |
inicis_identity_records |
17 | user→User | - |
InicisIdentityRecord가 PII(이름·생년월일·성별·CI/DI 등)를 직접 보관하는 것이 결제
플러그인들과의 근본적 차이입니다(§AGENTS.md "1. 이 확장은 무엇인가") — 이 레코드가 없으면
"이 사용자가 본인확인을 완료했는가"를 매번 이니시스에 재조회해야 합니다.
InicisChallengeMapping은 별도 모델입니다 — 진행 중인 인증 시도(mTxId ↔ challenge_id)와
완료된 확인 결과(PII record)는 생명주기가 다르기 때문입니다(전자는 인증 세션 하나,
후자는 사용자당 최신 1건).
소유 테이블
| 테이블 | 모델 |
|---|---|
inicis_challenge_mappings |
InicisChallengeMapping |
inicis_identity_records |
InicisIdentityRecord |
inicis_identity_records.user_id는 unique 제약을 갖습니다 — 한 사용자는 본인확인 결과를
1건만 보유하며, 재인증 시 기존 레코드를 갱신합니다(새 레코드를 추가하지 않습니다). 이
설계 덕분에 "이 사용자가 본인확인을 완료했는가"는 단순 존재 조회 하나로 판정됩니다.
마이그레이션
마이그레이션 3개.
| 파일 | 생성 테이블 | 변경 테이블 | down() |
|---|---|---|---|
2026_05_08_000001_create_inicis_identity_records_table.php |
inicis_identity_records |
inicis_identity_records |
✅ |
2026_05_08_000002_create_inicis_challenge_mappings_table.php |
inicis_challenge_mappings |
inicis_challenge_mappings |
✅ |
2026_06_22_000001_make_inicis_record_aux_fields_nullable.php |
- | inicis_identity_records |
✅ |
세 번째 마이그레이션이 name/phone/birthday 암호화 컬럼을 nullable 로 완화한 이유는
누락 값을 null로 저장하기 위함입니다 — Crypt::encryptString('')로 "암호화된 빈
문자열"을 저장하면 복호화 시 빈 칸이 나오는 오염 레코드가 됩니다. 정상 경로에서는
verify() 가드(INCOMPLETE_IDENTITY)가 이 신원 핵심값의 누락을 이미 차단하므로 항상
채워지며, 이 nullable 화는 가드를 우회한 비정상 입력이 암호화된 빈 문자열로 오염
저장되는 것을 막는 방어적 통일입니다.
Enum
| Enum | backing | case 수 | case |
|---|---|---|---|
InicisDuplicateField |
string |
2 | di, ci |
di(연계정보)와 ci(연계정보의 상위 개념 — 사이트 간 동일인 식별용) 중 어느 필드로 중복
가입을 판정할지는 운영자가 설정으로 고릅니다(§settings.md duplicate_field). Enum 으로
닫힌 것은 이 값이 AssertNoDuplicateInicisIdentity의 조회 조건과
InicisIdentityLogQueryRepository의 컬럼 화이트리스트 양쪽에서 타입 안전하게 재사용되기
때문입니다 — 문자열 리터럴이었다면 오타가 조용히 "중복 없음"으로 판정될 위험이 있습니다.
Repository
| 클래스 | 종류 | 설명 |
|---|---|---|
InicisChallengeMappingRepository |
구현 | inicis_challenge_mappings 테이블 Repository 구현체. |
InicisChallengeMappingRepositoryInterface |
인터페이스 | 이니시스 mTxId ↔ challenge_id 매핑 Repository 인터페이스. |
InicisIdentityLogQueryRepository |
구현 | InicisIdentityLogQueryRepositoryInterface 구현체. |
InicisIdentityLogQueryRepositoryInterface |
인터페이스 | 본 plugin 의 동일인 검증 listener 전용 IdentityVerificationLog 조회 Repository. |
InicisIdentityRecordRepository |
구현 | inicis_identity_records 테이블 Repository 구현체. |
InicisIdentityRecordRepositoryInterface |
인터페이스 | KG이니시스 본인확인 PII 레코드 Repository 인터페이스. |
3쌍(인터페이스+구현체)으로 나뉜 것은 각자 다른 데이터를 다루기 때문입니다 —
InicisChallengeMappingRepository(진행 중인 인증 세션), InicisIdentityRecordRepository
(완료된 PII), InicisIdentityLogQueryRepository(동일인 검증 전용 IdentityVerificationLog
조회, 코어 로그 테이블을 이 플러그인 관점으로 좁혀 읽는 어댑터). 결제 플러그인들이
Repository 를 하나도 두지 않는 것과 대조적으로, 이 플러그인은 실제 PII 를 소유하므로
Repository 인터페이스 주입 원칙(§코어 AGENTS.md "Service-Repository 패턴")이 그대로 적용됩니다.