UserOnboarding
docs/domain/user-onboarding.md
UserOnboarding
개요
사용자 레벨의 초기 온보딩(MAKITT BEGIN) 진행 상태를 관리하는 도메인. 계정 인증, 프로필 설정, 조직 설정, 사업자 정보, 물류계정, 최초 샵 생성까지의 단계를 추적하여 /home 대시보드의 온보딩 아코디언 UI에 상태를 제공합니다.
MAKITT HAPPEN / EXPLODE는 샵 레벨의 온보딩이므로 ShopOnboarding 도메인에서 별도로 관리합니다.
User 엔티티와 동일한 파티션(PK)에 저장하되, SK를 ONBOARDING으로 분리하여 Single Table Design을 유지합니다.
서버 패키지: com.makitt.core.domain.user
DynamoDB Entity
UserOnboarding
User 파티션 하위의 온보딩 상태 엔티티.
키 구조:
| 키 | 패턴 | 예시 |
|---|---|---|
| PK | USER#{userId} | USER#abc123 |
| SK | ONBOARDING | ONBOARDING |
필드:
| 필드 | DynamoDB Attribute | 타입 | 필수 | 설명 |
|---|---|---|---|---|
| pk | PK | String | O | Partition Key |
| sk | SK | String | O | Sort Key |
| entityType | entity_type | String | O | "USER_ONBOARDING" 고정 |
| userId | user_id | String | O | 사용자 고유 ID |
| steps | steps | List<OnboardingStep> | O | 단계별 상태 (ordered list) |
| createdAt | created_at | Instant | O | 생성 시각 |
| updatedAt | updated_at | Instant | O | 수정 시각 |
Factory Methods:
UserOnboarding.create(userId)— 사용자 가입 시 기본 상태로 생성 (ACCOUNT_VERIFIED만 COMPLETED, 나머지는 PENDING + sub-step 초기화)
Nested Objects
OnboardingStep
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|---|---|---|
| stepId | step_id | String | 단계 ID (enum name) |
| status | status | StepStatus | 완료 상태 (sub-step이 있으면 mandatory sub-step 전부 완료 시 자동 COMPLETED) |
| completedAt | completed_at | Instant | 완료 시각 (null이면 미완료) |
| subSteps | sub_steps | List<OnboardingSubStep> | sub-step 목록 (없으면 null) |
OnboardingSubStep
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|---|---|---|
| subStepId | sub_step_id | String | sub-step ID (enum name) |
| status | status | StepStatus | 완료 상태 |
| mandatory | mandatory | Boolean | 필수 여부 (true면 부모 step 완료 조건에 포함) |
| completedAt | completed_at | Instant | 완료 시각 (null이면 미완료) |
Enums
UserOnboardingStep (상위 단계)
| 값 | 설명 | sub-step 여부 | 자동 완료 |
|---|---|---|---|
ACCOUNT_VERIFIED | 계정 인증 | X | O (가입 시 자동) |
PROFILE_COMPLETION | 프로필 완성 | O | X (mandatory sub-step 전부 완료 시) |
ORGANIZATION_COMPLETION | 조직 설정 완성 | O | X (mandatory sub-step 전부 완료 시) |
FIRST_SHOP_CREATED | 최초 샵 생성 | X | X |
ProfileSubStep
| 값 | 설명 | mandatory |
|---|---|---|
NAME_SET | 이름 설정 (firstName, lastName) | O |
PHONE_VERIFIED | 핸드폰 인증 | X (추후 mandatory 전환 예정) |
PASSWORD_SET | 비밀번호 설정 | X (OAuth 유저 불필요) |
PREFERENCES_SET | 언어, 타임존 설정 | X |
OrgSubStep
| 값 | 설명 | mandatory |
|---|---|---|
ORG_INFO_SET | 조직 기본정보 | O |
BUSINESS_INFO_SET | 사업자 정보 입력 | O |
LOGISTICS_CONNECTED | 물류계정 연결 | X |
StepStatus
| 값 | 설명 |
|---|---|
PENDING | 미완료 |
COMPLETED | 완료 |
단계 간 의존성
각 상위 단계는 기본적으로 독립적으로 진행할 수 있되, FIRST_SHOP_CREATED만 선행 조건이 존재한다.
ACCOUNT_VERIFIED ──(자동 완료)
PROFILE_COMPLETION ──┐ (sub-steps: NAME_SET*, PHONE_VERIFIED, PASSWORD_SET, PREFERENCES_SET)
├──▶ FIRST_SHOP_CREATED (선행 조건: 둘 다 COMPLETED)
ORGANIZATION_COMPLETION ──┘ (sub-steps: ORG_INFO_SET*, BUSINESS_INFO_SET*, LOGISTICS_CONNECTED)
* = mandatory
PROFILE_COMPLETION,ORGANIZATION_COMPLETION은 순서 무관, 독립적으로 진행 가능- 각 상위 step의 status는 mandatory sub-step이 전부 COMPLETED일 때 자동으로 COMPLETED
FIRST_SHOP_CREATED는PROFILE_COMPLETION과ORGANIZATION_COMPLETION이 모두 COMPLETED여야 진행 가능- 클라이언트에서
FIRST_SHOP_CREATED의 선행 조건 미충족 시 해당 항목을 비활성 표시하고, 어떤 선행 조건이 필요한지 안내
상태 자동 업데이트
각 도메인의 저장 API가 성공하면 해당 sub-step을 자동으로 업데이트한다. mandatory sub-step이 전부 완료되면 부모 step도 자동 COMPLETED.
| 트리거 API | 업데이트 대상 | 판단 조건 |
|---|---|---|
| 사용자 가입 완료 | ACCOUNT_VERIFIED → COMPLETED | 가입 시 자동 |
PUT /api/v1/users/me/profile (이름) | PROFILE_COMPLETION > NAME_SET → COMPLETED | firstName, lastName이 non-null |
| 핸드폰 인증 API | PROFILE_COMPLETION > PHONE_VERIFIED → COMPLETED | 핸드폰 인증 완료 |
| 비밀번호 설정 API | PROFILE_COMPLETION > PASSWORD_SET → COMPLETED | 비밀번호 설정 완료 |
PUT /api/v1/users/me/profile (환경설정) | PROFILE_COMPLETION > PREFERENCES_SET → COMPLETED | language, timezone이 non-null |
| Organization 생성/수정 API | ORGANIZATION_COMPLETION > ORG_INFO_SET → COMPLETED | Organization 데이터 존재 |
| 사업자 정보 저장 API | ORGANIZATION_COMPLETION > BUSINESS_INFO_SET → COMPLETED | 사업자 정보 존재 |
| 물류계정 연결 API | ORGANIZATION_COMPLETION > LOGISTICS_CONNECTED → COMPLETED | 물류계정 존재 |
| Shop 생성 API | FIRST_SHOP_CREATED → COMPLETED | Shop 1개 이상 존재 |
구현 방식: 각 도메인 서비스에서 UserOnboardingService.completeSubStep(userId, stepId, subStepId)을 호출. 내부에서 mandatory sub-step 완료 여부를 체크하여 부모 step status를 자동 갱신.
API
온보딩 상태 조회
GET /api/v1/users/me/onboarding-status
인증: Bearer Token 필요
응답:
{ "steps": [ { "stepId": "ACCOUNT_VERIFIED", "status": "COMPLETED", "blockedBy": [], "completedAt": "2025-01-15T09:00:00Z", "subSteps": null }, { "stepId": "PROFILE_COMPLETION", "status": "PENDING", "blockedBy": [], "completedAt": null, "subSteps": [ { "subStepId": "NAME_SET", "status": "PENDING", "mandatory": true, "completedAt": null }, { "subStepId": "PHONE_VERIFIED", "status": "PENDING", "mandatory": false, "completedAt": null }, { "subStepId": "PASSWORD_SET", "status": "PENDING", "mandatory": false, "completedAt": null }, { "subStepId": "PREFERENCES_SET", "status": "PENDING", "mandatory": false, "completedAt": null } ] }, { "stepId": "ORGANIZATION_COMPLETION", "status": "PENDING", "blockedBy": [], "completedAt": null, "subSteps": [ { "subStepId": "ORG_INFO_SET", "status": "PENDING", "mandatory": true, "completedAt": null }, { "subStepId": "BUSINESS_INFO_SET", "status": "PENDING", "mandatory": true, "completedAt": null }, { "subStepId": "LOGISTICS_CONNECTED", "status": "PENDING", "mandatory": false, "completedAt": null } ] }, { "stepId": "FIRST_SHOP_CREATED", "status": "PENDING", "blockedBy": ["PROFILE_COMPLETION", "ORGANIZATION_COMPLETION"], "completedAt": null, "subSteps": null } ], "progressPercent": 25 }
- blockedBy: 해당 단계를 진행하기 위해 먼저 완료해야 하는 미완료 단계 목록. 빈 배열이면 바로 진행 가능.
- 부모 step status: mandatory sub-step이 전부 COMPLETED이면 자동으로 COMPLETED.
- progressPercent 계산:
completedStepCount / totalStepCount * 100(4개 상위 step 기준)
Key Builder
클래스: com.makitt.core.common.dynamodb.key.UserKey (기존 확장)
// UserOnboarding Keys (User 파티션에 추가)
UserKey.pk(userId) → "USER#{userId}" (User와 동일 PK)
UserKey.onboardingSk() → "ONBOARDING"
서버 아키텍처
UserOnboardingController (makitt-api) -- GET /api/v1/users/me/onboarding-status
|
v (DTO <-> VO)
UserOnboardingApplication (makitt-application)
|
v (VO)
UserOnboardingService (makitt-core/service)
|
v (DynamoDB 조작)
UserOnboardingRepository (makitt-core/repository)
|
v
UserOnboarding (makitt-core/entity)
패키지 구조:
makitt-core/
com.makitt.core.domain.user/
entity/
UserOnboarding.java # DynamoDB Entity
OnboardingStep.java # 단계 Nested Object
UserOnboardingStep.java # 단계 Enum
StepStatus.java # 완료 상태 Enum
service/
UserOnboardingService.java # 상태 조회 + completeStep() + 의존성 체크
repository/
UserOnboardingRepository.java # DynamoDB Repository
makitt-application/
com.makitt.application.user/
UserOnboardingApplication.java
vo/
OnboardingStatusResponseVo.java
makitt-api/
com.makitt.api.controller.user/
UserOnboardingController.java
dto/
OnboardingStatusResponse.java
연동 포인트 (각 도메인에서 호출):
// 예: UserProfileApplication.updateProfile() 내부 — 이름 저장 시 userOnboardingService.completeSubStep(userId, UserOnboardingStep.PROFILE_COMPLETION, ProfileSubStep.NAME_SET); // 예: OrganizationApplication.create() 내부 userOnboardingService.completeSubStep(userId, UserOnboardingStep.ORGANIZATION_COMPLETION, OrgSubStep.ORG_INFO_SET); // 예: BusinessInfoApplication.save() 내부 userOnboardingService.completeSubStep(userId, UserOnboardingStep.ORGANIZATION_COMPLETION, OrgSubStep.BUSINESS_INFO_SET); // 예: ShopApplication.createShop() 내부 // → 내부에서 PROFILE_COMPLETION, ORGANIZATION_COMPLETION 완료 여부를 체크 userOnboardingService.completeStep(userId, UserOnboardingStep.FIRST_SHOP_CREATED);
관련 엔티티
| 엔티티 | 관계 | 설명 |
|---|---|---|
| User | 동일 PK (USER#{userId}) | User 파티션 내 별도 아이템 |
| Organization | completeSubStep 트리거 | 조직 생성 시 ORG_INFO_SET, 사업자 정보 시 BUSINESS_INFO_SET 완료 |
| Shop | completeStep 트리거 | 샵 생성 시 FIRST_SHOP_CREATED 완료 (선행 조건 체크) |
| ShopOnboarding | 후속 도메인 | MAKITT HAPPEN / EXPLODE는 샵 레벨에서 관리 |
참조
- Domain: User
- Epic: 회원가입 플로우 정리 + Home 온보딩