docs: README 를 현재 모모유통 ERP 기준으로 전면 재작성
Deploy momo-erp / deploy (push) Failing after 18m12s

이전엔 FITO PLM(Java→Next 컨버전 시절) 내용이 그대로 남아 있었음.
현 상태(유통/물류 ERP, momotogether.com, com.momotogether.app TWA)에 맞춰
주요 기능·기술 스택·디렉토리·환경변수·Gitea 자동배포·TWA 빌드·코딩 컨벤션
모두 갱신.
This commit is contained in:
chpark
2026-05-29 15:33:49 +09:00
parent 93d6f0fc3f
commit 8e49fab63f
+155 -47
View File
@@ -1,70 +1,178 @@
# FITO — (주)피토 PLM (Next.js) # 모모유통 ERP (Distribution ERP)
기존 Java/Spring MVC + JSP + MyBatis 기반 FITO PLM을 Next.js 15 + Node.js로 컨버전한 시스템. 식자재/도소매 **유통·물류 업무 통합 관리 시스템**.
거래처가 발주를 넣고, 본사가 출고·정산하고, 매입·입고·재고·세금계산서까지 한 화면에서 처리한다.
- 원본: [/Users/jhj/FITO](../FITO) (Java 7 + Spring 3.2.4 + MyBatis 3.2.3 + JSP) - 운영 도메인: **https://momotogether.com**
- DB: 외부 PostgreSQL `211.115.91.141:11140/fito` (기존 스키마 그대로 사용) - Android 앱: **`com.momotogether.app`** (TWA, Play 스토어 등록용 AAB / 사이드로드 APK)
- 이전 이력: `woosung-nextjs`에서 피벗. 스냅샷 태그 `woosung-v1-snapshot`. - 코드 저장소(원격): `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 `183.99.177.40: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 ```bash
npm install npm install
npm run dev # http://localhost:3000 npm run dev # http://localhost:3000
npm run build # 운영 빌드 검증
npm run lint
``` ```
## 환경변수 ### 환경변수 (`.env.development`)
`.env.development`의 DB 접속 정보를 확인. 필수 키: | 키 | 설명 |
|---|---|
| `DATABASE_URL` | PostgreSQL 접속 (예: `postgresql://momo_app:****@183.99.177.40: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` 의 기본키 사용 |
- `DATABASE_URL` — 외부 PostgreSQL 접속 `.env.momo.example` 참고.
- `NEXTAUTH_SECRET` — JWT 서명 키
- `MASTER_PWD` — 마스터 비밀번호 (개발 편의용)
- `AES_KEY` — 비밀번호 AES 암호화 키 (기존 Java 호환)
## 배포 표준 ---
- Docker Compose (dev/prod 분리) — 기존 FITO(Java) 배포환경 재사용 ## 배포 — Gitea Actions 자동 배포
- Traefik 리버스 프록시 + `fito.wace.me` 도메인 (entrypoints: web, websecure / certresolver: le)
- 외부 네트워크 `toktork_server_default`
- DB는 외부 서버 공유 (`211.115.91.141:11140/fito`) — 컨테이너 내부 DB 없음
### `start.sh` 배포 스크립트 (권장) `main` 브랜치에 push 하면 [`.gitea/workflows/deploy.yml`](.gitea/workflows/deploy.yml) 이 자동 실행되어 운영 서버에서 `git pull → docker compose build → up -d` 까지 수행.
```bash - 운영 서버: `183.99.177.40` (SSH, chpark)
# 첫 배포 (서버에서) - Compose 파일: [`docker-compose.prod.yml`](docker-compose.prod.yml)
cp .env.production.example .env.production - 컨테이너명: `momo-erp` / 이미지: `momo-erp:latest`
vi .env.production # DATABASE_URL, NEXTAUTH_SECRET, AES_KEY 등 입력 - 리버스 프록시: Traefik (`traefik-net` 외부 네트워크, Let's Encrypt 자동발급)
- 호스트: `momotogether.com`, `www.momotogether.com`
- 영구 스토리지: named volume `momo_data_storage``/data_storage` (업로드 이미지)
- DB: 외부 공유 — 컨테이너 내부 DB 없음
./start.sh prod # git pull → build → 기동 → Traefik 라우팅 확인 > ⚠️ **수동 SSH 빌드 금지** — 자동 워크플로우와 충돌. 배포 검증은 `build-sha.txt` 또는 `docker logs momo-erp` 로 확인.
# 이후 배포 (git commit 후) ---
./start.sh prod # 자동 git pull + 재빌드
# 기타 운영 ## Android 앱 (TWA)
./start.sh logs prod # 실시간 로그
./start.sh restart prod # 재시작 (git pull 포함)
./start.sh stop prod # 중지
./start.sh status prod # 컨테이너 상태
./start.sh build prod # no-cache 재빌드
./start.sh clean prod # 전체 삭제 (확인 필요)
```
스크립트는 start.sh 자체가 업데이트되면 새 버전으로 **자동 재실행**하므로 안전합니다. `com.momotogether.app``momotogether.com` 을 감싸는 Trusted Web Activity.
### 로컬 개발 - **알림 위임(notification delegation) ON** — 웹 푸시가 "삼성 인터넷" 등 브라우저가 아니라 **모모유통 앱 이름·아이콘**으로 표시됨.
- **AAB**: Play 스토어 업로드용
- **APK**: 사이드로드(직접 설치) 테스트용
- 빌드 가이드: [`android/README.md`](android/README.md) (PWABuilder 또는 Bubblewrap)
- ⚠️ 기존 서명키 재사용 필수 — 키가 바뀌면 `assetlinks.json` 지문이 안 맞아 위임 깨짐.
```bash 서비스워커 갱신 / 페이지 콘텐츠 변경은 **APK 재빌드 불필요** — 서버 배포만으로 앱에도 반영됨.
./start.sh # docker 기반 (localhost:3643, hot reload)
npm run dev # docker 없이 Node 직접 (localhost:3000)
```
### 인프라 정보 ---
- 컨테이너명: `plm-fito-next` (prod) / `plm-fito-next-dev` (dev) ## 코딩 컨벤션
- 도메인: `https://fito.wace.me`
- 내부 포트: 3000 (Traefik이 외부 80/443 → 3000)
- 파일 저장: 호스트 `./data_storage` (레포 상대경로) ↔ 컨테이너 `/data_storage`
- 이미지: Next.js `output: "standalone"` 기반 multi-stage build
상세 구성은 [CLAUDE.md](CLAUDE.md) 참고. 상세 규칙은 [`.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 })`
---
## 라이선스
내부용. 외부 배포·재사용 금지.