Rebrand repository from "Re:Link" to "Startover" across the codebase. Updates include package names and scopes (@relink/* -> @startover/*), import paths, Next.js transpile settings, vitest name, UI text and docs, Dockerfile and CI/workflow names, deploy scripts and repo paths, and example/production env values. Also add auth-related env vars, an apps/web .env symlink, and small formatting/typing cleanups in several TSX/TS files and tests to accommodate the rename.
47 KiB
Startover 이벤트 스키마 정의서
문서 코드: D004 버전: 1.0.0 작성일: 2026-03-07 적용 범위: MVP Phase 1 전체 도메인 승인 상태: 초안 관련 문서: schema-prisma-draft.md, D001(subsidy-policy.md), D002(contract-escrow-policy.md), D003(data-exposure-policy.md)
목차
1. 목적 및 설계 원칙
1-1. 목적
이 문서는 Startover 플랫폼에서 EventLog 테이블에 저장되는 도메인 이벤트의 규격을 정의한다.
이벤트 로그는 세 가지 목적으로 활용된다.
- 감사 추적: 도메인 객체의 상태 전환을 불변(immutable) append-only 방식으로 보존한다.
- 비동기 연동:
OutboxEvent를 통해 외부 시스템(알림, 정산, 분석)에 이벤트를 발행한다. - KPI 분석: 매칭 전환율, 지원금 케이스 성공률, 에스크로 정산 속도 등 지표 산출에 활용한다.
EventLog는 AuditLog와 구분된다. AuditLog는 운영자/사용자 행위의 before/after 스냅샷을 운영 감사 목적으로 남기는 반면, EventLog는 도메인 이벤트를 비즈니스 의미 단위로 기록하고 후속 처리의 입력으로 활용한다.
1-2. 이벤트 네이밍 규칙
이벤트 이름은 {도메인}.{액션} 또는 {도메인}.{엔티티}_{액션} 형태를 따른다.
{도메인}.{액션}
예: store.submitted, match.accepted, subsidy.approved
{도메인}.{엔티티}_{액션}
예: store.deal_status_changed, subsidy.document_uploaded, vendor.certification_approved
규칙:
- 도메인과 액션은 모두 소문자 스네이크케이스(
snake_case)를 사용한다. - 도메인과 액션 사이는 점(
.)으로 구분한다. - 엔티티와 액션 사이는 언더스코어(
_)로 구분한다. - 액션은 과거형(completed action)으로 표현한다.
create가 아니라created,accept가 아니라accepted. - 한 이벤트는 정확히 하나의 비즈니스 사실을 표현한다. 복수 상태 전환을 하나의 이벤트로 합치지 않는다.
도메인 접두어 목록:
| 접두어 | 대응 도메인 / aggregate |
|---|---|
user |
Identity — User, UserConsent |
store |
Store Supply — Store, StorePhoto |
match |
Matching — MatchRequest |
subsidy |
Subsidy — SubsidyCase, SubsidyDocument |
vendor |
Vendor — Vendor, VendorCertification |
contract |
Trust — Contract |
escrow |
Trust — EscrowTransaction |
inspection |
Trust — InspectionRecord |
dispute |
Trust — DisputeCase |
operator |
Backoffice — 운영자 배정 |
policy |
Backoffice — PolicyVersion 활성화 |
1-3. 이벤트 버전 관리 정책
eventVersion 필드는 동일한 eventName의 payload 스키마가 하위 호환이 깨지는 방식으로 변경될 때 증가한다.
| 상황 | 처리 방식 |
|---|---|
| 새 필드 추가 (선택적) | eventVersion 유지. 소비자는 미지 필드를 무시해야 한다. |
| 필드 타입 변경 또는 필수 필드 제거 | eventVersion을 v2, v3으로 증가. 구버전 소비자와 공존 가능 기간을 명시한다. |
| 이벤트 이름 변경 | 이전 이름을 deprecated로 표시하고 마이그레이션 기간 동안 양쪽을 동시 발행한다. |
초기 버전은 v1이다. 버전 문자열 형식: v{N} (예: v1, v2).
1-4. PII 레벨 정책
piiLevel 필드는 payload에 개인정보가 포함되는 정도를 나타낸다. 이 값은 이벤트 스트림을 외부 시스템에 발행하거나 로그를 장기 보관할 때 마스킹 또는 접근 제어 기준으로 사용한다.
| 레벨 | 정의 | payload 예시 |
|---|---|---|
NONE |
개인 식별 정보 없음. 집계 ID 또는 상태값만 포함. | storeId, status, amount |
LOW |
간접 식별 가능한 정보 포함. 이름·연락처·주소는 없으나 내부 ID로 역추적 가능. | userId, vendorId, matchRequestId |
HIGH |
직접 식별 정보 포함. 이름, 이메일, 전화번호, 주소, 사업자번호 등. | email, phone, businessRegistrationNumber |
원칙:
- payload에
HIGHPII가 포함되어야 한다면 해당 필드를 포함하지 않는 대신 연결 ID(예:userId)만 기록하고 PII는 원본 테이블에서 조회한다. OutboxEvent로 외부 발행 시HIGH이벤트는 발행하지 않거나, 발행 전 PII 필드를 제거한 별도 payload를 사용한다.NONE이벤트는 별도 접근 제어 없이 분석 시스템에 전달할 수 있다.
2. 공통 이벤트 엔벨로프
모든 이벤트는 EventLog 테이블의 다음 컬럼 구조를 공유한다.
2-1. EventLog 컬럼 정의
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
BigInt |
내부 자동 증가 PK. 외부에 노출하지 않는다. |
aggregateType |
String |
이벤트가 속한 aggregate 타입. 예: Store, MatchRequest, SubsidyCase |
aggregateId |
String |
aggregate의 publicId 또는 내부 ID (BigInt를 문자열로 직렬화). |
eventName |
String |
이벤트 이름. 네이밍 규칙 참조. 예: store.submitted |
eventVersion |
String |
payload 스키마 버전. 기본값 v1. |
eventKey |
String |
중복 방지용 고유 키. @unique 제약. 형식: {aggregateType}:{aggregateId}:{eventName}:{idempotencyToken} |
payloadJson |
Json |
이벤트 상세 데이터. 도메인별 스키마는 섹션 3 참조. |
actorUserId |
BigInt? |
이벤트를 발생시킨 사용자 ID. 시스템 자동 이벤트인 경우 null. |
causationId |
String? |
이 이벤트를 직접 유발한 이벤트의 eventKey. 이벤트 체이닝 추적에 사용. |
correlationId |
String |
동일 비즈니스 트랜잭션을 묶는 ID. HTTP 요청 ID 또는 saga ID. |
piiLevel |
String |
NONE / LOW / HIGH. 섹션 1-4 참조. |
occurredAt |
DateTime |
이벤트가 비즈니스 레벨에서 발생한 시각 (UTC). |
recordedAt |
DateTime |
DB에 기록된 시각 (UTC). @default(now()). |
2-2. payloadJson 공통 구조 권고
모든 payload는 아래 최상위 필드를 포함하도록 권고한다. 도메인별 필드는 추가로 확장한다.
{
"aggregateId": "store_abc123",
"previousStatus": "DRAFT",
"currentStatus": "SUBMITTED",
"triggeredBy": "USER_ACTION"
}
| 공통 필드 | 타입 | 설명 |
|---|---|---|
aggregateId |
string |
aggregate 식별자 (publicId). |
previousStatus |
string? |
전환 전 상태. 상태 전환 이벤트에서 필수. |
currentStatus |
string? |
전환 후 상태. 상태 전환 이벤트에서 필수. |
triggeredBy |
string |
USER_ACTION / OPERATOR_ACTION / SYSTEM_AUTO / WEBHOOK |
2-3. eventKey 생성 규칙
eventKey는 멱등성 보장을 위해 고유해야 한다.
{aggregateType}:{aggregateId}:{eventName}:{ulid 또는 uuid}
예: Store:store_abc123:store.submitted:01HXXXXXXXXXXXXX
재시도 안전성이 필요한 경우 idempotencyToken에 외부에서 주입된 멱등 키를 사용할 수 있다.
3. 도메인별 이벤트 목록 및 payload 스키마
3-1. Identity 도메인
aggregateType: User
user.registered
사용자가 신규 회원가입을 완료했을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
user.registered |
aggregateType |
User |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "user_abc123",
"userId": "user_abc123",
"primaryRole": "CLOSING_OWNER",
"registrationChannel": "KAKAO_OAUTH"
}
| 필드 | 타입 | 설명 |
|---|---|---|
userId |
string |
사용자 publicId |
primaryRole |
string |
UserRole enum 값. CLOSING_OWNER / FOUNDER / VENDOR_MANAGER / OPS_MANAGER / SUBSIDY_OPERATOR / TRUST_OPERATOR / FINANCE_OPERATOR / SUPER_ADMIN |
registrationChannel |
string |
KAKAO_OAUTH / NAVER_OAUTH / GOOGLE_OAUTH / EMAIL |
user.verified
이메일 또는 전화번호 인증이 완료되었을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
user.verified |
aggregateType |
User |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "user_abc123",
"userId": "user_abc123",
"verificationType": "EMAIL",
"verifiedAt": "2026-03-07T10:05:00Z"
}
| 필드 | 타입 | 설명 |
|---|---|---|
verificationType |
string |
EMAIL / PHONE |
verifiedAt |
string |
ISO 8601 UTC |
user.profile_updated
사용자 프로필 정보가 변경되었을 때 발행된다. 변경된 필드 목록만 기록하며 값 자체는 포함하지 않는다(PII 보호).
| 항목 | 값 |
|---|---|
eventName |
user.profile_updated |
aggregateType |
User |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "user_abc123",
"userId": "user_abc123",
"updatedFields": ["name", "phone"],
"profileType": "CLOSING_OWNER"
}
| 필드 | 타입 | 설명 |
|---|---|---|
updatedFields |
string[] |
변경된 필드명 목록. 실제 값은 포함하지 않는다. |
profileType |
string? |
UserProfile 변경인 경우 프로필 타입 |
user.consent_granted / user.consent_revoked
동의 항목이 수락 또는 철회될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
user.consent_granted 또는 user.consent_revoked |
aggregateType |
User |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "user_abc123",
"userId": "user_abc123",
"consentType": "STORE_PUBLICATION_CONSENT",
"policyVersionId": "polv_xyz",
"isGranted": true
}
| 필드 | 타입 | 설명 |
|---|---|---|
consentType |
string |
TERMS_OF_SERVICE / PRIVACY_POLICY_REQUIRED / PRIVACY_POLICY_MARKETING / STORE_PUBLICATION_CONSENT / MATCHED_INFO_DISCLOSURE / THIRD_PARTY_MATCHED_PARTY / NOTIFICATION_KAKAO |
policyVersionId |
string |
동의 당시 적용된 PolicyVersion publicId |
isGranted |
boolean |
true(granted) / false(revoked) |
user.suspended / user.reactivated
운영자가 계정을 정지하거나 재활성화할 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
user.suspended 또는 user.reactivated |
aggregateType |
User |
piiLevel |
LOW |
triggeredBy |
OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "user_abc123",
"userId": "user_abc123",
"previousStatus": "ACTIVE",
"currentStatus": "SUSPENDED",
"reasonCode": "POLICY_VIOLATION",
"operatorId": "user_op01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
previousStatus |
string |
UserStatus enum 값. PENDING_VERIFICATION / ACTIVE / SUSPENDED / DEACTIVATED |
currentStatus |
string |
UserStatus enum 값 |
reasonCode |
string |
사유 코드 |
operatorId |
string |
처리한 운영자 userId |
3-2. Store Supply 도메인
aggregateType: Store
store.draft_created
폐업자가 매장 등록 초안을 생성했을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
store.draft_created |
aggregateType |
Store |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"ownerUserId": "user_abc123",
"industryLeafId": 42,
"regionClusterId": 7
}
| 필드 | 타입 | 설명 |
|---|---|---|
storeId |
string |
Store publicId |
ownerUserId |
string |
폐업자 userId |
industryLeafId |
number |
업종 말단 분류 ID (IndustryTaxonomy 참조) |
regionClusterId |
number |
지역 클러스터 ID (RegionHierarchy 참조) |
store.submitted
폐업자가 매장 등록을 운영자 검토용으로 제출했을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
store.submitted |
aggregateType |
Store |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"ownerUserId": "user_abc123",
"previousStatus": "DRAFT",
"currentStatus": "SUBMITTED",
"submittedAt": "2026-03-07T11:00:00Z"
}
| 필드 | 타입 | 설명 |
|---|---|---|
previousStatus |
string |
StoreReviewStatus 값. DRAFT |
currentStatus |
string |
StoreReviewStatus 값. SUBMITTED |
store.approved / store.rejected
운영자가 매장 등록 검토를 완료했을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
store.approved 또는 store.rejected |
aggregateType |
Store |
piiLevel |
LOW |
triggeredBy |
OPERATOR_ACTION |
payloadJson (approved):
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"previousStatus": "REVIEWING",
"currentStatus": "APPROVED",
"operatorId": "user_op01",
"approvedAt": "2026-03-07T14:00:00Z"
}
payloadJson (rejected):
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"previousStatus": "REVIEWING",
"currentStatus": "REJECTED",
"operatorId": "user_op01",
"reasonCode": "INVALID_DOCUMENT",
"rejectedAt": "2026-03-07T14:00:00Z"
}
| 필드 | 타입 | 설명 |
|---|---|---|
operatorId |
string |
처리한 운영자 userId |
reasonCode |
string? |
store.rejected 시 필수. 반려 사유 코드. |
store.published / store.unpublished
매장의 공개 상태(publicationStatus)가 변경될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
store.published 또는 store.unpublished |
aggregateType |
Store |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"previousPublicationStatus": "PRIVATE",
"currentPublicationStatus": "PUBLISHED",
"triggeredBy": "USER_ACTION",
"consentRecordId": "consent_xyz"
}
| 필드 | 타입 | 설명 |
|---|---|---|
previousPublicationStatus |
string |
StorePublicationStatus enum 값. PRIVATE / RESTRICTED / PUBLISHED / UNPUBLISHED |
currentPublicationStatus |
string |
StorePublicationStatus enum 값 |
consentRecordId |
string? |
store.published 시 — 정보 공개에 동의한 UserConsent ID |
store.deal_status_changed
매장의 거래 상태(dealStatus)가 변경될 때 발행된다. OPEN→MATCHING→RESERVED→CONTRACTED→CLOSED→CANCELLED 전환 모두 이 이벤트로 처리한다.
| 항목 | 값 |
|---|---|
eventName |
store.deal_status_changed |
aggregateType |
Store |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"previousDealStatus": "OPEN",
"currentDealStatus": "MATCHING",
"triggeredBy": "SYSTEM_AUTO",
"relatedMatchRequestId": "match_xyz",
"relatedContractId": null
}
| 필드 | 타입 | 설명 |
|---|---|---|
previousDealStatus |
string |
StoreDealStatus enum 값. OPEN / MATCHING / RESERVED / CONTRACTED / CLOSED / CANCELLED |
currentDealStatus |
string |
StoreDealStatus enum 값 |
relatedMatchRequestId |
string? |
매칭 요청 수락으로 인한 전환인 경우 |
relatedContractId |
string? |
계약 완료/취소로 인한 전환인 경우 |
store.photo_uploaded / store.photo_removed
매장 사진이 업로드되거나 삭제될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
store.photo_uploaded 또는 store.photo_removed |
aggregateType |
Store |
piiLevel |
NONE |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "store_abc123",
"storeId": "store_abc123",
"photoId": "12345",
"photoCategory": "KITCHEN",
"visibilityScope": "RESTRICTED",
"uploadedByUserId": "user_abc123"
}
| 필드 | 타입 | 설명 |
|---|---|---|
photoId |
string |
StorePhoto 내부 ID (BigInt를 문자열로 직렬화) |
photoCategory |
string |
PhotoCategory enum 값. EXTERIOR / INTERIOR / KITCHEN / EQUIPMENT / FLOOR_PLAN / DOCUMENT |
visibilityScope |
string |
VisibilityScope enum 값. INTERNAL / MATCHED_ONLY / PUBLIC_SUMMARY |
uploadedByUserId |
string? |
store.photo_removed 시에는 삭제 실행자 userId |
3-3. Matching 도메인
aggregateType: MatchRequest
match.requested
창업자/업체/운영자 추천으로 매칭 요청이 생성될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
match.requested |
aggregateType |
MatchRequest |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "match_abc123",
"matchRequestId": "match_abc123",
"storeId": "store_xyz",
"matchType": "ACQUISITION",
"requesterUserId": "user_founder01",
"requesterVendorId": null,
"sourceType": "USER_INITIATED"
}
| 필드 | 타입 | 설명 |
|---|---|---|
matchType |
string |
MatchType enum 값. ACQUISITION / DEMOLITION / INTERIOR |
requesterUserId |
string? |
창업자(FOUNDER)인 경우 userId |
requesterVendorId |
string? |
업체(VENDOR_MANAGER)인 경우 vendorId |
sourceType |
string |
USER_INITIATED / OPERATOR_RECOMMENDED / SYSTEM_SUGGESTED |
match.accepted / match.rejected
폐업자 또는 운영자가 매칭 요청을 수락하거나 거절했을 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
match.accepted 또는 match.rejected |
aggregateType |
MatchRequest |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "match_abc123",
"matchRequestId": "match_abc123",
"storeId": "store_xyz",
"matchType": "ACQUISITION",
"previousStatus": "REVIEWING",
"currentStatus": "ACCEPTED",
"decisionByUserId": "user_owner01",
"decisionReasonCode": null
}
| 필드 | 타입 | 설명 |
|---|---|---|
previousStatus |
string |
MatchRequestStatus enum 값 |
currentStatus |
string |
ACCEPTED 또는 REJECTED |
decisionByUserId |
string |
결정한 사용자 또는 운영자 userId |
decisionReasonCode |
string? |
match.rejected 시 반려 사유 코드 |
match.expired / match.cancelled
매칭 요청이 만료되거나 취소될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
match.expired 또는 match.cancelled |
aggregateType |
MatchRequest |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO 또는 USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "match_abc123",
"matchRequestId": "match_abc123",
"storeId": "store_xyz",
"previousStatus": "OPEN",
"currentStatus": "EXPIRED",
"triggeredBy": "SYSTEM_AUTO",
"reasonCode": "NO_RESPONSE_TIMEOUT"
}
match.completed
매칭이 정상 완료될 때(계약 완료 이후) 발행된다.
| 항목 | 값 |
|---|---|
eventName |
match.completed |
aggregateType |
MatchRequest |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO |
payloadJson:
{
"aggregateId": "match_abc123",
"matchRequestId": "match_abc123",
"storeId": "store_xyz",
"matchType": "ACQUISITION",
"previousStatus": "CONTRACTING",
"currentStatus": "COMPLETED",
"relatedContractId": "contract_xyz"
}
3-4. Subsidy 도메인
aggregateType: SubsidyCase
subsidy.case_created
지원금 케이스가 DRAFT 상태로 생성될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
subsidy.case_created |
aggregateType |
SubsidyCase |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"storeId": "store_xyz",
"applicantUserId": "user_abc123",
"programCode": "HOPE_RETURN_PKG",
"policyVersionId": "polv_xyz",
"checklistVersionCode": "HOPE_RETURN_PKG_V1"
}
| 필드 | 타입 | 설명 |
|---|---|---|
programCode |
string |
지원 프로그램 코드. MVP는 HOPE_RETURN_PKG |
policyVersionId |
string |
케이스 생성 시점에 고정되는 PolicyVersion publicId |
checklistVersionCode |
string |
케이스 생성 시점의 체크리스트 버전. 예: HOPE_RETURN_PKG_V1 |
subsidy.eligibility_checked
자격 판별이 실행되어 결과가 결정될 때 발행된다. SubsidyCase가 ELIGIBILITY_CHECKED 상태로 전환될 때 발행한다.
| 항목 | 값 |
|---|---|
eventName |
subsidy.eligibility_checked |
aggregateType |
SubsidyCase |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO |
payloadJson:
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"storeId": "store_xyz",
"eligibilityResult": "ELIGIBLE",
"previousStatus": "DRAFT",
"currentStatus": "ELIGIBILITY_CHECKED",
"policyVersionId": "polv_xyz"
}
| 필드 | 타입 | 설명 |
|---|---|---|
eligibilityResult |
string |
EligibilityResult enum 값. ELIGIBLE / CONDITIONALLY_ELIGIBLE / NOT_ELIGIBLE / UNKNOWN |
eligibilitySnapshotJson 원본은 SubsidyCase 테이블에 저장하며 이벤트 payload에는 포함하지 않는다(PII 보호).
subsidy.document_uploaded / subsidy.document_reviewed
지원금 서류가 업로드되거나 운영자 검토가 완료될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
subsidy.document_uploaded 또는 subsidy.document_reviewed |
aggregateType |
SubsidyCase |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson (document_uploaded):
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"subsidyDocumentId": "sdoc_xyz",
"documentTypeCode": "HRP_DOC_001",
"itemCode": "HRP_DOC_001",
"uploadedByUserId": "user_abc123",
"isResubmission": false
}
payloadJson (document_reviewed):
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"subsidyDocumentId": "sdoc_xyz",
"documentTypeCode": "HRP_DOC_001",
"reviewResult": "APPROVED",
"reviewedByOperatorId": "user_op01",
"reasonCode": null
}
| 필드 | 타입 | 설명 |
|---|---|---|
isResubmission |
boolean |
반려 후 재업로드 여부 |
reviewResult |
string |
APPROVED / REJECTED / RESUBMITTED |
reasonCode |
string? |
REJECTED 시 반려 사유 코드. MISSING_DOCUMENT / INVALID_DOCUMENT / ILLEGIBLE_DOCUMENT / EXPIRED_DOCUMENT / ELIGIBILITY_ISSUE / INCOMPLETE_INFO / MISMATCHED_INFO / WRONG_FORMAT |
subsidy.submitted / subsidy.approved / subsidy.rejected
지원금 케이스의 주요 상태 전환 이벤트다.
| 항목 | 값 |
|---|---|
eventName |
subsidy.submitted / subsidy.approved / subsidy.rejected |
aggregateType |
SubsidyCase |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson (submitted):
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"storeId": "store_xyz",
"programCode": "HOPE_RETURN_PKG",
"previousStatus": "READY_TO_SUBMIT",
"currentStatus": "SUBMITTED"
}
payloadJson (approved):
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"storeId": "store_xyz",
"programCode": "HOPE_RETURN_PKG",
"previousStatus": "SUBMITTED",
"currentStatus": "APPROVED",
"operatorId": "user_op01"
}
payloadJson (rejected):
{
"aggregateId": "scase_abc123",
"subsidyCaseId": "scase_abc123",
"storeId": "store_xyz",
"programCode": "HOPE_RETURN_PKG",
"previousStatus": "SUBMITTED",
"currentStatus": "REJECTED",
"operatorId": "user_op01",
"rejectionReasonCode": "INELIGIBLE_AFTER_REVIEW"
}
3-5. Vendor 도메인
aggregateType: Vendor
vendor.registered
업체가 플랫폼에 신규 등록될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
vendor.registered |
aggregateType |
Vendor |
piiLevel |
LOW |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "vendor_abc123",
"vendorId": "vendor_abc123",
"ownerUserId": "user_vendor01",
"vendorType": "DEMOLITION",
"primaryRegionId": 7
}
| 필드 | 타입 | 설명 |
|---|---|---|
vendorType |
string |
VendorType enum 값. DEMOLITION / INTERIOR / BOTH |
primaryRegionId |
number |
주요 서비스 지역 ID (RegionHierarchy 참조) |
vendor.certification_applied / vendor.certification_approved / vendor.certification_rejected
업체 인증 신청, 승인, 반려 이벤트다.
| 항목 | 값 |
|---|---|
eventName |
vendor.certification_applied / vendor.certification_approved / vendor.certification_rejected |
aggregateType |
Vendor |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson (certification_applied):
{
"aggregateId": "vendor_abc123",
"vendorId": "vendor_abc123",
"certificationId": "vcert_xyz",
"requestedScopeCode": "DEMOLITION_STANDARD",
"previousCertificationStatus": null,
"currentCertificationStatus": "APPLIED"
}
payloadJson (certification_approved):
{
"aggregateId": "vendor_abc123",
"vendorId": "vendor_abc123",
"certificationId": "vcert_xyz",
"previousCertificationStatus": "REVIEWING",
"currentCertificationStatus": "APPROVED",
"reviewedByOperatorId": "user_op01",
"validUntil": "2027-03-07T00:00:00Z"
}
payloadJson (certification_rejected):
{
"aggregateId": "vendor_abc123",
"vendorId": "vendor_abc123",
"certificationId": "vcert_xyz",
"previousCertificationStatus": "REVIEWING",
"currentCertificationStatus": "REJECTED",
"reviewedByOperatorId": "user_op01",
"reasonCode": "INSUFFICIENT_DOCUMENTS"
}
| 필드 | 타입 | 설명 |
|---|---|---|
currentCertificationStatus |
string |
VendorCertificationStatus enum 값. APPLIED / REVIEWING / APPROVED / REJECTED / SUSPENDED / EXPIRED |
validUntil |
string? |
certification_approved 시 인증 유효 기간 |
3-6. Trust Infrastructure 도메인
Contract 이벤트
aggregateType: Contract
contract.created
매칭 수락 후 계약이 생성될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
contract.created |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"matchRequestId": "match_xyz",
"storeId": "store_xyz",
"contractType": "ACQUISITION",
"templateCode": "ACQUISITION_V1",
"storeOwnerUserId": "user_owner01",
"buyerUserId": "user_founder01",
"vendorId": null
}
| 필드 | 타입 | 설명 |
|---|---|---|
contractType |
string |
ContractType enum 값. ACQUISITION / DEMOLITION / INTERIOR |
templateCode |
string |
사용된 계약서 템플릿 코드 |
vendorId |
string? |
DEMOLITION / INTERIOR 계약인 경우 |
contract.signed
계약 양측 서명이 완료될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
contract.signed |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"contractVersionId": "cver_xyz",
"previousStatus": "SIGNING",
"currentStatus": "SIGNED",
"signerCount": 2
}
서명자 개인정보(ipAddress, userAgent)는 SignatureEvidence 테이블에만 저장하고 이벤트 payload에는 포함하지 않는다.
contract.completed / contract.cancelled
계약이 완료되거나 취소될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
contract.completed 또는 contract.cancelled |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
SYSTEM_AUTO 또는 OPERATOR_ACTION |
payloadJson (completed):
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"storeId": "store_xyz",
"contractType": "ACQUISITION",
"previousStatus": "ACTIVE",
"currentStatus": "COMPLETED",
"triggeredBy": "SYSTEM_AUTO",
"relatedEscrowTransactionId": "etx_xyz"
}
payloadJson (cancelled):
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"storeId": "store_xyz",
"contractType": "ACQUISITION",
"previousStatus": "SIGNING",
"currentStatus": "CANCELLED",
"triggeredBy": "SYSTEM_AUTO",
"reasonCode": "SIGNING_TIMEOUT"
}
Escrow 이벤트
에스크로 이벤트는 계약의 부속 상태이므로 Contract를 aggregateType으로 사용한다.
aggregateType: Contract
escrow.deposit_initiated
에스크로 결제 요청이 PG사로 발송될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
escrow.deposit_initiated |
aggregateType |
Contract |
piiLevel |
NONE |
triggeredBy |
SYSTEM_AUTO |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"escrowTransactionId": "etx_xyz",
"amount": 5000000,
"currencyCode": "KRW",
"providerCode": "TOSSPAYMENTS",
"idempotencyKey": "etx_abc123_deposit_01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
amount |
number |
결제 요청 금액 (KRW, 정수) |
providerCode |
string |
PG사 코드 |
idempotencyKey |
string |
중복 방지 키 |
escrow.holding
PG 결제 성공 웹훅이 처리되어 에스크로가 HOLDING 상태로 전환될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
escrow.holding |
aggregateType |
Contract |
piiLevel |
NONE |
triggeredBy |
WEBHOOK |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"escrowTransactionId": "etx_xyz",
"previousEscrowStatus": "DEPOSIT_PENDING",
"currentEscrowStatus": "HOLDING",
"amount": 5000000,
"currencyCode": "KRW",
"providerTransactionId": "pg_txn_999"
}
escrow.released
운영자 정산 승인 후 에스크로가 해제될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
escrow.released |
aggregateType |
Contract |
piiLevel |
NONE |
triggeredBy |
OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"escrowTransactionId": "etx_xyz",
"previousEscrowStatus": "RELEASE_REVIEW",
"currentEscrowStatus": "RELEASED",
"settledAmount": 4850000,
"platformFeeAmount": 150000,
"currencyCode": "KRW",
"approvedByOperatorId": "user_fin01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
settledAmount |
number |
업체에 지급되는 정산 금액 (KRW) |
platformFeeAmount |
number |
플랫폼 수수료 금액 (KRW) |
escrow.refunded
환불이 실행될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
escrow.refunded |
aggregateType |
Contract |
piiLevel |
NONE |
triggeredBy |
OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"escrowTransactionId": "etx_xyz",
"previousEscrowStatus": "DISPUTED",
"currentEscrowStatus": "REFUNDED",
"refundType": "FULL_REFUND",
"refundAmount": 5000000,
"currencyCode": "KRW",
"reasonCode": "DISPUTE_RESOLVED",
"approvedByOperatorId": "user_fin01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
refundType |
string |
FULL_REFUND / PARTIAL_REFUND |
refundAmount |
number |
환불 금액 (KRW) |
Inspection 이벤트
aggregateType: Contract
inspection.submitted
검수 사진이 업로드되어 검수 요청이 완료될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
inspection.submitted |
aggregateType |
Contract |
piiLevel |
NONE |
triggeredBy |
USER_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"inspectionRecordId": "insp_xyz",
"inspectionType": "DEMOLITION_COMPLETION",
"previousStatus": "REQUESTED",
"currentStatus": "SUBMITTED",
"photoCount": 6,
"submittedByUserId": "user_vendor01"
}
inspection.approved / inspection.rejected
검수가 승인 또는 거절될 때 발행된다. 1차(폐업자)와 2차(운영자) 승인 모두 이 이벤트를 사용하며 approvalStage로 구분한다.
| 항목 | 값 |
|---|---|
eventName |
inspection.approved 또는 inspection.rejected |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson (approved):
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"inspectionRecordId": "insp_xyz",
"previousStatus": "REVIEWING",
"currentStatus": "APPROVED",
"approvalStage": "OPERATOR_FINAL",
"reviewedByUserId": "user_op01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
approvalStage |
string |
OWNER_PRIMARY (폐업자 1차) / OPERATOR_FINAL (운영자 2차) |
reviewedByUserId |
string |
검수를 처리한 사용자 또는 운영자 userId |
Dispute 이벤트
aggregateType: Contract
dispute.opened
분쟁이 접수될 때 발행된다. 에스크로가 즉시 DISPUTED 상태로 전환된다.
| 항목 | 값 |
|---|---|
eventName |
dispute.opened |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
USER_ACTION 또는 OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"disputeCaseId": "disp_xyz",
"openedByUserId": "user_founder01",
"reasonCode": "QUALITY_ISSUE",
"previousEscrowStatus": "HOLDING",
"currentEscrowStatus": "DISPUTED"
}
| 필드 | 타입 | 설명 |
|---|---|---|
reasonCode |
string |
QUALITY_ISSUE / SCOPE_DIFFERENCE / TIMELINE_BREACH / DAMAGE / INCOMPLETE_WORK / OTHER |
previousEscrowStatus |
string |
분쟁 접수 전 에스크로 상태 (HOLDING 또는 RELEASE_REVIEW) |
currentEscrowStatus |
string |
DISPUTED (고정값) |
dispute.resolved
분쟁이 해결될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
dispute.resolved |
aggregateType |
Contract |
piiLevel |
LOW |
triggeredBy |
OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "contract_abc123",
"contractId": "contract_abc123",
"disputeCaseId": "disp_xyz",
"previousDisputeStatus": "MEDIATING",
"currentDisputeStatus": "RESOLVED",
"resolutionCode": "PARTIAL_REFUND",
"refundAmount": 2000000,
"settledAmount": 3000000,
"resolvedByOperatorId": "user_trust01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
resolutionCode |
string |
FULL_RELEASE / PARTIAL_REFUND / FULL_REFUND / NEGOTIATED |
refundAmount |
number? |
환불 금액. FULL_RELEASE인 경우 0 또는 null |
settledAmount |
number? |
정산 금액. FULL_REFUND인 경우 0 또는 null |
3-7. Backoffice 도메인
operator.assigned
운영자가 케이스(SubsidyCase, MatchRequest, DisputeCase 등)에 배정될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
operator.assigned |
aggregateType |
배정 대상 엔티티 타입 (예: SubsidyCase, MatchRequest) |
piiLevel |
LOW |
triggeredBy |
OPERATOR_ACTION 또는 SYSTEM_AUTO |
payloadJson:
{
"aggregateId": "scase_abc123",
"targetEntityType": "SubsidyCase",
"targetEntityId": "scase_abc123",
"assignedOperatorId": "user_op01",
"assignedByUserId": "user_manager01"
}
| 필드 | 타입 | 설명 |
|---|---|---|
targetEntityType |
string |
배정 대상 엔티티 타입 |
assignedOperatorId |
string |
배정된 운영자 userId |
assignedByUserId |
string? |
배정을 실행한 상위 운영자. 시스템 자동 배정이면 null |
policy.version_activated
정책 버전이 활성화될 때 발행된다.
| 항목 | 값 |
|---|---|
eventName |
policy.version_activated |
aggregateType |
PolicyVersion |
piiLevel |
NONE |
triggeredBy |
OPERATOR_ACTION |
payloadJson:
{
"aggregateId": "polv_xyz",
"policyVersionId": "polv_xyz",
"policyType": "SUBSIDY_CHECKLIST",
"versionCode": "HOPE_RETURN_PKG_V2",
"previousVersionCode": "HOPE_RETURN_PKG_V1",
"effectiveFrom": "2026-04-01T00:00:00Z",
"activatedByOperatorId": "user_admin01"
}
4. Outbox 발행 정책
4-1. Outbox 발행 대상 이벤트
OutboxEvent는 EventLog와 별도로 외부 시스템(알림 서비스, 분석 파이프라인 등)으로의 비동기 발행을 담당한다. 아래에 해당하는 이벤트는 EventLog 기록과 동시에 OutboxEvent로도 저장한다.
| 이벤트 | 발행 이유 | 소비자 |
|---|---|---|
store.approved |
공개 전환 안내 알림 트리거 | 알림 서비스 |
store.rejected |
반려 사유 안내 알림 트리거 | 알림 서비스 |
store.published |
구독자 알림 (Phase 2 준비) | 알림 서비스 |
match.requested |
폐업자 매칭 요청 수신 알림 | 알림 서비스 |
match.accepted |
창업자/업체 매칭 수락 알림 + 계약 생성 트리거 | 알림 서비스, 계약 서비스 |
match.rejected |
창업자/업체 매칭 거절 알림 | 알림 서비스 |
match.expired |
만료 알림 | 알림 서비스 |
subsidy.case_created |
운영자 큐 등록 트리거 | 운영 콘솔 |
subsidy.document_reviewed |
서류 검토 결과 알림 | 알림 서비스 |
subsidy.submitted |
운영자 최종 접수 알림 | 알림 서비스 |
subsidy.approved |
지원금 승인 결과 알림 | 알림 서비스 |
subsidy.rejected |
지원금 반려 결과 알림 | 알림 서비스 |
vendor.certification_approved |
업체 인증 승인 알림 + 매칭 참여 자격 활성화 | 알림 서비스, 매칭 서비스 |
vendor.certification_rejected |
업체 인증 반려 알림 | 알림 서비스 |
contract.signed |
에스크로 결제 요청 트리거 | 결제 서비스 |
contract.completed |
완료 알림 + KPI 집계 트리거 | 알림 서비스, 분석 파이프라인 |
escrow.holding |
에스크로 보관 확인 알림 | 알림 서비스 |
escrow.released |
정산 완료 알림 | 알림 서비스 |
escrow.refunded |
환불 완료 알림 | 알림 서비스 |
inspection.submitted |
검수 요청 수신 알림 | 알림 서비스 |
inspection.approved |
정산 검토 단계 진입 트리거 | 에스크로 서비스 |
dispute.opened |
분쟁 접수 운영자 알림 + 에스크로 보류 트리거 | 알림 서비스, 에스크로 서비스 |
dispute.resolved |
분쟁 해결 알림 + 정산/환불 트리거 | 알림 서비스, 결제 서비스 |
발행 대상이 아닌 이벤트(user.profile_updated, store.photo_uploaded, store.deal_status_changed 등)는 EventLog에만 기록하고 OutboxEvent는 생성하지 않는다.
4-2. 트랜잭션 보장
EventLog와 OutboxEvent는 반드시 동일한 DB 트랜잭션 내에서 도메인 상태 변경과 함께 커밋한다.
BEGIN TRANSACTION
-- 도메인 상태 변경 (Store, MatchRequest, SubsidyCase 등)
-- EventLog INSERT
-- OutboxEvent INSERT (발행 대상인 경우만)
COMMIT
애플리케이션 코드에서 EventLog 커밋 후 별도로 OutboxEvent를 삽입하지 않는다. 트랜잭션 바깥에서 삽입하면 상태 불일치가 발생한다.
4-3. OutboxEvent 필드
| 필드 | 설명 |
|---|---|
aggregateType |
EventLog의 aggregateType과 동일 |
aggregateId |
EventLog의 aggregateId와 동일 |
eventName |
EventLog의 eventName과 동일 |
payloadJson |
외부 발행용 payload. HIGH PII 필드는 제거 또는 마스킹 후 저장. |
publishStatus |
PENDING → PUBLISHED / FAILED / DEAD_LETTER |
availableAt |
최초 처리 가능 시각. 기본값 NOW(). 재시도 시 갱신. |
retryCount |
재시도 횟수. 0부터 시작. |
lastError |
마지막 실패 오류 메시지 (최대 2000자). |
4-4. 재시도 정책
발행 실패 시 지수 백오프(Exponential Backoff) 방식으로 재시도한다.
| 시도 | 대기 시간 |
|---|---|
| 1차 | 1분 후 |
| 2차 | 5분 후 |
| 3차 | 15분 후 |
| 4차 | 1시간 후 |
| 5차 | 4시간 후 |
최대 재시도 횟수: 5회.
4-5. Dead-Letter 처리
5회 재시도 모두 실패한 경우 아래 처리를 실행한다.
OutboxEvent.publishStatus를DEAD_LETTER로 변경한다.FINANCE_OPERATOR또는OPS_MANAGER에게 내부 알림을 발송한다.- 운영자가 수동으로 재발행하거나 해당 이벤트를 수동 처리한다.
- 재발행 실행 시
retryCount를 0으로 초기화하고availableAt을 현재 시각으로 설정한다. - 모든 수동 재발행 이력은
AuditLog에 기록한다.
Dead-Letter 이벤트는 삭제하지 않는다. 원인 분석과 감사 목적으로 영구 보관한다.
5. 향후 확장
5-1. 알림 트리거 이벤트
Phase 2에서 알림 서비스가 고도화되면 이벤트 기반 알림 발송 규칙을 아래 이벤트 중심으로 선언적으로 정의할 예정이다.
| 이벤트 | 알림 수신자 | 발송 채널 |
|---|---|---|
store.approved |
폐업자 | 이메일 |
store.rejected |
폐업자 | 이메일 |
match.requested |
폐업자 | 카카오 알림톡 |
match.accepted |
창업자/업체 | 카카오 알림톡 |
subsidy.document_reviewed (REJECTED) |
폐업자 | 카카오 알림톡 + 이메일 |
subsidy.approved |
폐업자 | 카카오 알림톡 + 이메일 |
escrow.holding |
계약 당사자 | 이메일 |
escrow.released |
계약 당사자 | 이메일 + 카카오 알림톡 |
dispute.opened |
운영자(TRUST_OPERATOR) |
내부 알림 |
향후 AlertSubscription 모델을 도입하면 업체(VENDOR_MANAGER) 대상 B2B 알림 상품도 이 이벤트 스트림을 기반으로 구현한다(D003 섹션 6-3 참조).
5-2. KPI 집계 이벤트
Phase 2에서 KpiSnapshot 모델을 도입하면 아래 이벤트를 집계 파이프라인의 입력으로 활용한다.
| KPI | 기반 이벤트 |
|---|---|
| 매장 등록 → 공개 전환율 | store.submitted → store.published |
| 매칭 요청 → 수락 전환율 | match.requested → match.accepted |
| 매칭 → 계약 완료율 | match.accepted → contract.completed |
| 지원금 케이스 완료율 | subsidy.case_created → subsidy.approved |
| 에스크로 정산 소요 시간 | escrow.holding → escrow.released |
| 분쟁 발생률 | contract.signed 대비 dispute.opened |
| 분쟁 해결 소요 시간 | dispute.opened → dispute.resolved |
집계 이벤트는 별도의 KpiSnapshot 테이블 또는 외부 데이터 웨어하우스에서 처리하며, 원본 EventLog에 직접 집계 쿼리를 수행하지 않는다.
5-3. 이벤트 스키마 레지스트리
이벤트 종류가 증가하면 다음 관리 체계를 도입한다.
- 각
eventName의 JSON Schema를 별도 파일(docs/analytics/event-schemas/{eventName}.json)로 관리한다. - 이벤트 발행 전 payload를 JSON Schema로 검증하는 미들웨어를 적용한다.
- 버전별 스키마 이력을 보존하여 구버전 소비자와의 호환성을 유지한다.
부록
A. 이벤트 이름 전체 목록
| 이벤트 이름 | aggregateType | piiLevel | OutboxEvent |
|---|---|---|---|
user.registered |
User |
LOW | - |
user.verified |
User |
LOW | - |
user.profile_updated |
User |
LOW | - |
user.consent_granted |
User |
LOW | - |
user.consent_revoked |
User |
LOW | - |
user.suspended |
User |
LOW | - |
user.reactivated |
User |
LOW | - |
store.draft_created |
Store |
LOW | - |
store.submitted |
Store |
LOW | - |
store.approved |
Store |
LOW | O |
store.rejected |
Store |
LOW | O |
store.published |
Store |
LOW | O |
store.unpublished |
Store |
LOW | - |
store.deal_status_changed |
Store |
LOW | - |
store.photo_uploaded |
Store |
NONE | - |
store.photo_removed |
Store |
NONE | - |
match.requested |
MatchRequest |
LOW | O |
match.accepted |
MatchRequest |
LOW | O |
match.rejected |
MatchRequest |
LOW | O |
match.expired |
MatchRequest |
LOW | O |
match.cancelled |
MatchRequest |
LOW | - |
match.completed |
MatchRequest |
LOW | - |
subsidy.case_created |
SubsidyCase |
LOW | O |
subsidy.eligibility_checked |
SubsidyCase |
LOW | - |
subsidy.document_uploaded |
SubsidyCase |
LOW | - |
subsidy.document_reviewed |
SubsidyCase |
LOW | O |
subsidy.submitted |
SubsidyCase |
LOW | O |
subsidy.approved |
SubsidyCase |
LOW | O |
subsidy.rejected |
SubsidyCase |
LOW | O |
vendor.registered |
Vendor |
LOW | - |
vendor.certification_applied |
Vendor |
LOW | - |
vendor.certification_approved |
Vendor |
LOW | O |
vendor.certification_rejected |
Vendor |
LOW | O |
contract.created |
Contract |
LOW | - |
contract.signed |
Contract |
LOW | O |
contract.completed |
Contract |
LOW | O |
contract.cancelled |
Contract |
LOW | - |
escrow.deposit_initiated |
Contract |
NONE | - |
escrow.holding |
Contract |
NONE | O |
escrow.released |
Contract |
NONE | O |
escrow.refunded |
Contract |
NONE | O |
inspection.submitted |
Contract |
NONE | O |
inspection.approved |
Contract |
LOW | O |
inspection.rejected |
Contract |
LOW | - |
dispute.opened |
Contract |
LOW | O |
dispute.resolved |
Contract |
LOW | O |
operator.assigned |
(대상 엔티티) | LOW | - |
policy.version_activated |
PolicyVersion |
NONE | - |
B. 관련 문서
| 문서 | 경로 |
|---|---|
| Prisma 스키마 초안 | /docs/database/schema-prisma-draft.md |
| 지원금 대행 정책서 (D001) | /docs/policies/subsidy-policy.md |
| 계약-에스크로-분쟁 정책서 (D002) | /docs/policies/contract-escrow-policy.md |
| 정보 공개 정책서 (D003) | /docs/policies/data-exposure-policy.md |
C. 개정 이력
| 버전 | 날짜 | 변경 내용 | 작성자 |
|---|---|---|---|
| 1.0.0 | 2026-03-07 | 초안 작성 (MVP Phase 1 전 도메인) | - |