chpark 5f1983b0f6 feat(deploy): firebase-sa.json 호스트 마운트 추가 — FCM 발송용
호스트의 /home/chpark/momo-erp/firebase-sa.json 을 컨테이너 안
/deploy/firebase-sa.json (ro) 으로 마운트. .env.production 의 FIREBASE_SA_PATH
환경변수가 이 경로를 가리킴 → src/lib/firebase-push.ts 의 sendFcm() 가 정상 동작.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 00:11:43 +09:00

모모유통 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 참고.


로컬 개발

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 이 자동 실행되어 운영 서버에서 git pull → docker compose build → up -d 까지 수행.

  • 운영 서버: 121.156.99.3 (SSH, chpark)
  • Compose 파일: 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.appmomotogether.com 을 감싸는 Trusted Web Activity.

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

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


코딩 컨벤션

상세 규칙은 .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 })

라이선스

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

S
Description
No description provided
Readme 148 MiB
Languages
TypeScript 94.6%
HTML 3.4%
JavaScript 1.8%
CSS 0.1%