# 모모유통 ERP (Distribution ERP)

식자재/도소매 **유통·물류 업무 통합 관리 시스템**.
거래처가 발주를 넣고, 본사가 출고·정산하고, 매입·입고·재고·세금계산서까지 한 화면에서 처리한다.

- 운영 도메인: **https://momotogether.com**
- Android 앱: **`com.momotogether.app`** (TWA, Play 스토어 등록용 AAB / 사이드로드 APK)
- 코드 저장소(원격): `git.junggomoa.com/chpark/distribution_erp`
- 사용자: (주)모모유통 본사·김포지사 + 계약 거래처 전용 — 일반 소비자용 아님

---

## 주요 기능

### 거래처(구매자) 화면
- **출고 요청** — 재고 있는 품목 선택 → 장바구니 → 발주 요청. 택배전용·용차비·환불 라인 자동/수동 추가. 상시판매·기간한정 품목 분리.
- **내 출고 이력** — 본인 발주 진행상태 추적.
- **푸시 알림 토글** — PWA 설치 후 새 상품 등록 시 알림 수신.
- **회원정보 수정** — 본인 정보·기준 명세표 변경.

### 본사/지사 운영
- **출고 처리** — 발주 검토 → 거래명세표 자동 생성(이미지/엑셀/메일 발송) → 재고 자동 차감.
- **입금 관리** — 출고 후 미수금 추적·입금 등록.
- **계산서·전자세금계산서** — 과세/면세 자동 분리. 국세청 ESERO 연동 어댑터(현재는 DB 기록).
- **매입 발주** — 공급업체별 발주서 작성·메일 발송. 발주지사(HQ/KIMPO) 선택.
- **매입 입금관리** — 진행상태와 결재상태(입금완료/미입금)를 **분리 관리**. 부분입고 시 입고금액 기준 입금 처리.
- **입고 처리** — 정상/불량 분리 입고, 유통기한·물류팀 최종완료자 체크리스트.
- **재고 관리** — 창고별 실시간 재고, 입출고 이력, 창고 간 이동, 유통기한 임박 알림.

### 마스터·통계·관리
- **품목 마스터** — 가격·원가·과세/면세·택배전용·1회 발주한도·판매기간(또는 상시판매) + 일괄 적용.
- **공급업체/거래처/창고/계산서 기준정보** 관리.
- **푸시알림 게시판** — 관리자가 공지(이미지+본문)를 작성하고 선택한 구독자에게 푸시 발송. 사용자가 알림 탭하면 공지 페이지로 이동.
- **통계** — 대시보드, 월간/일자별 매출, 원가·마진, 거래처×일자 매출, 지사 수수료, 창고 이동 통계.

---

## 기술 스택

- **풀스택 단일 Next.js 프로젝트** — 프론트(React 19, App Router) + 백엔드(API Routes, Node.js) 한 저장소.
- **TypeScript** strict mode, **Tailwind CSS**.
- **DB**: 외부 PostgreSQL `121.156.99.3:5432/distribution` — raw SQL(`pg`).
- **인증**: JWT(jose) + HTTP Cookie 세션 + AES-128-ECB(비밀번호).
- **PWA**: `manifest.json` + Service Worker(`public/sw.js`) — 푸시 핸들러·알림 위임(badge·icon).
- **푸시**: `web-push`(VAPID) — `momo_push_subscriptions` 에 endpoint 저장, 발송은 `lib/push.ts`.
- **거래명세표 캡처**: `html-to-image` (이미지 공유/저장).
- **상태관리**: Zustand (auth/menu/theme).

---

## 디렉토리 구조

```
src/
├── app/
│   ├── (auth)/login            로그인
│   ├── (main)/
│   │   ├── m/orders/new        거래처 — 출고요청
│   │   ├── m/orders            거래처 — 내 출고이력
│   │   ├── m/notices/[id]      공지 도달 페이지 (푸시 클릭 시)
│   │   ├── m/admin/orders      출고 처리
│   │   ├── m/admin/payments    입금 관리
│   │   ├── m/admin/invoices    계산서 발행
│   │   ├── m/admin/einvoices   전자세금계산서
│   │   ├── m/admin/procurements매입 발주서
│   │   ├── m/admin/proc-payments 매입 입금관리
│   │   ├── m/admin/inbounds    입고 처리
│   │   ├── m/admin/inventory   재고 관리
│   │   ├── m/admin/items       품목 마스터
│   │   ├── m/admin/notices     푸시알림 게시판
│   │   ├── m/admin/vendors     공급업체 관리
│   │   ├── m/admin/warehouses  창고 관리
│   │   ├── m/admin/statistics  통계 대시보드
│   │   └── profile             회원정보 수정
│   └── api/m/                  업무 API (orders/items/inbounds/push/notices …)
├── lib/
│   ├── db.ts            PostgreSQL Pool (queryRows/queryOne/execute)
│   ├── auth.ts          인증 + 세션
│   ├── push.ts          web-push 발송 + 구독 관리
│   ├── notices.ts       공지 테이블 자동 생성
│   ├── momo-proc.ts     매입 진행/결재 분리 마이그레이션
│   └── capture-share.ts 이미지 캡처/공유
├── components/
│   ├── layout/          Header / Sidebar
│   ├── grid/            DataGrid (TanStack Table)
│   ├── ui/              버튼/입력/SearchableSelect 등
│   └── push-optin.tsx   푸시 알림 켜기/끄기 토글 (localStorage 영속)
└── store/               Zustand (auth/menu/theme)

public/
├── sw.js                Service Worker — fetch 캐시 + push/notificationclick
├── manifest.json        PWA 매니페스트
├── icon-{192,512}.png   PWA 아이콘 (모모 로고)
├── badge-96.png         알림 상태바 단색 배지
└── .well-known/assetlinks.json  TWA Digital Asset Links

android/
├── twa-manifest.json    Bubblewrap TWA 빌드 설정 (notification delegation ON)
└── README.md            APK/AAB 빌드 가이드 (PWABuilder / Bubblewrap)
```

각 디렉토리별 상세는 `*/CLAUDE.md` 참고.

---

## 로컬 개발

```bash
npm install
npm run dev          # http://localhost:3000
npm run build        # 운영 빌드 검증
npm run lint
```

### 환경변수 (`.env.development`)

| 키 | 설명 |
|---|---|
| `DATABASE_URL` | PostgreSQL 접속 (예: `postgresql://momo_app:****@121.156.99.3:5432/distribution`) |
| `NEXTAUTH_URL` | 로컬: `http://localhost:3000` |
| `NEXTAUTH_SECRET` | JWT 서명 시크릿 |
| `AES_KEY` | 16바이트 — 비밀번호 AES 키 (기존 데이터 호환 필요) |
| `MASTER_PWD` | 마스터 비밀번호 (개발 편의) |
| `SMTP_HOST/USER/PASS/FROM` | 거래명세표·계산서 메일 발송 |
| `MOMO_BANK_ACCOUNT`, `MOMO_PHONE` | 거래명세표 공급자 정보 (기준명세표 미설정 폴백) |
| `VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY` | (선택) 웹푸시 VAPID — 미설정 시 `lib/push.ts` 의 기본키 사용 |

`.env.momo.example` 참고.

---

## 배포 — Gitea Actions 자동 배포

`main` 브랜치에 push 하면 [`.gitea/workflows/deploy.yml`](.gitea/workflows/deploy.yml) 이 자동 실행되어 운영 서버에서 `git pull → docker compose build → up -d` 까지 수행.

- 운영 서버: `121.156.99.3` (SSH, chpark)
- Compose 파일: [`docker-compose.prod.yml`](docker-compose.prod.yml)
- 컨테이너명: `momo-erp` / 이미지: `momo-erp:latest`
- 리버스 프록시: Traefik (`traefik-net` 외부 네트워크, Let's Encrypt 자동발급)
- 호스트: `momotogether.com`, `www.momotogether.com`
- 영구 스토리지: named volume `momo_data_storage` ↔ `/data_storage` (업로드 이미지)
- DB: 외부 공유 — 컨테이너 내부 DB 없음

> ⚠️ **수동 SSH 빌드 금지** — 자동 워크플로우와 충돌. 배포 검증은 `build-sha.txt` 또는 `docker logs momo-erp` 로 확인.

---

## Android 앱 (TWA)

`com.momotogether.app` — `momotogether.com` 을 감싸는 Trusted Web Activity.

- **알림 위임(notification delegation) ON** — 웹 푸시가 "삼성 인터넷" 등 브라우저가 아니라 **모모유통 앱 이름·아이콘**으로 표시됨.
- **AAB**: Play 스토어 업로드용
- **APK**: 사이드로드(직접 설치) 테스트용
- 빌드 가이드: [`android/README.md`](android/README.md) (PWABuilder 또는 Bubblewrap)
- ⚠️ 기존 서명키 재사용 필수 — 키가 바뀌면 `assetlinks.json` 지문이 안 맞아 위임 깨짐.

서비스워커 갱신 / 페이지 콘텐츠 변경은 **APK 재빌드 불필요** — 서버 배포만으로 앱에도 반영됨.

---

## 코딩 컨벤션

상세 규칙은 [`.claude/rules/`](.claude/rules/) 와 디렉토리별 `CLAUDE.md` 참고.

- **SQL alias 대문자 유지**: `SELECT col AS "OBJID"` (큰따옴표 필수, 없으면 PG 가 소문자 반환)
- **삭제 플래그**: `COALESCE(is_del,'N') != 'Y'`
- **objid 타입 변환**: `objid::text AS "OBJID"`
- **API 응답**: 목록 `{ RESULTLIST, TOTAL_CNT }`, 단건 `{ success, data }`, 저장 `{ success, objId? }`, 오류 `{ success:false, message }` + 적절한 status code
- **인증 가드**: 모든 API 라우트 첫 줄에 `getSession()` / `requireMomoAdmin()` / `requireMomoUser()`
- **신규 컬럼**: `ensureColumns` 패턴으로 라우트 첫 호출 시 자동 ALTER (운영 무중단)
- **푸시 알림 대상**: 일반 발송은 모든 구독자 / 거래처 전용은 `sendPush(payload, undefined, { generalOnly: true })`

---

## 라이선스

내부용. 외부 배포·재사용 금지.
