From c5b1eb050e441097b0da270698b152b4237b9634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Wed, 11 Feb 2026 17:04:06 +0900 Subject: [PATCH] =?UTF-8?q?docs:=EC=98=81=EC=97=85/=EB=A7=A4=EC=B6=9C?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B0=9C=EB=B0=9C=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(7=EA=B0=9C=20=EB=A9=94=EB=89=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 영업관리 대시보드: 수당 현황, 테넌트 진행률, 파트너 활동 - 파트너관리: 영업파트너 CRUD, 역할 관리, 서류 관리 - 영업파트너승인: 신규 파트너 신청 승인/반려 워크플로우 - 상품관리: 카테고리별 상품, 가격/수당률 설정 - 고객관리(관리자): 전사 고객 현황, 본사 진행상태 8단계 - 영업파트너 고객관리: 명함등록 기반 영업권, 테넌트 전환 - 인터뷰 시나리오: 질문 템플릿, 세션 기반 인터뷰 기록 Co-Authored-By: Claude Opus 4.6 --- features/sales/README.md | 128 +++++++++++++ features/sales/admin-prospects.md | 155 +++++++++++++++ features/sales/interviews.md | 281 ++++++++++++++++++++++++++++ features/sales/partner-approvals.md | 102 ++++++++++ features/sales/partners.md | 166 ++++++++++++++++ features/sales/products.md | 175 +++++++++++++++++ features/sales/prospects.md | 189 +++++++++++++++++++ features/sales/sales-dashboard.md | 122 ++++++++++++ 8 files changed, 1318 insertions(+) create mode 100644 features/sales/README.md create mode 100644 features/sales/admin-prospects.md create mode 100644 features/sales/interviews.md create mode 100644 features/sales/partner-approvals.md create mode 100644 features/sales/partners.md create mode 100644 features/sales/products.md create mode 100644 features/sales/prospects.md create mode 100644 features/sales/sales-dashboard.md diff --git a/features/sales/README.md b/features/sales/README.md new file mode 100644 index 0000000..4fc22f0 --- /dev/null +++ b/features/sales/README.md @@ -0,0 +1,128 @@ +# 영업/매출관리 + +## 개요 + +영업/매출관리 모듈은 영업파트너 관리, 고객 영업권, 상품 관리, 인터뷰 시나리오 등 +영업 전체 프로세스를 관리하는 기능 그룹입니다. + +- **라우트 Prefix**: `/sales` +- **미들웨어**: `auth`, `hq.member` (본사 회원 전용) +- **UI 기술**: Blade + HTMX + Alpine.js (일부 React) + +## 메뉴 구성 + +| # | 메뉴명 | 경로 | 문서 | 상태 | +|---|--------|------|------|------| +| 1 | 영업관리 대시보드 | `/sales/salesmanagement/dashboard` | [sales-dashboard.md](sales-dashboard.md) | 구현완료 | +| 2 | 파트너관리 | `/sales/managers` | [partners.md](partners.md) | 구현완료 | +| 3 | 영업파트너승인 | `/sales/managers/approvals` | [partner-approvals.md](partner-approvals.md) | 구현완료 | +| 4 | 상품관리 | `/sales/products` | [products.md](products.md) | 구현완료 | +| 5 | 세일즈사이트 | (외부 링크) | - | 미구현 | +| 6 | 랜딩페이지 | (외부 링크) | - | 미구현 | +| 7 | 고객 관리 | `/sales/admin-prospects` | [admin-prospects.md](admin-prospects.md) | 구현완료 | +| 8 | 영업파트너 고객관리 | `/sales/prospects` | [prospects.md](prospects.md) | 구현완료 | +| 9 | 인터뷰 시나리오 | `/sales/interviews` | [interviews.md](interviews.md) | 구현완료 | + +## 아키텍처 + +``` +영업/매출관리 +├── 대시보드 ──── 수당 현황, 테넌트 진행률, 파트너 활동 +├── 파트너관리 +│ ├── 파트너 CRUD ──── 영업파트너 등록/수정/역할 관리 +│ └── 파트너 승인 ──── 신규 파트너 신청 승인/반려 +├── 상품관리 ──── 카테고리별 상품, 가격/수당률 설정 +├── 고객관리 +│ ├── 고객 관리(관리자) ──── 전사 고객 현황, 본사 진행상태 +│ └── 파트너 고객관리 ──── 명함등록 기반 영업권 관리 +└── 인터뷰 시나리오 ──── 질문 템플릿, 인터뷰 세션 기록 +``` + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ ├── SalesDashboardController.php # 영업관리 대시보드 +│ ├── SalesManagerController.php # 파트너관리 + 승인 +│ ├── SalesProductController.php # 상품관리 +│ ├── TenantProspectController.php # 영업권(명함등록) 관리 +│ ├── AdminProspectController.php # 관리자 전체 고객 관리 +│ └── InterviewScenarioController.php # 인터뷰 시나리오 +├── app/Models/Sales/ +│ ├── SalesPartner.php # 영업파트너 +│ ├── SalesTenantManagement.php # 테넌트 영업 관리 +│ ├── TenantProspect.php # 가망고객 (영업권) +│ ├── SalesCommission.php # 영업 수수료 +│ ├── SalesProduct.php # 영업 상품 +│ ├── SalesProductCategory.php # 상품 카테고리 +│ └── SalesManagerDocument.php # 파트너 서류 +├── app/Models/Interview/ +│ ├── InterviewCategory.php # 인터뷰 카테고리 +│ ├── InterviewTemplate.php # 인터뷰 템플릿 +│ ├── InterviewQuestion.php # 인터뷰 질문 +│ ├── InterviewSession.php # 인터뷰 세션 +│ └── InterviewAnswer.php # 인터뷰 답변 +├── app/Services/Sales/ +│ ├── SalesManagerService.php # 파트너 관리 서비스 +│ ├── TenantProspectService.php # 영업권 서비스 +│ └── InterviewScenarioService.php # 인터뷰 서비스 +└── resources/views/sales/ + ├── dashboard/ # 대시보드 뷰 + ├── managers/ # 파트너관리 뷰 + ├── products/ # 상품관리 뷰 + ├── prospects/ # 영업권 관리 뷰 + ├── admin-prospects/ # 관리자 고객관리 뷰 + └── interviews/ # 인터뷰 시나리오 뷰 + +api/ +└── database/migrations/ + ├── 2026_01_27_221000_create_tenant_prospects_table.php + ├── 2026_01_28_090000_add_attachments_to_tenant_prospects_table.php + ├── 2026_01_29_100000_create_sales_partners_table.php + ├── 2026_01_29_100100_create_sales_tenant_managements_table.php + ├── 2026_01_29_150000_create_sales_products_tables.php + └── 2026_02_06_10000x_create_interview_*_tables.php (5개) +``` + +## 핵심 데이터 모델 관계 + +``` +User (영업파트너) + │ + ├── SalesPartner (파트너 정보, 수수료율, 계좌) + │ + ├── TenantProspect (영업권 = 명함등록) + │ ├── status: active → expired / converted / completed + │ ├── 유효기간: 2개월 + │ └── 쿨다운: 만료 후 1개월 + │ │ + │ ↓ convert() + │ Tenant (계약 고객사) + │ │ + │ ↓ + │ SalesTenantManagement (영업 관리) + │ ├── status: prospect → approach → negotiation → contracted → onboarding → active + │ ├── hq_status: pending → review → planning → coding → dev_test → dev_done → int_test → handover + │ └── SalesCommission (수당 정보) + │ + └── SalesManagerDocument (등록 서류) + +SalesProductCategory + └── SalesProduct (개발비, 가입비, 구독료, 수당율) + └── SalesContractProduct (계약별 선택 상품) + +InterviewCategory + └── InterviewTemplate + └── InterviewQuestion + └── InterviewSession → InterviewAnswer +``` + +## 권한 체계 + +| 역할 | 대시보드 | 파트너관리 | 승인 | 상품 | 고객관리 | 파트너고객 | 인터뷰 | +|------|---------|-----------|------|------|---------|-----------|--------| +| 영업파트너 | O (본인) | - | - | - | - | O (본인) | O | +| 상담매니저 | O (본인) | - | - | - | - | - | O | +| 관리자 | O (전체) | O | O | O | O | O | O | +| 슈퍼관리자 | O (전체) | O | O | O | O (삭제) | O | O | diff --git a/features/sales/admin-prospects.md b/features/sales/admin-prospects.md new file mode 100644 index 0000000..b1b92ef --- /dev/null +++ b/features/sales/admin-prospects.md @@ -0,0 +1,155 @@ +# 고객 관리 (관리자) + +## 개요 + +고객 관리(관리자)는 본사 관리자가 모든 영업파트너의 고객을 통합 관리하는 기능입니다. +전사 고객 현황 파악, 본사 진행상태 관리, 수당 지급 기록, 상태 변경을 지원합니다. + +- **라우트**: `GET /sales/admin-prospects` +- **미들웨어**: `auth`, `hq.member` + 관리자 권한 체크 +- **UI 기술**: Blade + HTMX + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── AdminProspectController.php # 메인 컨트롤러 (8개 메서드) +└── resources/views/sales/admin-prospects/ + ├── index.blade.php # 전체 고객 목록 (460줄) + └── partials/ + ├── content.blade.php # 콘텐츠 새로고침 + └── show-modal.blade.php # 고객 상세 모달 +``` + +## 라우트 + +```php +// routes/web.php (sales prefix 그룹 내) +GET /admin-prospects → index() 전체 고객 목록 +GET /admin-prospects/refresh → refresh() HTMX 새로고침 +GET /admin-prospects/{id}/modal-show → modalShow() 상세 모달 +POST /admin-prospects/{id}/hq-status → updateHqStatus() 본사 진행상태 변경 +POST /admin-prospects/{id}/commission-date → updateCommissionDate() 수당 날짜 기록 +DELETE /admin-prospects/{id}/commission-date → clearCommissionDate() 수당 날짜 초기화 +DELETE /admin-prospects/{id} → destroy() 삭제 (슈퍼관리자) +POST /admin-prospects/{id}/toggle-status → toggleStatus() 상태 토글 +``` + +## 컨트롤러 + +### AdminProspectController + +| 메서드 | HTTP | 설명 | 권한 | +|--------|------|------|------| +| `index()` | GET | 전체 고객 목록 (필터+통계) | 관리자/슈퍼관리자 | +| `refresh()` | GET | 콘텐츠 새로고침 (HTMX) | 관리자/슈퍼관리자 | +| `modalShow()` | GET | 고객 상세 모달 (진행률 포함) | 관리자/슈퍼관리자 | +| `updateHqStatus()` | POST | 본사 진행상태 변경 | 관리자/슈퍼관리자 | +| `updateCommissionDate()` | POST | 수당 지급 날짜 기록/수정 | 관리자/슈퍼관리자 | +| `clearCommissionDate()` | DELETE | 수당 날짜 초기화 | 관리자/슈퍼관리자 | +| `toggleStatus()` | POST | 상태 토글 (영업중 ↔ 완료) | 관리자/슈퍼관리자 | +| `destroy()` | DELETE | 삭제 | 슈퍼관리자 전용 | + +### 본사 진행상태 (HQ Status) 8단계 + +``` +pending (대기) + → review (검토) + → planning (기획안작성) + → coding (개발코드작성) + → dev_test (개발테스트) + → dev_done (개발완료) + → int_test (통합테스트) + → handover (인계) +``` + +### 수당 날짜 관리 + +``` +updateCommissionDate(): + - 납입일(membership_paid_at) 입력 시 + - 자동 지급일 계산: 익월 10일 + - commission_paid_at 기록 +``` + +## 모델 + +### SalesTenantManagement (핵심 모델) + +**테이블**: `sales_tenant_managements` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint (FK, unique) | 테넌트 ID (1:1) | +| `tenant_prospect_id` | bigint (FK) | 가망고객 ID | +| `sales_partner_id` | bigint (FK) | 영업 담당자 ID | +| `manager_user_id` | bigint (FK) | 상담매니저 사용자 ID | +| `sales_scenario_step` | int | 영업 시나리오 단계 (1-6) | +| `manager_scenario_step` | int | 매니저 시나리오 단계 (1-6) | +| `status` | enum | 영업 상태 | +| `hq_status` | enum | 본사 진행상태 | +| `first_contact_at` | timestamp | 최초 접촉일 | +| `contracted_at` | timestamp | 계약 체결일 | +| `onboarding_completed_at` | timestamp | 온보딩 완료일 | +| `membership_fee` | decimal | 가입비 | +| `membership_paid_at` | timestamp | 가입비 입금일 | +| `membership_status` | enum | pending / partial / paid / refunded | +| `sales_commission` | decimal | 영업 수당 | +| `manager_commission` | decimal | 관리 수당 | +| `commission_paid_at` | timestamp | 수당 지급일 | +| `sales_progress` | tinyint | 영업 진행률 (%) | +| `manager_progress` | tinyint | 매니저 진행률 (%) | +| `incentive_status` | enum | pending / eligible / paid | +| `notes` | text | 메모 | + +#### 영업 상태 흐름 + +``` +prospect (잠재) → approach (접근) → negotiation (협상) + → contracted (계약) → onboarding (온보딩) → active (활성) / churned (이탈) +``` + +#### 수당 상태 + +``` +pending (대기) → eligible (지급대상) → paid (지급완료) +``` + +## 뷰 구성 + +### index.blade.php + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "고객 관리" +│ [새로고침] 버튼 +│ +├─ 통계 카드 ──────────────────────── +│ 전체 | 활성 | 완료 | 인계완료 +│ +├─ 필터 영역 ──────────────────────── +│ 검색 (회사명, 사업자번호, 대표자, 연락처) +│ 상태: active / expired / converted / progress_complete +│ 인계: hq_status = 'handover' +│ 영업파트너: registered_by 필터 +│ +├─ 고객 목록 테이블 ──────────────── +│ 회사명 | 사업자번호 | 대표자 | 영업파트너 +│ 영업진행률 | 매니저진행률 | 본사상태 | 작업 +│ └─ 본사상태: 8단계 프로그레스바 +│ └─ 작업: 상세, 상태변경, 삭제 +│ +└─ 상세 모달 ─────────────────────── + 기본 정보 (회사명, 사업자번호, 대표자, 연락처) + 영업 진행률 (영업 시나리오, 매니저 시나리오) + 본사 진행상태 (8단계 프로그레스바 + 변경 드롭다운) + 수당 정보 (납입일, 지급일, 자동 계산) + 담당 매니저 정보 +``` + +## HTMX 호환성 + +- Blade + HTMX 기반으로 **HX-Redirect 불필요** +- `hx-get`으로 부분 새로고침 +- 모달로 상세 조회 및 상태 변경 diff --git a/features/sales/interviews.md b/features/sales/interviews.md new file mode 100644 index 0000000..1de6b10 --- /dev/null +++ b/features/sales/interviews.md @@ -0,0 +1,281 @@ +# 인터뷰 시나리오 + +## 개요 + +인터뷰 시나리오는 영업 상담 시 사용할 질문 템플릿을 관리하고, +인터뷰 세션을 진행/기록하는 기능입니다. +카테고리별 질문 구조, 체크리스트/텍스트 답변, MD 일괄 가져오기를 지원합니다. + +- **라우트**: `GET /sales/interviews` +- **미들웨어**: `auth`, `hq.member` +- **UI 기술**: Blade + React/JavaScript (API 기반, 1,076줄) + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── InterviewScenarioController.php # 메인 컨트롤러 (16개 메서드) +├── app/Services/Sales/ +│ └── InterviewScenarioService.php # 비즈니스 로직 서비스 +├── app/Models/Interview/ +│ ├── InterviewCategory.php # 카테고리 +│ ├── InterviewTemplate.php # 템플릿 (항목) +│ ├── InterviewQuestion.php # 질문 +│ ├── InterviewSession.php # 인터뷰 세션 +│ └── InterviewAnswer.php # 답변 +└── resources/views/sales/interviews/ + └── index.blade.php # 메인 페이지 (1,076줄) + +api/ +└── database/migrations/ + ├── 2026_02_06_100000_create_interview_categories_table.php + ├── 2026_02_06_100001_create_interview_templates_table.php + ├── 2026_02_06_100002_create_interview_questions_table.php + ├── 2026_02_06_100003_create_interview_sessions_table.php + └── 2026_02_06_100004_create_interview_answers_table.php +``` + +## 라우트 + +```php +// routes/web.php (sales/interviews prefix 그룹 내) + +// 페이지 +GET /interviews → index() 메인 페이지 + +// 카테고리 API +GET /interviews/api/categories → categories() 카테고리 목록 +POST /interviews/api/categories → storeCategory() 카테고리 생성 +PUT /interviews/api/categories/{id} → updateCategory() 카테고리 수정 +DELETE /interviews/api/categories/{id} → destroyCategory() 카테고리 삭제 + +// 트리 API +GET /interviews/api/tree → tree() 전체 계층 구조 + +// 템플릿(항목) API +POST /interviews/api/templates → storeTemplate() 템플릿 생성 +PUT /interviews/api/templates/{id} → updateTemplate() 템플릿 수정 +DELETE /interviews/api/templates/{id} → destroyTemplate() 템플릿 삭제 + +// 질문 API +POST /interviews/api/questions → storeQuestion() 질문 생성 +PUT /interviews/api/questions/{id} → updateQuestion() 질문 수정 +DELETE /interviews/api/questions/{id} → destroyQuestion() 질문 삭제 + +// 일괄 가져오기 +POST /interviews/api/bulk-import → bulkImport() MD 파일에서 가져오기 + +// 세션(인터뷰) API +GET /interviews/api/sessions → sessions() 세션 목록 (필터) +POST /interviews/api/sessions → storeSession() 인터뷰 시작 +GET /interviews/api/sessions/{id} → showSession() 세션 상세 +POST /interviews/api/sessions/toggle-answer → toggleAnswer() 답변 토글 +POST /interviews/api/sessions/{id}/complete → completeSession() 인터뷰 완료 +``` + +## 컨트롤러 + +### InterviewScenarioController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 메인 페이지 | +| `categories()` | GET | 카테고리 목록 | +| `storeCategory()` | POST | 카테고리 생성 | +| `updateCategory()` | PUT | 카테고리 수정 | +| `destroyCategory()` | DELETE | 카테고리 삭제 | +| `tree()` | GET | 전체 계층 구조 (카테고리→템플릿→질문) | +| `storeTemplate()` | POST | 템플릿 생성 | +| `updateTemplate()` | PUT | 템플릿 수정 | +| `destroyTemplate()` | DELETE | 템플릿 삭제 | +| `storeQuestion()` | POST | 질문 생성 | +| `updateQuestion()` | PUT | 질문 수정 | +| `destroyQuestion()` | DELETE | 질문 삭제 | +| `bulkImport()` | POST | MD 파일에서 일괄 가져오기 | +| `sessions()` | GET | 인터뷰 세션 목록 | +| `storeSession()` | POST | 인터뷰 시작 | +| `showSession()` | GET | 세션 상세 | +| `toggleAnswer()` | POST | 답변 토글/기록 | +| `completeSession()` | POST | 인터뷰 완료 | + +### InterviewScenarioService + +| 메서드 | 설명 | +|--------|------| +| `getCategories()` | 카테고리 목록 | +| `createCategory()` | 카테고리 생성 | +| `updateCategory()` | 카테고리 수정 | +| `deleteCategory()` | 카테고리 삭제 | +| `getTree()` | 전체 계층 구조 조회 | +| `createTemplate()` | 템플릿 생성 | +| `updateTemplate()` | 템플릿 수정 | +| `deleteTemplate()` | 템플릿 삭제 | +| `createQuestion()` | 질문 생성 | +| `updateQuestion()` | 질문 수정 | +| `deleteQuestion()` | 질문 삭제 | +| `bulkImport()` | MD에서 일괄 가져오기 | +| `getSessions()` | 세션 목록 (필터) | +| `startSession()` | 인터뷰 시작 | +| `getSessionDetail()` | 세션 상세 | +| `toggleAnswer()` | 답변 토글 | +| `completeSession()` | 인터뷰 완료 | + +## 모델 + +### 데이터 계층 구조 + +``` +InterviewCategory (카테고리) + └── InterviewTemplate (템플릿/항목) + └── InterviewQuestion (질문) + +InterviewSession (인터뷰 세션) + └── InterviewAnswer (답변) +``` + +### InterviewCategory + +**테이블**: `interview_categories` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `name` | string | 카테고리명 (예: 제조-방화셔터) | +| `description` | text | 설명 | +| `sort_order` | int | 정렬 순서 | +| `is_active` | boolean | 활성 여부 | +| `created_by` | bigint | 등록자 | + +- SoftDeletes 적용 +- 관계: `templates()`, `sessions()` + +### InterviewTemplate + +**테이블**: `interview_templates` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `interview_category_id` | bigint (FK) | 카테고리 ID | +| `name` | string | 항목명 (예: 견적서 제작) | +| `description` | text | 설명 | +| `sort_order` | int | 정렬 순서 | +| `is_active` | boolean | 활성 여부 | + +- SoftDeletes 적용 +- 관계: `category()`, `questions()` + +### InterviewQuestion + +**테이블**: `interview_questions` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `interview_template_id` | bigint (FK) | 템플릿 ID | +| `question_text` | string(500) | 질문 텍스트 | +| `question_type` | string | **checkbox** / **text** | +| `options` | json | 선택지 (배열) | +| `is_required` | boolean | 필수 여부 | +| `sort_order` | int | 정렬 순서 | +| `is_active` | boolean | 활성 여부 | + +- SoftDeletes 적용 +- 관계: `template()` + +#### 질문 타입 + +| 타입 | 설명 | 답변 방식 | +|------|------|----------| +| `checkbox` | 체크 질문 | is_checked 토글 | +| `text` | 서술형 질문 | answer_text 입력 | + +### InterviewSession + +**테이블**: `interview_sessions` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `interview_category_id` | bigint (FK) | 사용한 카테고리 ID | +| `interviewer_id` | bigint (FK) | 면담자(매니저) ID | +| `interviewee_name` | string(100) | 면담 상대 이름 | +| `interviewee_company` | string(200) | 면담 상대 회사 | +| `interview_date` | date | 면담 일자 | +| `status` | string | **in_progress** / **completed** | +| `total_questions` | int | 총 질문 수 | +| `answered_questions` | int | 답변 완료 수 | +| `memo` | text | 메모 | +| `completed_at` | timestamp | 완료 일시 | + +- SoftDeletes 적용 +- 관계: `category()`, `interviewer()`, `answers()` + +### InterviewAnswer + +**테이블**: `interview_answers` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `interview_session_id` | bigint (FK) | 세션 ID | +| `interview_question_id` | bigint (FK) | 질문 ID | +| `interview_template_id` | bigint (FK) | 템플릿 ID | +| `is_checked` | boolean | 체크 여부 (checkbox 유형) | +| `answer_text` | text | 답변 텍스트 (text 유형) | +| `memo` | text | 메모 | + +### 인터뷰 진행 흐름 + +``` +1. 카테고리 선택 + 면담 상대 정보 입력 + → storeSession() → 세션 생성 (status: in_progress) + → 해당 카테고리의 모든 질문에 대해 빈 Answer 생성 + +2. 질문별 답변 기록 + → toggleAnswer() → is_checked 토글 / answer_text 저장 + → answered_questions 카운트 갱신 + +3. 인터뷰 완료 + → completeSession() → status: completed, completed_at 기록 +``` + +## 뷰 구성 + +### index.blade.php + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "인터뷰 시나리오" +│ [카테고리 추가] [일괄 가져오기] 버튼 +│ +├─ 좌측 사이드바 ─────────────────── +│ 카테고리 트리 +│ ├── 카테고리 A +│ │ ├── 템플릿 1 (질문 3개) +│ │ └── 템플릿 2 (질문 5개) +│ └── 카테고리 B +│ └── 템플릿 3 (질문 2개) +│ +├─ 우측 메인 영역 ────────────────── +│ ├─ 템플릿 편집 모드 +│ │ 질문 목록 + 추가/수정/삭제 +│ │ 질문 타입(checkbox/text) + 옵션 +│ │ +│ └─ 인터뷰 세션 모드 +│ 면담 상대 정보 + 날짜 +│ 질문별 체크/답변 기록 +│ 진행률 표시 +│ [완료] 버튼 +│ +└─ 세션 목록 ─────────────────────── + 과거 인터뷰 기록 (필터: 카테고리, 날짜) + 면담자 | 상대방 | 회사 | 날짜 | 완료율 | 상태 +``` + +## HTMX 호환성 + +- JavaScript/React 기반 페이지이므로 **HX-Redirect 필요** +- API 호출로 동적 CRUD 관리 +- `@push('scripts')` 블록에 스크립트 포함 diff --git a/features/sales/partner-approvals.md b/features/sales/partner-approvals.md new file mode 100644 index 0000000..ae4fb60 --- /dev/null +++ b/features/sales/partner-approvals.md @@ -0,0 +1,102 @@ +# 영업파트너승인 + +## 개요 + +영업파트너승인은 신규 영업파트너 등록 신청을 검토하고 승인/반려를 처리하는 기능입니다. +본사 관리자 전용 페이지로, 신청자의 정보와 서류를 확인하고 일괄 처리할 수 있습니다. + +- **라우트**: `GET /sales/managers/approvals` +- **미들웨어**: `auth`, `hq.member` + 관리자 권한 체크 +- **UI 기술**: Blade + HTMX + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── SalesManagerController.php # 파트너관리와 동일 컨트롤러 (승인 메서드 포함) +├── app/Services/Sales/ +│ └── SalesManagerService.php # approve(), reject() 로직 +└── resources/views/sales/managers/ + └── approvals.blade.php # 승인 관리 페이지 +``` + +## 라우트 + +```php +// routes/web.php (sales prefix 그룹 내, resource 전에 정의) +GET /managers/approvals → approvals() 승인 목록 페이지 +POST /managers/approvals/{id}/approve → approveFromList() 목록에서 승인 +POST /managers/approvals/{id}/reject → rejectFromList() 목록에서 반려 +``` + +## 컨트롤러 + +### SalesManagerController (승인 관련 메서드) + +| 메서드 | HTTP | 설명 | 권한 | +|--------|------|------|------| +| `approvals()` | GET | 승인 대기 목록 페이지 | 관리자 전용 | +| `approveFromList()` | POST | 목록에서 승인 처리 | 관리자 전용 | +| `rejectFromList()` | POST | 목록에서 반려 처리 | 관리자 전용 | +| `approve()` | POST | 상세에서 승인 | - | +| `reject()` | POST | 상세에서 반려 | - | + +### 승인 처리 흐름 + +``` +영업파트너 등록 신청 (store) + ↓ +approval_status = 'pending' (Users 테이블) + ↓ +관리자 승인 목록에서 확인 + ├── approveFromList() → status = 'approved' + │ ├── approved_at 기록 + │ └── approved_by 기록 + │ + └── rejectFromList() → status = 'rejected' + └── rejection_reason 저장 (필수) +``` + +### 응답 방식 + +``` +HTMX 요청 → JsonResponse (success, message) +일반 요청 → Redirect (redirect back) +``` + +## 뷰 구성 + +### approvals.blade.php + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "영업파트너 승인관리" +│ +├─ 통계 카드 ──────────────────────── +│ 승인 대기 | 오늘 승인 | 오늘 반려 +│ +├─ 검색/필터 영역 ────────────────── +│ 검색 (이름, 아이디, 이메일, 전화번호) +│ +├─ 2분할 레이아웃 ────────────────── +│ ┌─ 좌: 승인 대기 ────────────┐ ┌─ 우: 승인 완료 ─────────────┐ +│ │ 신청자명 | 역할 | 유치자 │ │ 파트너명 | 승인일 | 승인자 │ +│ │ └─ [승인] [반려] 버튼 │ │ │ +│ └────────────────────────────┘ └─────────────────────────────┘ +│ +└─ 상세 모달 ─────────────────────── + 파트너 정보 (이름, 아이디, 이메일, 전화) + 계층 정보 (레벨, 추천인) + 등록 서류 목록 (다운로드/삭제) + [승인] [반려] 버튼 +``` + +## 반려 처리 + +``` +반려 시: + - rejection_reason (반려 사유) 필수 입력 + - 상태: pending → rejected + - 반려 후 재신청 가능 +``` diff --git a/features/sales/partners.md b/features/sales/partners.md new file mode 100644 index 0000000..53fd5d7 --- /dev/null +++ b/features/sales/partners.md @@ -0,0 +1,166 @@ +# 파트너관리 + +## 개요 + +파트너관리는 영업파트너(판매자/매니저)의 등록, 수정, 역할 관리, 서류 관리를 수행하는 기능입니다. +파트너 등록 신청, 서류 업로드, 역할 부여/위임, 계층 구조(추천인) 관리를 지원합니다. + +- **라우트**: `GET /sales/managers` +- **미들웨어**: `auth`, `hq.member` +- **UI 기술**: Blade + HTMX + Alpine.js + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── SalesManagerController.php # 메인 컨트롤러 (425줄) +├── app/Services/Sales/ +│ └── SalesManagerService.php # 비즈니스 로직 서비스 +├── app/Models/Sales/ +│ ├── SalesPartner.php # 영업파트너 모델 +│ └── SalesManagerDocument.php # 파트너 서류 모델 +└── resources/views/sales/managers/ + ├── index.blade.php # 파트너 목록 + ├── create.blade.php # 등록 폼 + ├── show.blade.php # 상세 페이지 + ├── edit.blade.php # 수정 폼 + └── partials/ + ├── show-modal.blade.php # 상세 모달 + └── edit-modal.blade.php # 수정 모달 + +api/ +└── database/migrations/ + └── 2026_01_29_100000_create_sales_partners_table.php +``` + +## 라우트 + +```php +// routes/web.php (sales prefix 그룹 내) + +// Resource 라우트 +GET /managers → index() 파트너 목록 +GET /managers/create → create() 등록 폼 +POST /managers → store() 등록 처리 +GET /managers/{id} → show() 상세 페이지 +GET /managers/{id}/edit → edit() 수정 폼 +PUT /managers/{id} → update() 수정 처리 +DELETE /managers/{id} → destroy() 비활성화 (관리자) + +// 추가 라우트 +GET /managers/{id}/modal-show → modalShow() 상세 모달 +GET /managers/{id}/modal-edit → modalEdit() 수정 모달 +POST /managers/{id}/approve → approve() 승인 +POST /managers/{id}/reject → reject() 반려 +POST /managers/{id}/delegate-role → delegateRole() 역할 위임 +POST /managers/{id}/assign-role → assignRole() 역할 부여 +POST /managers/{id}/remove-role → removeRole() 역할 제거 +GET /managers/{id}/documents/{docId}/download → downloadDocument() 서류 다운로드 +DELETE /managers/{id}/documents/{docId} → deleteDocument() 서류 삭제 +``` + +## 컨트롤러 + +### SalesManagerController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 파트너 목록 (현재 사용자 유치분) | +| `create()` | GET | 등록 폼 | +| `store()` | POST | 파트너 등록 (서류 업로드 포함) | +| `show()` | GET | 상세 페이지 | +| `edit()` | GET | 수정 폼 | +| `update()` | PUT | 정보 수정 | +| `destroy()` | DELETE | 비활성화 (관리자 전용) | +| `modalShow()` | GET | 상세 모달 (HTMX) | +| `modalEdit()` | GET | 수정 모달 (HTMX) | +| `delegateRole()` | POST | 상담매니저 역할 위임 | +| `assignRole()` | POST | 역할 부여 (sales/manager) | +| `removeRole()` | POST | 역할 제거 | +| `downloadDocument()` | GET | 서류 파일 다운로드 | +| `deleteDocument()` | DELETE | 서류 파일 삭제 | + +### SalesManagerService + +| 메서드 | 설명 | +|--------|------| +| `getSalesPartners()` | 필터 적용 파트너 목록 조회 | +| `getStats()` | 파트너 통계 계산 | +| `getApprovalStats()` | 승인 관련 통계 | +| `createSalesPartner()` | 파트너 생성 | +| `updateSalesPartner()` | 파트너 수정 | +| `approve()` | 승인 처리 | +| `reject()` | 반려 처리 | + +## 모델 + +### SalesPartner + +**테이블**: `sales_partners` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `user_id` | bigint (FK) | 연결된 사용자 ID | +| `partner_code` | string | 파트너 고유 코드 (SP + 연도 + 순번) | +| `partner_type` | string | individual(개인) / corporate(법인) | +| `commission_rate` | decimal(5,2) | 기본 수수료율 | +| `manager_commission_rate` | decimal(5,2) | 관리자 수수료율 | +| `bank_name` | string | 은행명 | +| `account_number` | string | 계좌번호 | +| `account_holder` | string | 예금주 | +| `status` | string | pending / active / inactive / suspended | +| `approved_at` | timestamp | 승인 일시 | +| `approved_by` | bigint (FK) | 승인자 ID | +| `total_contracts` | int | 총 계약 건수 (캐시) | +| `total_commission` | decimal | 총 수당 (캐시) | + +- SoftDeletes 적용 + +### SalesManagerDocument + +**테이블**: `sales_manager_documents` + +- 파트너 등록 시 필수 서류 관리 (신분증, 통장사본 등) +- `DOCUMENT_TYPES` 상수로 서류 타입 정의 + +### 파트너 계층 구조 + +``` +User 모델의 parent_id를 통한 다단계 구조: + +추천인 (parent) + └── 영업파트너 (children) + └── 하위 파트너 (children) +``` + +## 뷰 구성 + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "파트너관리" +│ [등록] 버튼 +│ +├─ 통계 카드 ──────────────────────── +│ 전체 | 활성 | 대기중 | 비활성 +│ +├─ 필터 영역 ──────────────────────── +│ 검색 (이름, 아이디) | 상태 필터 | 타입 필터 +│ +├─ 파트너 목록 테이블 ─────────────── +│ 이름 | 파트너코드 | 타입 | 수수료율 | 계약수 | 상태 | 작업 +│ └─ 작업: 상세, 수정, 역할관리, 승인/반려 +│ +├─ 등록 폼 ───────────────────────── +│ 사용자 정보, 파트너 타입, 수수료율 +│ 계좌 정보, 서류 업로드 +│ +└─ 상세/수정 모달 ────────────────── + 파트너 정보, 계층, 서류 목록, 역할 관리 +``` + +## HTMX 호환성 + +- Blade + HTMX 기반으로 **HX-Redirect 불필요** +- 모달로 상세/수정 처리 +- HTMX 또는 JavaScript AJAX 호출 diff --git a/features/sales/products.md b/features/sales/products.md new file mode 100644 index 0000000..a51de0e --- /dev/null +++ b/features/sales/products.md @@ -0,0 +1,175 @@ +# 상품관리 + +## 개요 + +상품관리는 영업에 사용되는 상품(프로그램)을 카테고리별로 등록하고 가격/수당률을 설정하는 기능입니다. +카테고리 관리, 상품 CRUD, 순서 조정, 가격/수당률 설정, 영업 시나리오 연동을 지원합니다. + +- **라우트**: `GET /sales/products` +- **미들웨어**: `auth`, `hq.member` (본사 전용) +- **UI 기술**: Blade + Alpine.js + HTMX + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── SalesProductController.php # 메인 컨트롤러 (12개 메서드) +├── app/Models/Sales/ +│ ├── SalesProduct.php # 상품 모델 +│ └── SalesProductCategory.php # 카테고리 모델 +└── resources/views/sales/products/ + ├── index.blade.php # 메인 페이지 + └── partials/ + └── product-list.blade.php # 상품 목록 파셜 (HTMX) + +api/ +└── database/migrations/ + ├── 2026_01_29_150000_create_sales_products_tables.php + ├── 2026_01_29_161626_add_partner_manager_commission_to_sales_products_table.php + └── 2026_01_29_162847_add_registration_fee_to_sales_products_table.php +``` + +## 라우트 + +```php +// routes/web.php (sales/products prefix 그룹 내) + +// 상품 관리 +GET /products → index() 메인 페이지 +GET /products/list → productList() 카테고리별 상품 목록 (HTMX) +POST /products → store() 상품 등록 +PUT /products/{id} → update() 상품 수정 +DELETE /products/{id} → destroy() 상품 삭제 +POST /products/{id}/toggle → toggleActive() 활성화 토글 +POST /products/reorder → reorder() 순서 변경 + +// 카테고리 관리 +GET /products/categories → categories() 카테고리 목록 +POST /products/categories → storeCategory() 카테고리 생성 +PUT /products/categories/{id} → updateCategory() 카테고리 수정 +DELETE /products/categories/{id} → deleteCategory() 카테고리 삭제 + +// API (영업 시나리오용) +GET /products/api/list → getProductsApi() 활성 상품 목록 +``` + +## 컨트롤러 + +### SalesProductController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 메인 페이지 (HX-Redirect 처리) | +| `productList()` | GET | 카테고리별 상품 목록 (HTMX 파셜) | +| `store()` | POST | 상품 등록 (코드 중복 체크, 자동 순서) | +| `update()` | PUT | 상품 수정 (부분 업데이트 허용) | +| `destroy()` | DELETE | 상품 삭제 (Soft Delete) | +| `toggleActive()` | POST | 활성화/비활성화 토글 | +| `reorder()` | POST | 다중 상품 순서 변경 (배치) | +| `categories()` | GET | 활성 카테고리 목록 | +| `storeCategory()` | POST | 카테고리 생성 (코드 unique) | +| `updateCategory()` | PUT | 카테고리 수정 | +| `deleteCategory()` | DELETE | 카테고리 삭제 (하위 상품 있으면 실패) | +| `getProductsApi()` | GET | API: 활성 카테고리+상품 (영업 시나리오용) | + +## 모델 + +### SalesProductCategory + +**테이블**: `sales_product_categories` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `code` | string(50) | 카테고리 코드 (unique) | +| `name` | string(100) | 카테고리명 | +| `description` | text | 설명 | +| `base_storage` | string(20) | 기본 제공 용량 (기본: 100GB) | +| `display_order` | int | 표시 순서 | +| `is_active` | boolean | 활성화 | + +- SoftDeletes 적용 +- 관계: `products()`, `activeProducts()` +- Scope: `active()`, `ordered()` + +### SalesProduct + +**테이블**: `sales_products` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `category_id` | bigint (FK) | 카테고리 ID | +| `code` | string(50) | 상품 코드 (카테고리별 unique) | +| `name` | string(100) | 상품명 | +| `description` | text | 설명 (프로그램 타입) | +| `development_fee` | decimal(15,2) | 개발비 | +| `registration_fee` | decimal(15,2) | 가입비 (할인가) | +| `subscription_fee` | decimal(15,2) | 월 구독료 | +| `partner_commission_rate` | decimal(5,2) | 영업파트너 수당율 (기본 20%) | +| `manager_commission_rate` | decimal(5,2) | 매니저 수당율 (기본 5%) | +| `allow_flexible_pricing` | boolean | 재량권 허용 여부 | +| `is_required` | boolean | 필수 선택 여부 | +| `display_order` | int | 표시 순서 | +| `is_active` | boolean | 활성화 | + +- SoftDeletes 적용 +- Unique Key: `(category_id, code)` +- Scope: `active()`, `ordered()` +- Accessor: `total_commission_rate`, `commission`, `formatted_*_fee` + +### SalesContractProduct (계약별 선택 상품) + +**테이블**: `sales_contract_products` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint (FK, nullable) | 테넌트 ID | +| `management_id` | bigint (FK) | 영업관리 ID | +| `category_id` | bigint (FK) | 선택 카테고리 | +| `product_id` | bigint (FK) | 선택 상품 | +| `development_fee` | decimal(15,2) | 적용 개발비 | +| `registration_fee` | decimal(15,2) | 적용 가입비 | +| `subscription_fee` | decimal(15,2) | 적용 구독료 | +| `discount_rate` | decimal(5,2) | 할인율 (기본 0%) | +| `notes` | text | 비고 | +| `created_by` | bigint (FK) | 등록자 | + +## 뷰 구성 + +### index.blade.php + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "상품관리" +│ [카테고리 관리] 버튼 +│ +├─ 카테고리 탭 ────────────────────── +│ [카테고리A] [카테고리B] [카테고리C] ... +│ └─ 선택 시 HTMX로 상품 목록 갱신 +│ +├─ 상품 영역 ──────────────────────── +│ 헤더: 카테고리명 + 기본 용량 + [상품 추가] +│ +│ ┌─ 상품 카드 (그리드: 1/2/3열 반응형) ─┐ +│ │ 상품명 + 필수/비활성 배지 + 코드 │ +│ │ 프로그램 설명 │ +│ │ 개발비(취소선) + 가입비(할인가) │ +│ │ 월 구독료 │ +│ │ 수당: 파트너 20%, 매니저 5% │ +│ │ 재량권 허용/고정가 태그 + [삭제] │ +│ └───────────────────────────────────────┘ +│ +├─ 상품 등록/수정 모달 (Alpine.js) ── +│ 코드, 상품명, 설명 +│ 개발비, 가입비, 구독료 +│ 파트너 수당율, 매니저 수당율 +│ 재량권 허용, 필수 선택 +│ +└─ 카테고리 관리 모달 ────────────── + 코드, 카테고리명, 설명, 기본 용량 +``` + +## HTMX 호환성 + +- Alpine.js 스크립트가 `@push('scripts')`에 있어 **HX-Redirect 필요** +- 카테고리 탭 전환은 HTMX `hx-get`으로 부분 로드 diff --git a/features/sales/prospects.md b/features/sales/prospects.md new file mode 100644 index 0000000..80cd786 --- /dev/null +++ b/features/sales/prospects.md @@ -0,0 +1,189 @@ +# 영업파트너 고객관리 + +## 개요 + +영업파트너 고객관리는 영업파트너가 명함을 등록하여 영업권을 확보하고, +고객과의 계약 진행을 관리하는 기능입니다. +명함 등록, 영업권 유효기간(2개월), 사업자번호 중복 체크, 테넌트 전환을 지원합니다. + +- **라우트**: `GET /sales/prospects` +- **미들웨어**: `auth`, `hq.member` +- **UI 기술**: Blade + HTMX + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── TenantProspectController.php # 메인 컨트롤러 (12개 메서드) +├── app/Services/Sales/ +│ └── TenantProspectService.php # 비즈니스 로직 서비스 +├── app/Models/Sales/ +│ └── TenantProspect.php # 가망고객 모델 +└── resources/views/sales/prospects/ + ├── index.blade.php # 영업권 목록 + ├── create.blade.php # 명함 등록 폼 + ├── show.blade.php # 상세 페이지 + ├── edit.blade.php # 수정 폼 + └── partials/ + ├── show-modal.blade.php # 상세 모달 + └── edit-modal.blade.php # 수정 모달 + +api/ +└── database/migrations/ + ├── 2026_01_27_221000_create_tenant_prospects_table.php + └── 2026_01_28_090000_add_attachments_to_tenant_prospects_table.php +``` + +## 라우트 + +```php +// routes/web.php (sales prefix 그룹 내) + +// Resource 라우트 +GET /prospects → index() 영업권 목록 (본인 기준) +GET /prospects/create → create() 명함 등록 폼 +POST /prospects → store() 명함 등록 처리 +GET /prospects/{id} → show() 상세 페이지 +GET /prospects/{id}/edit → edit() 수정 폼 +PUT /prospects/{id} → update() 수정 처리 +DELETE /prospects/{id} → destroy() 삭제 (관리자) + +// 추가 라우트 +POST /prospects/{id}/convert → convert() 테넌트 전환 +POST /prospects/check-business-number → checkBusinessNumber() 사업자번호 중복 체크 +DELETE /prospects/{id}/attachment → deleteAttachment() 첨부파일 삭제 +GET /prospects/{id}/modal-show → modalShow() 상세 모달 +GET /prospects/{id}/modal-edit → modalEdit() 수정 모달 +``` + +## 컨트롤러 + +### TenantProspectController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 영업권 목록 (현재 사용자 기준) | +| `create()` | GET | 명함 등록 폼 | +| `store()` | POST | 명함 등록 (등록자 = 현재 사용자) | +| `show()` | GET | 상세 페이지 | +| `edit()` | GET | 수정 폼 | +| `update()` | PUT | 정보 수정 | +| `destroy()` | DELETE | 삭제 (관리자 전용) | +| `convert()` | POST | 영업권 → 테넌트 전환 | +| `checkBusinessNumber()` | POST | 사업자번호 중복 체크 (AJAX) | +| `modalShow()` | GET | 상세 모달 | +| `modalEdit()` | GET | 수정 모달 | +| `deleteAttachment()` | DELETE | 첨부 이미지 삭제 | + +### TenantProspectService + +| 메서드 | 설명 | +|--------|------| +| `register()` | 명함 등록 (영업권 확보), expires_at = 등록일 + 2개월 | +| `update()` | 정보 수정 + 파일 업로드 (명함/신분증/통장) | +| `convertToTenant()` | 영업권 → 테넌트 전환 (Tenant + user_tenants 생성) | +| `expireOldProspects()` | 만료 영업권 자동 처리 (배치) | +| `canRegister()` | 사업자번호 등록 가능 여부 확인 | +| `getProspects()` | 목록 조회 (검색, 상태, 파트너 필터) | +| `getStats()` | 통계 (total, active, expired, converted) | +| `uploadAttachment()` | 파일 업로드 (tenant disk) | +| `deleteAttachment()` | 파일 삭제 | + +## 모델 + +### TenantProspect + +**테이블**: `tenant_prospects` + +| 필드 | 타입 | 설명 | +|------|------|------| +| `business_number` | string(20) | 사업자번호 (중복 체크 키) | +| `company_name` | string(100) | 회사명 | +| `ceo_name` | string(50) | 대표자명 | +| `contact_phone` | string(20) | 연락처 | +| `contact_email` | string(100) | 이메일 | +| `address` | string(500) | 주소 | +| `registered_by` | bigint (FK) | 등록한 영업파트너 ID | +| `business_card_path` | string(500) | 명함 이미지 경로 | +| `id_card_path` | string(500) | 신분증 이미지 경로 | +| `bankbook_path` | string(500) | 통장 이미지 경로 | +| `status` | string(20) | active / expired / converted / completed | +| `registered_at` | timestamp | 등록일 | +| `expires_at` | timestamp | 만료일 (등록일 + 2개월) | +| `cooldown_ends_at` | timestamp | 재등록 가능일 (만료일 + 1개월) | +| `tenant_id` | bigint (FK, nullable) | 전환된 테넌트 ID | +| `converted_at` | timestamp | 전환일 | +| `converted_by` | bigint (FK) | 전환 처리자 ID | +| `memo` | text | 메모 | + +- SoftDeletes 적용 + +#### 상태 흐름 + +``` +명함 등록 → active (영업권 유효, 2개월) + │ + ├── convert() → converted (테넌트 전환 완료) + │ └→ completed (영업 완료) + │ + └── (2개월 경과) → expired (만료) + └→ (1개월 쿨다운 후 재등록 가능) +``` + +#### 영업권 규칙 + +| 규칙 | 설명 | +|------|------| +| 유효기간 | 등록일로부터 2개월 | +| 쿨다운 | 만료 후 1개월간 재등록 불가 | +| 중복 체크 | 동일 사업자번호 중복 등록 방지 | +| 전환 | 영업권 → Tenant + user_tenants 자동 생성 | + +#### 주요 속성/메서드 + +| 메서드 | 설명 | +|--------|------| +| `isActive()` | 영업권 유효 여부 | +| `isExpired()` | 만료 여부 | +| `isConverted()` | 테넌트 전환 완료 여부 | +| `canReRegister()` | 재등록 가능 여부 | +| `getStatusLabelAttribute()` | 상태 라벨 (영업중/완료/계약완료/대기중/만료) | +| `getStatusColorAttribute()` | Tailwind CSS 색상 | +| `getRemainingDaysAttribute()` | 남은 일수 | + +## 뷰 구성 + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "고객관리 (영업권)" +│ [명함 등록] 버튼 +│ +├─ 통계 카드 ──────────────────────── +│ 전체 | 영업중 | 만료 | 전환완료 +│ +├─ 필터 영역 ──────────────────────── +│ 검색 (회사명, 사업자번호) | 상태 필터 +│ +├─ 영업권 목록 테이블 ────────────── +│ 회사명 | 사업자번호 | 대표자 | 연락처 | 상태 | 남은일수 | 작업 +│ └─ 상태: 영업중(초록), 만료(빨강), 전환(파랑), 완료(회색) 배지 +│ └─ 작업: 상세, 수정, 전환, 삭제 +│ +├─ 등록 폼 ───────────────────────── +│ 사업자번호 (중복 체크), 회사명, 대표자명 +│ 연락처, 이메일, 주소 +│ 명함 이미지 업로드 +│ 신분증, 통장사본 (선택) +│ +└─ 상세 모달 ─────────────────────── + 회사 정보 + 첨부파일 미리보기 + 영업권 상태 + 남은 기간 + [테넌트 전환] 버튼 +``` + +## HTMX 호환성 + +- Blade + HTMX 기반으로 **HX-Redirect 불필요** +- 사업자번호 중복 체크: AJAX 실시간 검증 +- 모달로 상세/수정 처리 diff --git a/features/sales/sales-dashboard.md b/features/sales/sales-dashboard.md new file mode 100644 index 0000000..557764c --- /dev/null +++ b/features/sales/sales-dashboard.md @@ -0,0 +1,122 @@ +# 영업관리 대시보드 + +## 개요 + +영업관리 대시보드는 영업파트너/상담매니저의 수당 현황, 테넌트 진행률, 유치 파트너 활동을 종합적으로 보여주는 페이지입니다. +로그인한 사용자 기준의 실적 및 수당 정보를 실시간으로 제공합니다. + +- **라우트**: `GET /sales/salesmanagement/dashboard` +- **미들웨어**: `auth`, `hq.member` +- **UI 기술**: Blade + HTMX + Alpine.js + Tailwind CSS + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Sales/ +│ └── SalesDashboardController.php # 메인 컨트롤러 (18개 메서드, 1,073줄) +└── resources/views/sales/dashboard/ + ├── index.blade.php # 메인 페이지 + └── partials/ + ├── data-container.blade.php # HTMX 새로고침 컨테이너 + ├── stats.blade.php # 통계 카드 + ├── commission-by-role.blade.php # 역할별 수당 + ├── tenant-list.blade.php # 테넌트 목록 + ├── tenant-stats.blade.php # 테넌트 통계 + ├── partner-activity.blade.php # 유치 파트너 활동 + ├── my-commission.blade.php # 내 수당 정보 + ├── help-modal.blade.php # 도움말 + └── prospect-row.blade.php # 가망고객 행 +``` + +## 라우트 + +```php +// routes/web.php (sales prefix 그룹 내) +GET /salesmanagement/dashboard → index() 메인 페이지 +GET /salesmanagement/dashboard/refresh → refresh() HTMX 부분 새로고침 +GET /salesmanagement/dashboard/tenants → refreshTenantList() 테넌트 목록 갱신 +GET /salesmanagement/dashboard/partner-activity → partnerActivity() 유치 파트너 활동 +GET /salesmanagement/dashboard/help → helpGuide() 도움말 모달 +GET /salesmanagement/dashboard/prospect/{id}/row → getProspectRow() 가망고객 행 +GET /managers/list → getManagers() 매니저 목록 +GET /managers/search → searchManagers() 매니저 검색 +POST /tenants/{tenant}/assign-manager → assignManager() 매니저 지정 +POST /prospects/{prospect}/assign-manager → assignProspectManager() 가망고객 매니저 지정 +``` + +## 컨트롤러 + +### SalesDashboardController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 대시보드 메인 화면 | +| `refresh()` | GET | HTMX 부분 새로고침 | +| `getDashboardData()` | - | 대시보드 핵심 데이터 조회 (private) | +| `refreshTenantList()` | GET | 테넌트 목록 새로고침 | +| `getManagers()` | GET | 매니저 드롭다운 목록 | +| `searchManagers()` | GET | 매니저 검색 API | +| `partnerActivity()` | GET | 유치 파트너 활동 현황 | +| `getPartnerActivityData()` | - | 파트너 활동 데이터 (private) | +| `calculatePartnerSummaryStats()` | - | 파트너 요약 통계 (private) | +| `getPartnerActivitiesDetail()` | - | 파트너별 상세 활동 (private) | +| `getManagerOnlyProspects()` | - | 매니저 전용 가망고객 (private) | +| `getCommissionData()` | - | 수당 정보 조회 (private) | +| `getAllManagerUsers()` | - | 상담매니저 사용자 목록 (private) | +| `helpGuide()` | GET | 도움말 모달 | +| `getProspectRow()` | GET | 가망고객 개별 행 | +| `assignManager()` | POST | 테넌트 매니저 변경 | +| `assignProspectManager()` | POST | 가망고객 매니저 변경 | +| `calculateExpectedCommissionSummary()` | - | 예상 수당 계산 (private) | + +### 수당 계산 로직 + +``` +영업파트너 수당: + - 판매자 수당: 가입비 × 20% + - 협업지원금: 개발비 × 10% (인계 완료 시) + - 1차/2차 분할: 각 50% + +매니저 수당: + - 1개월 구독료 (매니저 기본 수당) + - 1차/2차 분할: 각 50% +``` + +## 뷰 구성 + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "영업관리" +│ [새로고침] 버튼 +│ +├─ 탭 전환 (Alpine.js) ───────────── +│ [내 활동] | [유치 파트너 현황] +│ +├─ 탭1: 내 활동 ───────────────────── +│ ├─ 통계 카드 (수당 요약) +│ │ 총 수당 | 지급완료 | 미지급 | 예상 수당 +│ │ +│ ├─ 역할별 수당 상세 +│ │ 영업파트너 수당 | 매니저 수당 +│ │ +│ └─ 테넌트/가망고객 목록 +│ 회사명 | 상태 | 진행률 | 수당 | 매니저 | 작업 +│ └─ 매니저 지정 변경 (드롭다운) +│ +├─ 탭2: 유치 파트너 현황 ──────────── +│ ├─ 파트너 요약 통계 +│ │ 총 파트너 | 활성 | 계약건수 | 총 수당 +│ │ +│ └─ 파트너별 활동 상세 +│ 파트너명 | 등록 고객 | 계약 | 진행중 | 수당 +│ +└─ 도움말 모달 ────────────────────── + 수당 계산 방식, 진행 단계 설명 +``` + +## HTMX 호환성 + +- Blade + HTMX 기반으로 **HX-Redirect 불필요** +- `hx-get`으로 부분 새로고침 처리 +- Alpine.js 탭 전환