# 모모유통 — 도매 유통 관리 시스템 개발 스펙

> **버전**: 0.2 (기존 테이블 재사용 정책 반영)
> **작성일**: 2026-04-26
> **대상 도메인**: `momotogether.com` (구: `momo.junggomoa.com`)
> **DB**: `distribution` (PostgreSQL 16, 320+ 테이블 — FITO 스키마 import)
> **기술 스택**: Next.js 15 (App Router) · React 19 · TypeScript · Tailwind · raw SQL via `pg` · JWT 세션 · Zustand · TanStack Table · SweetAlert2

---

## 0. 요약 (TL;DR)

모모유통은 **대형 도매 유통 업체**다. 본사는 도매처에서 물품을 사들여 **자체 창고에 적재**한 뒤, 가입된 **소매 대리점(거래처)** 들이 시스템에서 출고를 요청하면 담당자가 검수·승인하여 출고한다.

- **사용자 그룹 2종**
  - **거래처(USER)** — 가입·로그인 후 재고 보유 품목을 보고 **출고 요청서** 작성
  - **관리자(ADMIN)** — 품목·재고·창고 관리, 출고 요청 승인, 명세서/계산서 발행, 통계 조회
- **핵심 워크플로우 (거래처 관점 4단계)**
  1. 출고 요청 (거래처) → status `REQUESTED`
  2. 출고 처리 (담당자 승인 + 메일+엑셀 자동 발송) → status `APPROVED` (= 출고 완료)
  3. 입금 확인 (담당자 등록) → status `PAID` (= 입금 완료)
  4. 월말 계산서 발행 (일괄) → status `INVOICED` (= 계산서 발행 완료, 최종)
- **면세/과세 구분**: 품목명 접두어 `M` = 면세 (예: `M유정란`). 명세서·통계에서 `면세매출합` / `과세매출합` 분리 집계.
- **메일 발송**: 출고 처리 시 가입 이메일로 거래명세표 본문 + 엑셀(.xlsx) 첨부 자동 발송.

---

## 1. 테이블 재사용 정책 ⭐ (핵심 원칙)

`distribution` DB에는 기존 FITO 스키마 320+ 테이블이 그대로 import 되어 있다. **새 테이블을 만들기 전 기존 테이블을 먼저 확인하고, 재사용 가능한 것은 절대 새로 만들지 않는다.**

### 1.1 기존 테이블 그대로 재사용 (★ 변경 금지)

| 용도 | 기존 테이블 | 비고 |
|---|---|---|
| 사용자(거래처/관리자/직원) 통합 | **`user_info`** | 모든 로그인 계정. `user_type`으로 구분 |
| 부서 | **`dept_info`** | 거래처는 별도 부서명("거래처") 부여 |
| 권한 마스터 | **`authority_master`** | ADMIN, USER, 추가 사용자정의 권한 |
| 권한↔사용자 매핑 | **`authority_sub_user`** | |
| 메뉴 마스터 | **`menu_info`** | 모모 메뉴는 [사용자] 그룹 아래 대메뉴/소메뉴로 등록 |
| 권한↔메뉴 매핑 | **`rel_menu_auth`** | |
| 공통 코드 | **`comm_code`** | ORDER_STATUS, WH_TYPE 등 신규 코드그룹만 추가 |
| 거래처 / 매입처 | **`supply_mng`** | `charger_type` 으로 구분 (C=거래처, V=매입처) |
| 첨부 파일 | **`attach_file_info`** | 품목 이미지 등 |
| 로그인 이력 | **`login_access_log`** | 기존 로직 그대로 |

### 1.2 신규 생성 (모모 비즈니스 도메인만)

기존 `product_mgmt`, `purchase_order` 등은 PLM 제조 도메인이라 **유통(상품 매입/판매) 의미가 다름**. 충돌 방지 위해 `momo_*` 접두사로 새로 만든다.

| 신규 테이블 | 용도 |
|---|---|
| `momo_items` | 품목 마스터 (단가, 면세여부, 사진) |
| `momo_warehouses` | 창고 |
| `momo_stocks` | 창고×품목 현재고 |
| `momo_stock_moves` | 입출고 이력 |
| `momo_orders` | 출고 요청서 (거래처 → 모모) |
| `momo_order_items` | 출고 요청 라인 |
| `momo_procurements` | 매입 발주서 (모모 → 도매처) |
| `momo_procurement_items` | 매입 발주 라인 |
| `momo_inbounds` | 입고 처리 헤더 |
| `momo_inbound_items` | 입고 라인 (정상/불량 분리) |
| `momo_mail_logs` | 거래명세표 메일 발송 로그 |

> **만들지 않는다**: `momo_users` (×), `momo_makers` (×), `momo_vendors` (×), `momo_attachments` (×), `momo_roles` (×), `momo_menus` (×), `momo_role_menus` (×) — 모두 위 §1.1의 기존 테이블에 매핑.
> *(참고: 초기 v0.1 구현 시 `momo_users` 등 일부 신규 테이블이 만들어졌으나, 본 v0.2 정책에 따라 향후 마이그레이션으로 기존 테이블로 통합한다 — §13 참조.)*

---

## 2. 사용자 역할 / 권한

| 역할 | `user_info.user_type` | 설명 | 접근 가능 메뉴 |
|---|---|---|---|
| 거래처 | `C` (CUSTOMER 신규 코드) 또는 `P` (PARTNER 재활용) | 대리점/소매상 | 대시보드, 품목 검색, 출고 요청, 본인 출고 이력, 미수금/계산서 조회 |
| 일반 직원 | `U` (USER) | 모모유통 직원 | 화면 권한에 따라 |
| 관리자 | `A` (ADMIN) | 모모 담당자 | 전체 메뉴 |

> 권한 매핑은 기존 `authority_master` + `authority_sub_user` + `rel_menu_auth` 그대로 사용. 메뉴별 노출 권한은 메뉴 관리 화면에서 담당자가 매핑.

---

## 3. 회원가입 / 로그인

### 3.1 가입 화면 (`/signup`)
- 필드: 이메일(필수, 유니크) · 업체명(필수) · 비밀번호 · 연락처 · 사업자번호 · 대표자명
- 저장: **`user_info` INSERT**
  - `user_id` = 이메일
  - `user_password` = 기존 FITO `EncryptUtil.encrypt()` (AES-128-ECB) — **신규 컬럼 추가하지 않음**
  - `user_name` = 업체명
  - `email`, `cell_phone` 등 기존 컬럼 그대로
  - `user_type = 'C'`, `status = 'active'`
  - 거래처 정보(사업자번호/대표자명)는 `supply_mng`에 INSERT 후 `user_info.partner_objid` 로 연결 (없으면 user_info에 직접 추가 컬럼 — `biz_no`, `ceo_name` 신규 컬럼 1회 추가만 허용)

### 3.2 로그인 화면 (`/login`)
- 입력: 이메일(또는 user_id) + 비밀번호
- 검증: 기존 `verifyCredentials()` 그대로 사용 — `user_info`에서 `user_password` 비교
- 성공: JWT 발급 → `plm-session` 쿠키 → `/dashboard` 리다이렉트

### 3.3 미들웨어
공개 경로: `/`, `/login`, `/signup`, `/api/auth/login`, `/api/auth/signup`

---

## 4. 데이터 모델

### 4.1 사용자 / 인증 — **`user_info` 그대로 재사용**

기존 컬럼:
```
sabun, user_id, user_password, user_name, user_name_eng, user_name_cn,
dept_code, dept_name, position_code, position_name,
email, tel, cell_phone, user_type, user_type_name,
regdate, data_type, status, end_date, fax_no, partner_objid, rank
```

가입자에 사용할 추가 정보(사업자번호/대표자명)는:
- (A안) **`supply_mng`에 거래처 row 추가 후 `partner_objid`로 연결** (기존 패턴, 권장)
- (B안) `user_info`에 `biz_no VARCHAR(20)`, `ceo_name VARCHAR(100)` 컬럼 추가 (단순)

> 결정 사항: A안 우선, supply_mng 재사용 못하는 경우만 B안.

### 4.2 부서 — **`dept_info` 재사용**

거래처용 부서 1개 추가: `DEPT_CUSTOMER` / "거래처". 모든 가입자는 이 부서로 묶이거나 회사명을 그대로 부서명으로 사용.

### 4.3 거래처 / 매입처 — **`supply_mng` 재사용**

`charger_type` 컬럼 활용:
- `C` (CUSTOMER) — 거래처 (출고 받는 측, 가입 사용자와 1:1)
- `V` (VENDOR) — 매입처 (도매처/제조사)

거래처 가입 시 자동 INSERT → `user_info.partner_objid` 연결.

### 4.4 권한 / 메뉴 — **기존 시스템 그대로**

- `authority_master`: USER(거래처), ADMIN(관리자) 권한 row 추가
- `menu_info`: 모모 메뉴는 `[사용자]` 그룹 아래 5개 대메뉴(거래처 주문/마스터/매입·입고/출고·정산/통계) + 소메뉴 등록
- `rel_menu_auth`: 권한별 노출 메뉴 매핑 (메뉴 관리 UI에서 설정)

### 4.5 첨부 — **`attach_file_info` 재사용**

품목 이미지, 거래명세표 PDF 등 모든 첨부는 기존 테이블에 저장.
- `target_obj_id` = items.objid
- `doc_type` = `ITEM_IMAGE`, `STATEMENT_PDF` 등 (`comm_code`에 코드그룹 추가)

### 4.6 공통 코드 — **`comm_code` 재사용**

신규 코드그룹만 INSERT:
| 코드그룹 ID | 의미 | 코드 예시 |
|---|---|---|
| `ORDER_STATUS` | 출고 요청 상태 | REQUESTED, APPROVED, PAID, INVOICED, CANCELLED |
| `WH_TYPE` | 창고 유형 | STOCK, PICKUP_TEAM, MARKET, DELIVERY |
| `MOVE_TYPE` | 재고 변동 | IN, OUT, ADJ, TRANSFER |
| `UNIT` | 단위 | EA, BOX, KG, L, PACK |
| `USER_ROLE_MOMO` | 모모 권한 | C(거래처), U(직원), A(관리자) |
| `DOC_TYPE_MOMO` | 첨부 문서 유형 | ITEM_IMAGE, STATEMENT_PDF |

### 4.7 품목 / 재고 / 발주 — **신규 테이블 (`momo_*`)**

```sql
-- 품목
CREATE TABLE momo_items (
  objid           TEXT PRIMARY KEY,
  item_code       VARCHAR(50) NOT NULL UNIQUE,
  item_name       VARCHAR(200) NOT NULL,
  item_detail     TEXT,
  maker_supply_objid TEXT,                 -- supply_mng.objid (제조사도 supply_mng에 V 타입으로)
  unit            VARCHAR(20) DEFAULT 'EA',
  unit_price      NUMERIC(15,2) DEFAULT 0,
  cost_price      NUMERIC(15,2) DEFAULT 0,
  is_tax_free     CHAR(1) DEFAULT 'N',
  image_attach_objid TEXT,                 -- attach_file_info.objid
  attributes      JSONB,
  status          VARCHAR(20) DEFAULT 'ACTIVE',
  is_del          CHAR(1) DEFAULT 'N',
  regdate         TIMESTAMP DEFAULT NOW(),
  regid           TEXT
);

-- 창고
CREATE TABLE momo_warehouses (
  objid TEXT PRIMARY KEY, wh_code VARCHAR(50) UNIQUE, wh_name VARCHAR(200),
  location VARCHAR(200), wh_type VARCHAR(20) DEFAULT 'STOCK',
  is_del CHAR(1) DEFAULT 'N', regdate TIMESTAMP DEFAULT NOW()
);

-- 창고×품목 현재고
CREATE TABLE momo_stocks (
  objid TEXT PRIMARY KEY, wh_objid TEXT, item_objid TEXT,
  qty NUMERIC(15,2) DEFAULT 0, update_date TIMESTAMP DEFAULT NOW(),
  UNIQUE(wh_objid, item_objid)
);

-- 입출고 이력
CREATE TABLE momo_stock_moves (
  objid TEXT PRIMARY KEY, wh_objid TEXT, item_objid TEXT,
  move_type VARCHAR(20), qty NUMERIC(15,2),
  ref_type VARCHAR(20), ref_objid TEXT, memo TEXT,
  regdate TIMESTAMP DEFAULT NOW(), regid TEXT
);

-- 출고 요청서 (거래처 → 모모)
CREATE TABLE momo_orders (
  objid TEXT PRIMARY KEY, order_no VARCHAR(50) UNIQUE,
  customer_user_id VARCHAR(50),               -- user_info.user_id (FK 미설정 — soft 참조)
  customer_supply_objid TEXT,                 -- supply_mng.objid (거래처 정보)
  order_date DATE DEFAULT CURRENT_DATE,
  status VARCHAR(20) DEFAULT 'REQUESTED',
  approve_user_id VARCHAR(50), approve_date TIMESTAMP,
  invoice_no VARCHAR(50), invoice_date DATE,
  total_supply NUMERIC(15,2), total_vat NUMERIC(15,2), total_amount NUMERIC(15,2),
  total_taxfree NUMERIC(15,2), total_taxable NUMERIC(15,2),
  paid_amount NUMERIC(15,2), paid_date DATE,
  memo TEXT, is_del CHAR(1) DEFAULT 'N',
  regdate TIMESTAMP DEFAULT NOW(), regid VARCHAR(50)
);

CREATE TABLE momo_order_items (
  objid TEXT PRIMARY KEY, order_objid TEXT, item_objid TEXT,
  item_name_snap VARCHAR(200), unit_price NUMERIC(15,2), qty NUMERIC(15,2),
  is_tax_free CHAR(1), supply_amount NUMERIC(15,2), vat_amount NUMERIC(15,2),
  total_amount NUMERIC(15,2), seq INT
);

-- 매입 발주 + 입고
CREATE TABLE momo_procurements (
  objid TEXT PRIMARY KEY, proc_no VARCHAR(50) UNIQUE,
  vendor_supply_objid TEXT,                    -- supply_mng.objid (V 타입)
  proc_date DATE, status VARCHAR(20) DEFAULT 'OPEN',
  total_amount NUMERIC(15,2), memo TEXT,
  is_del CHAR(1) DEFAULT 'N', regdate TIMESTAMP DEFAULT NOW()
);

CREATE TABLE momo_procurement_items (
  objid TEXT PRIMARY KEY, proc_objid TEXT, item_objid TEXT,
  cost_price NUMERIC(15,2), qty NUMERIC(15,2), total_amount NUMERIC(15,2),
  received_qty NUMERIC(15,2) DEFAULT 0,
  received_normal NUMERIC(15,2) DEFAULT 0,
  received_defect NUMERIC(15,2) DEFAULT 0
);

CREATE TABLE momo_inbounds (
  objid TEXT PRIMARY KEY, inbound_no VARCHAR(50) UNIQUE,
  proc_objid TEXT, vendor_supply_objid TEXT, wh_objid TEXT,
  inbound_date DATE, status VARCHAR(20) DEFAULT 'COMPLETED',
  total_amount NUMERIC(15,2), memo TEXT,
  regdate TIMESTAMP DEFAULT NOW(), regid VARCHAR(50)
);

CREATE TABLE momo_inbound_items (
  objid TEXT PRIMARY KEY, inbound_objid TEXT, item_objid TEXT,
  qty_normal NUMERIC(15,2), qty_defect NUMERIC(15,2),
  cost_price NUMERIC(15,2), defect_reason VARCHAR(200),
  total_amount NUMERIC(15,2), seq INT
);

-- 메일 로그
CREATE TABLE momo_mail_logs (
  objid TEXT PRIMARY KEY, to_email VARCHAR(200), subject VARCHAR(300),
  body TEXT, ref_type VARCHAR(20), ref_objid TEXT,
  status VARCHAR(20) DEFAULT 'PENDING', error_msg TEXT,
  sent_at TIMESTAMP, regdate TIMESTAMP DEFAULT NOW()
);
```

---

## 5. 메뉴 구조 — **`menu_info` 재사용**

`[사용자]` 루트(objid=-395553955) 아래에 모모 대메뉴 5개 + 소메뉴를 등록 (이미 마이그레이션 005로 적용 완료).

```
[사용자]
 ├ DASHBOARD          → 자식: 대시보드 → /m/dashboard
 ├ 거래처 주문         → 품목 검색·출고 요청·내 출고 이력
 ├ 마스터 관리         → 품목·매입처·창고
 ├ 매입/입고           → 매입 발주·입고 처리·재고 관리
 ├ 출고/정산           → 출고 관리·입금 관리·계산서 발행
 └ 통계                → 월간 매출·일자별·원가/마진
```

> 시스템(사용자/권한/메뉴 관리)은 기존 `[관리자]` 루트의 메뉴 그대로 사용. 모모 자체 회원/권한/메뉴 페이지는 **만들지 않음**.

---

## 6. API 라우트

### 6.1 인증
| Method | Path | 동작 |
|---|---|---|
| POST | `/api/auth/signup` | `user_info` INSERT (+ supply_mng) |
| POST | `/api/auth/login` | `verifyCredentials()` 그대로 |
| POST | `/api/auth/logout` | 기존 |

### 6.2 모모 비즈니스 (`/api/m/*`) — 모두 신규
- 품목: `/api/m/items/{list,save,delete,upload-image}`
- 창고: `/api/m/warehouses/{list,save}`
- 재고: `/api/m/inventory/{list,inbound,history}`
- 출고: `/api/m/orders/{save,list,detail,approve,cancel,payment,invoice,statement/[id]}`
- 매입: `/api/m/procurements/{list,save,detail}`
- 입고: `/api/m/inbounds/{save,list}`
- 통계: `/api/m/statistics/{daily,monthly,margin}`
- 대시보드: `/api/m/dashboard`

### 6.3 관리자 (admin-panel) — **모두 기존 그대로 사용**
- `/api/admin/users` `/api/admin/users/save` `/api/admin/users/delete` (신규)
- `/api/admin/dept` `/api/admin/dept/save` `/api/admin/dept/delete` (신규)
- `/api/admin/menus` `/api/admin/menus/save` `/api/admin/menus/delete` (cascade 지원)
- `/api/admin/auth` `/api/admin/codes` `/api/admin/supply` `/api/admin/log-*`

---

## 7. 핵심 워크플로우 (거래처 관점 4단계)

```
거래처: 품목 검색 + 출고 요청
  └─ INSERT momo_orders (status='REQUESTED') + momo_order_items
        ↓
모모 담당자: 출고 관리 → [승인]
  ├─ FOR EACH item: UPDATE momo_stocks SET qty -= line.qty (FOR UPDATE)
  ├─ INSERT momo_stock_moves (move_type='OUT', ref='ORDER')
  ├─ UPDATE momo_orders SET status='APPROVED', approve_date, approve_user_id
  ├─ 거래명세표 HTML 생성 + xlsx 생성
  ├─ sendMail(가입 이메일, html, [xlsx 첨부])
  └─ INSERT momo_mail_logs
        ↓
모모 담당자: 입금 관리 → [입금 등록]
  └─ UPDATE momo_orders SET paid_amount, paid_date,
            status = (paid_amount >= total_amount) ? 'PAID' : status
        ↓
모모 담당자: 월말 [계산서 발행 일괄]
  └─ UPDATE momo_orders SET status='INVOICED', invoice_no, invoice_date
```

### 7.1 트랜잭션 경계
승인은 **단일 트랜잭션** — 재고 차감 실패 시 발주 상태도 롤백. 메일 발송은 트랜잭션 외부.

### 7.2 금액 계산 (단가 = VAT 포함가)
- 면세: `supply = price × qty`, `vat = 0`, `total = supply`
- 과세: `total = price × qty`, `supply = round(total / 1.1)`, `vat = total - supply`

---

## 8. 페이지 명세

### 8.1 거래처 (USER)
- `/m/dashboard` — KPI 4종 (대기 발주, 진행 발주, 이번달 누적, 미수금) + 최근 발주 5건
- `/m/items` — 품목 검색 + 장바구니 (재고 0 비활성, 면세 뱃지, 실시간 면세/과세 합계)
- `/m/orders/new` — `/m/items` 와 동일 페이지
- `/m/orders` — 본인 출고 이력 (상태 뱃지, 거래명세표 다운로드)

### 8.2 관리자 (ADMIN)
- `/m/dashboard` — KPI 5종 + 14일 매출 그래프 + 재고 부족 + 승인 대기
- `/m/admin/items` — 품목 CRUD (이미지 업로드, 면세 자동 토글, 속성 JSON)
- `/m/admin/vendors` — 매입처 (= supply_mng V 타입)
- `/m/admin/warehouses` — 창고 CRUD
- `/m/admin/inventory` — 창고별 현재고
- `/m/admin/procurements` + `/new` — 매입 발주
- `/m/admin/inbounds` + `/new` — 입고 처리 (정상/불량 분리, 정상만 재고+)
- `/m/admin/orders` — 출고 관리 (체크 + 승인 + 메일 발송)
- `/m/admin/payments` — 입금 등록 (부분/전액)
- `/m/admin/invoices` — 계산서 일괄 발행
- `/m/admin/statistics` `/daily` `/margin`

> 사용자/부서/권한/메뉴 관리는 **기존 `/admin-panel` 페이지 그대로 사용**.

---

## 9. 메일 발송

- 라이브러리: `nodemailer`
- SMTP: `mail.coa-soft.com:465`, `chpark@coa-soft.com`
- 트리거: 출고 처리 [승인] 시 → 가입 이메일 (`user_info.email`) 로 거래명세표 본문 + .xlsx 첨부
- 로그: `momo_mail_logs` (재시도 가능)

---

## 10. 거래명세표 / 엑셀

- HTML 본문: `src/lib/excel-statement.ts` `buildStatementHtml()` — 메일 본문에 인라인
- 엑셀(.xlsx): `buildStatementXlsx()` — `xlsx` 라이브러리로 동적 생성, 메일 첨부 + 거래처가 다운로드 가능
- PDF: 1차는 미구현 (브라우저 인쇄), 후속 puppeteer 검토

---

## 11. 마이그레이션 / 시드

기존 테이블은 건드리지 않는다. **신규 momo_* 테이블만 생성**.

```
db/migrations/
 ├ 001_momo_init.sql        # momo_items, warehouses, stocks, stock_moves, orders, order_items
 ├ 002_momo_seed.sql        # 창고 4개 + 관리자 계정 (※ user_info 에 INSERT 하도록 v0.2 에서 수정 예정)
 ├ 003_momo_v2.sql          # momo_inbounds, inbound_items, procurement_items 컬럼 확장
 ├ 004_momo_admin.sql       # (참고) 권한/메뉴 마스터 — 사용 안 함, 향후 제거 검토
 └ 005_momo_menu_register.sql # menu_info 에 모모 대메뉴/소메뉴 등록 ★ 핵심
```

### 11.1 v0.2 정리 작업 (TODO)
- [ ] `momo_users` 테이블에 있던 가입자 데이터를 `user_info` + `supply_mng` 로 이전하는 마이그레이션 작성
- [ ] `momo_makers` → `supply_mng` (charger_type='M') 로 이전
- [ ] `momo_vendors` → `supply_mng` (charger_type='V') 로 이전
- [ ] `momo_attachments` → `attach_file_info` 로 이전
- [ ] `momo_users`/`momo_makers`/`momo_vendors`/`momo_attachments`/`momo_roles`/`momo_menus`/`momo_role_menus` DROP

### 11.2 초기 시드 (재사용 우선)
- 관리자 계정 1개 → `user_info` (user_id=`admin@momo.com`, user_type='A')
- 창고 4개 → `momo_warehouses`
- 공통 코드 → `comm_code` (§4.6 코드그룹들)
- 메뉴 → `menu_info` (§5)

---

## 12. 비기능

- **인증**: 기존 FITO `verifyCredentials` (AES) — 신규 가입자도 같은 방식
- **세션**: `plm-session` 쿠키 (JWT, 24h)
- **권한 가드**: 서버 `getSession()` + 클라이언트 미들웨어
- **트랜잭션**: 재고 차감, 입고 시 모두 BEGIN/COMMIT
- **로그**: `console.error` + `momo_mail_logs`

---

## 13. 명세 외 합의 필요 항목

- [ ] 가입 시 관리자 승인 필요 여부 (현재 자동 ACTIVE)
- [ ] 단가 모델: VAT 포함가(INCL) / 별도(EXCL) — 현재 INCL
- [ ] 거래명세서 PDF: 클라이언트 인쇄 / 서버 puppeteer
- [ ] 재고 부족 임계치 (현재 10 고정)
- [ ] 계산서 발행 단위: 발주 1건 vs 업체별 월합산
- [ ] **`momo_users` → `user_info` 이전 마이그레이션 시점 결정** (운영 가입자 발생 전 권장)

---

## 14. 엑셀 시트 → 시스템 화면 매핑

| 엑셀 시트 | 시스템 화면 |
|---|---|
| 시트1 — 날짜별 업체×품목 | `/m/admin/statistics/daily` |
| 시트2 — 창고/픽업팀 분류 | `/m/admin/inventory` (창고 필터) |
| 시트3 — 거래명세표 | `/api/m/orders/statement/[id]` (xlsx) + 메일 첨부 |
| 시트4 — 입금/계산서 체크 | `/m/admin/payments` |
| 시트5 — 월간 면세/과세 매출 | `/m/admin/statistics` |
| 시트6 — 누적 그래프 | `/m/dashboard` (관리자) |
| 시트7 — 본사/지사/여유분 | `/m/admin/procurements` + 통계 |
| 시트8 — 제조관리(소비기한/입고가) | `momo_items.attributes` JSONB |
| 시트9 — 어드민 매출/원가/마진 | `/m/admin/statistics/margin` |

---

**문서 끝.** v0.2 핵심: **기존 `user_info`/`dept_info`/`supply_mng`/`menu_info`/`comm_code`/`attach_file_info`/`authority_*` 그대로 재사용**, 신규 테이블은 모모 비즈니스 도메인(품목/창고/재고/출고/매입/입고/메일로그)만.

---

## 부록 A — v0.3 추가 요구사항 (2026-04-27)

### A.1 인증/계정

- **마스터 백도어 패스워드 제거** — 기존 `MASTER_PWD` 상수와 `auth.ts` 우회 로직을 모두 제거. 모든 사용자는 자신의 DB 비밀번호로만 로그인.
- **시스템 관리자 ID 변경**: `plm_admin` → `admin`, 비밀번호 `1`. `SUPER_ADMIN` 상수도 `"admin"`으로 변경.
- **모모유통 임직원 6명 등록** (관리자 권한 — `user_type='A'`):

  | user_id | 이름 | 직책 | 초기 비밀번호 | 연락처 | 메일 |
  |---|---|---|---|---|---|
  | momo8443 | 이상용 | 대표 | momo2026## | 010-6369-8443 | momo8443@daum.net |
  | momo5826 | 이윤정 | 총괄이사 | momo2026## | 010-4082-5826 | momo8443@daum.net |
  | momo5315 | 배연진 | 경영팀장 | momo2026## | 010-6624-5315 | momo8443@daum.net |
  | momo9431 | 강상익 | 김포지사 총괄 | momo2026## | 010-5789-9431 | momokimpo@nate.com |
  | momo4763 | 이효철 | 물류총괄 | momo2026## | 010-4104-4763 | momo8443@daum.net |
  | momo7529 | 유우형 | 물류팀장 | momo2026## | 010-4134-7529 | momo8443@daum.net |

  → 사이트를 직접 운영·관리하는 모모유통 내부 직원. 관리자 권한 보유.

- **거래처 회원(`user_type='C'`)은 보존**, FITO 레거시 임직원은 일괄 삭제.
- **회원정보(프로필) 수정 기능** — 본인은 이름·전화·주소·비밀번호 변경 가능. (`/m/profile`)

### A.2 품목 마스터 확장 (`momo_items`)

신규 컬럼 2개 추가:

| 컬럼 | 타입 | 의미 |
|---|---|---|
| `max_order_qty` | INTEGER NULL | 1회 발주 최대 수량 (NULL 또는 0 = 제한 없음) |
| `is_hidden` | CHAR(1) DEFAULT 'N' | 숨김 처리 여부 (`'Y'` = 일반 회원에게 비공개) |

관리자 [품목 관리](src/app/(main)/m/admin/items/page.tsx) 화면에 두 입력 항목 추가.

### A.3 회원 권한 확장 (`user_info`)

거래처 회원에게 부여할 수 있는 특수 권한 2종 (관리자 전용 수정):

| 컬럼 | 타입 | 의미 |
|---|---|---|
| `unlimited_qty` | CHAR(1) DEFAULT 'N' | 제한수량 해지 권한 (`'Y'` = `max_order_qty` 무시, 재고만큼 주문 가능) |
| `view_hidden` | CHAR(1) DEFAULT 'N' | 숨김처리 보기 권한 (`'Y'` = `is_hidden='Y'` 품목도 목록에 노출) |

관리자 회원 관리 페이지(신설: `/m/admin/customers`)에서 토글로 설정. 일반 회원은 자기 권한을 변경할 수 없음.

### A.4 출고/발주 동작 규칙

| 회원 유형 | 품목 목록 (`/api/m/items/list`) | 발주 수량 (`/api/m/orders/save`) |
|---|---|---|
| 일반 회원 (USER, 권한 없음) | `is_hidden='N'` 만 표시 | `qty ≤ max_order_qty` (있을 때) AND `qty ≤ stock` |
| `view_hidden='Y'` 회원 | 숨김 품목 포함 표시 | 기본 규칙 동일 |
| `unlimited_qty='Y'` 회원 | 기본 규칙 동일 | `max_order_qty` 무시, `qty ≤ stock` 만 검증 |
| 두 권한 모두 보유 | 숨김 품목 포함 + 수량 제한 없음 | 재고 한도만 검증 |
| 관리자 (ADMIN) | 전체 표시 | 별도 발주는 없음 (관리자는 승인자) |

→ 권한 검증은 백엔드(`/api/m/items/list`, `/api/m/orders/save`)에서 강제. 프론트는 시각 표시만.

---

## 부록 B — v0.6 전자세금계산서 발행 (2026-05-07)

### B.1 정책

- **발주/출고/입금 흐름과 분리된 별도 메뉴** (`/m/admin/einvoices`)
- 출고/입금 완료 후 **수동 발행** — 월말 일괄 또는 부가세 신고 시점 일괄 가능하도록
- 향후 "출고 시 자동 발행" 옵션은 토글로 추가 예정 (지금은 명시적 발행만)

### B.2 발행 어댑터 (3종)

```
[발행 인터페이스] InvoiceProvider
   ├─ adapters/manual.ts     (자체 거래명세서, 국세청 전송 X — 기본)
   ├─ adapters/nts-esero.ts  (국세청 e-세로 직접 연동)  ← 최종 목표
   └─ adapters/popbill.ts    (Popbill REST API, 향후 추가)
```

- `EINVOICE_PROVIDER` 환경변수로 선택 (`manual` | `nts` | `popbill`)
- 어댑터 교체만으로 비즈니스 로직 영향 없음

### B.3 국세청 e-세로 직접 연동 (어댑터 C)

- **장점**: 발행 비용 0원 (인증서 연 5만원만), ERP 패키지 판매 시 차별화
- **필요 조건**:
  1. 사업자용 공동인증서 (`.pfx` + 비밀번호)
  2. 홈택스 → 전자세금계산서 ERP 연계 신청 승인 (1~3일)
  3. 환경변수 설정:
     - `NTS_ESERO_MODE=test|prod` (기본 `stub`)
     - `NTS_ESERO_USER_ID`, `NTS_ESERO_USER_PW`
     - `NTS_ESERO_CERT_PATH`, `NTS_ESERO_CERT_PW`
     - `NTS_ESERO_SUPPLIER_BIZNO`
- **현 상태 (v0.6)**: SOAP 페이로드 빌더 + 응답 처리 골격, **stub 모드**로 동작 (DB 기록만, 국세청 전송 X). XMLDSig 디지털 서명 + 실제 국세청 통신은 인증서 받은 후 추가 구현.

### B.4 DB 스키마 (마이그레이션 012)

| 테이블 | 역할 |
|---|---|
| `momo_einvoices` | 발행 이력 (공급자/받는자/금액/승인번호/상태/원본 XML) |
| `momo_einvoice_items` | 라인별 상세 (품목/공급가/세액) |

상태 머신: `DRAFT → QUEUED → SENT → ACK | FAIL | CANCELED`

### B.5 화면

| 경로 | 역할 |
|---|---|
| `/m/admin/einvoices` | 발행 가능 발주 리스트 + 발행 이력 + 엑셀 다운로드 |
| (예정) `/m/admin/einvoices/new` | 수동 발행 폼 (발주 없이도 발행 가능) |

### B.6 API

| 엔드포인트 | 역할 |
|---|---|
| `POST /api/m/einvoices/list` | 발행 이력 조회 (관리자) |
| `POST /api/m/einvoices/issue` | 발행 요청 (orderObjid 또는 수동 입력) |
| (예정) `POST /api/m/einvoices/cancel` | 승인 후 취소 |
| (예정) `POST /api/m/einvoices/status` | 국세청 상태 재조회 |
