# erp_module — 추모·상조 업체 ERP (테넌트 본체)

> **한 줄**: 모리 구독 고객사(상조회사 등) 가 직접 사용하는 ERP. 회사마다 1개 인스턴스.
> **누가 쓰나**: 모리 구독한 상조회사 직원 (장지 분양·계약·고객 관리).
> **도메인**: `{site_domain}.mo-ree.com` (신규) 또는 `{site_domain}.acux.store` (레거시)
> **이 디렉토리(`/home/erp_module/www`)는 템플릿 원본** — tenant_provisioner 가 신규 인스턴스 생성 시 복제

---

## 4개 프로젝트 관계도

```
[모리 본사]                           [구독 고객사 ↓]
moree-user        ─결제·옵션─→     erp_module 인스턴스 (각 회사마다)
moree-admin       ─Pro 승인─→         실제 위치: /home/_tenants/{site}/www
                                       │
                                       │ 계약·결제 데이터를 internal HMAC API 로
                                       │ moree-mh 가 가져감 (mirror)
                                       ↓
                                  moree-mh (mini.mo-ree.com)
                                  단일 인스턴스가 모든 ERP 의 유가족 서빙
                                  (spaces 테이블로 격리)
```

| 시스템 | DB | 운영 주체 |
|---|---|---|
| erp_module 인스턴스 (여기) | `erp_{site_domain}` (테넌트별 독립 DB) | 각 상조회사 |
| moree-user | `moree` | 모리 본사 |
| moree-admin | `moree` | 모리 본사 |
| moree-mh | `moree_memorial` (별도) | 미니홈피 운영자 (테넌트) |

---

## 디렉토리 위치 정책 ⚠

```
실제 인스턴스 위치 (신규/이전 가입자 공통):
  /home/_tenants/{site_domain}/www

레거시 호환 (.acux.store 가입자만):
  /home/{site_domain} → symlink → /home/_tenants/{site_domain}
  (Apache *.acux.store 와일드카드가 symlink 따라가 진입)
```

**이 디렉토리(`/home/erp_module/www`) 자체는 템플릿 원본**. `tenant_provisioner.php` 가 신규 가입자 사이트 만들 때 이걸 복제. 인스턴스에 영향 가는 변경은 신중히 (모든 신규 가입자에게 전파됨).

---

## ERP 주요 기능

| 영역 | 위치 |
|---|---|
| **분양 관리** — 장지(burial_units) CRUD, 판매율 | `admin/pages/burial/*`, `admin/api/burial/*` |
| **수목장 관리** — 위치 정보(위도·경도), 수목 종류 | `admin/pages/tree/*` |
| **계약 관리** — `burial_contracts`(계약자) + `burial_successors`(승계자) | `admin/pages/contract/*`, `admin/api/contract/*` |
| **결제 관리** — 관리비·일시금 청구·수금 (스마트로 PG) | `admin/api/payment/*` |
| **알림 발송** — admin/api/mms/send_atalk.php (운영자 수동 호출) | `admin/api/mms/*` |
| **대시보드** — 분양 현황, 관리비 도래, 계약 만료 | `admin/pages/dashboard.php` |
| **RBAC** — master / admin / field_manager 역할 | `role_menu_permissions` 테이블 |
| **moree-mh 연동 (계약 mirror, 문의 bridge)** | `api/inquiry/bridge.php`, internal HMAC |

---

## 모리 본사와의 연결점

| 연결 | 방향 | 메커니즘 |
|---|---|---|
| 사이트 자동 생성 | moree-user → erp_module 인스턴스 | `tenant_provisioner.php` 가 신규 DB·디렉토리·site_config 자동 구성 + `/home/_tenants/{site}` 에 생성 |
| 회사 정보 변경 | moree-user → 인스턴스 | `company_sync.php` 가 acuxmsg + erp 동시 sync |
| PG 설정 | moree-admin 에서 통합 관리 | `company_pg_configs` (모리 통합) |
| 알림톡·SMS 발송 | erp_module → acuxmsg | `site_config.mms_key` 로 발신 (acuxmsg api_key) |
| 미니홈피 연동 | moree-mh ← erp_module | moree-mh 가 `erp_sources.config_json.base_url` 로 HMAC POST 호출 |

---

## 알림톡 정책 ⚠

erp_module 은 **각 테넌트의 acuxmsg 키 (`site_config.mms_key`)** 로 발송:
- 발신: `admin/api/mms/send_atalk.php`
- 운영자가 admin 페이지에서 수동 호출 (자동 cron 없음)
- 사용 채널: acuxmsg 가 카카오 비즈센터 등록된 발송 대행사로서 처리
- 발신번호: `site_config.sender_number` (acuxmsg agent.sender_numbers 에 ACTIVE 등록되어야 함)

**모리(MOREE) 채널과는 완전 별개**:
- 모리 구독·결제 알림 (`@moree`, agent.companies id=11) = moree-user 측 발송
- erp_module 측 알림 (고객 안내·기일 알림 등) = 테넌트 자체 채널 (각 site_config.mms_key)

**손대면 안 되는 것**: 본 인스턴스의 `site_config.mms_key` 직접 변경 → acuxmsg 발신 인증 깨짐. 회전하려면 acuxmsg /internal/provision.php 재호출.

---

## 핵심 디렉토리

```
www/
├ admin/
│  ├ pages/                ERP 관리 페이지 (분양·계약·결제·메시지·대시보드)
│  │  └ mms/send.php       메시지 발송 UI (운영자 수동)
│  └ api/
│     ├ burial/            장지 CRUD
│     ├ contract/          계약 CRUD
│     ├ payment/           결제 API
│     └ mms/send_atalk.php ★ 알림톡 발송 API (acuxmsg 호출)
├ setting/                 가맹점 ERP 초기 설정 (provisioner 가 호출하지 않고 첫 master 로그인 후 진입)
├ setting2/                신규 설정 (renewal·ERP migrations)
├ api/                     외부 호출 (REST)
│  └ inquiry/bridge.php    ★ moree-mh 가 HMAC 으로 호출하는 entry
├ _common/
│  ├ db.php                테넌트 DB 접속 (db.local.php 의 erp_{site} 사용)
│  └ site_config.php       mms_key·sender_number 등 테넌트 설정
├ _sms_platform/           acuxmsg 연동 layer (PlatformApi)
└ schema_erp.sql           스키마
```

---

## 손대면 안 되는 것

| 영역 | 이유 |
|---|---|
| 다른 테넌트 DB (`erp_{다른 site}`) | 회사간 격리 위반 |
| moree-user / moree-admin 코드 | 별도 프로젝트 |
| `/home/acuxmsg/www/` 핵심 코드 | 다른 테넌트와 공용 |
| 본 인스턴스의 `site_config.mms_key` 직접 변경 | acuxmsg 발신 인증 깨짐 |
| `tenant_provisioner.php` (moree-user 측) | 사이트 자동 생성 흐름 — 손대면 신규 가입 실패 |
| `/home/erp_module/www` (템플릿 원본) | 신규 인스턴스 복제 원본. 영향 전파됨 |

---

## 빠른 시작 (신규 인스턴스 자동 생성)

```
1. moree-user 에서 회원가입 + 결제
   - Standard → 결제 즉시 인스턴스 생성
   - Pro      → DB 제출 → admin 승인 시점 생성

2. tenant_provisioner.php 가 자동 처리:
   - DB erp_{site_domain} 생성 (스키마 복제)
   - /home/_tenants/{site_domain}/www 디렉토리 복사
   - site_config 초기화 (mms_key='' 후 acuxmsg 발급 키로 UPDATE)
   - master 계정 시드 (companies.user_id / password_hash)
   - acuxmsg 회사 등록 + api_key 발급 → site_config.mms_key
   - moree-mh erp_sources INSERT (유가족이 본인 ERP 찾을 수 있도록)

3. 첫 master 로그인 → /admin 또는 /setting 진입 → 운영
```

---

## DB 패턴

각 테넌트는 **자체 MySQL DB** (`erp_{site_domain}`).
- 모리 통합 데이터는 `moree.*` / `moree_memorial.*` 에 있고 erp_module 은 그걸 직접 안 만짐
- 알림톡 발송 결과는 `agent.*` (acuxmsg) 에 저장됨 (erp 가 조회만 가능)

---

## 운영 세부사항

### 런타임 요구사항
- PHP 7.4+ (PSR-12 코딩 표준)
- MySQL — 테넌트별 `erp_{site_domain}` DB

### 보안 정책
- SQL Injection — Prepared Statements 강제
- XSS — `htmlspecialchars()` 입력 검증
- 비밀번호 — bcrypt (`password_hash`)
- API — JSON 전용 (`Content-Type: application/json` 강제)
- 보안 헤더 — `X-Content-Type-Options`, `X-Frame-Options`
- internal API (moree-mh 가 호출) — HMAC + timestamp + nonce

### RBAC 역할
- **master** — 모든 메뉴 + 사용자 관리
- **admin** — 운영 메뉴 (계약·결제·메시지)
- **field_manager** — 현장 메뉴 (분양·안치)
- 메뉴별 접근 권한은 `role_menu_permissions` 테이블

### 디렉토리 위치 운영 (개별 인스턴스 관점)
- 신규: `/home/_tenants/{site}/www`
- 레거시 호환 (.acux.store): `/home/{site}` 가 symlink 로 `_tenants/{site}` 가리킴
- DocumentRoot 는 Apache `*.acux.store` / `*.mo-ree.com` 와일드카드 vhost 가 결정
