Commit Graph

258 Commits

Author SHA1 Message Date
chpark 21c8bf5ab5 fix(push,profile): 푸시 진단(환영/테스트/카운트) + 프로필 닫기 버튼
Deploy momo-erp / deploy (push) Successful in 1m55s
푸시:
- 구독 직후 '환영 푸시' 자동 발송 — 서버→푸시서비스→기기 경로 즉시 확인.
- /api/m/push/test (GET 구독 카운트, POST 본인 기기 테스트 발송).
- PushOptIn: 허용 결과 안내 + '알림 켜짐' 옆 [테스트] 버튼.
- sendPush 발송 로그(targets/sent/failed) 추가.

프로필:
- 회원정보 수정 페이지에 [닫기] 버튼 — 앱(standalone)은 브라우저 뒤로가기가
  없어 모달처럼 갇히던 문제. history 있으면 back, 없으면 /m/orders/new.
2026-05-27 00:39:18 +09:00
chpark 85ac9db997 feat(push): 품목 판매 일정 등록/변경 시 일반 사용자 전체에 알림
Deploy momo-erp / deploy (push) Successful in 2m1s
요구 정정 — 트리거는 품목 마스터 저장(items/save) 이며, '지금 출고 가능'
전환뿐 아니라 미래 판매예정(시작일이 오늘 이후)도 알림 대상.
- getSaleInfo(): 판매 일정 유무 + 마감 미경과(sellable) + 현재 출고가능(orderableNow).
- 등록: 판매 일정이 잡혀 있으면 알림. 수정: 판매 시작/마감일이 바뀌고
  그 일정이 아직 유효(오늘/미래)할 때만 알림 (단가 등 단순수정·과거날짜 제외).
- 메시지: 지금 가능 → "지금 출고요청 가능", 미래 → "{시작일} 판매 예정".
- 수신 대상: sendPush(generalOnly) — 관리자(user_type='A') 제외, 일반 거래처만.
2026-05-27 00:31:13 +09:00
chpark 34b64a5a17 feat(admin/users): 행별 수정(연필)/삭제(휴지통) 버튼 + 상태 한글 치환
Deploy momo-erp / deploy (push) Successful in 1m56s
- 사용자 관리 그리드 맨 오른쪽에 '관리' 컬럼 추가 — 품목 관리와 동일한
  연필(수정)/휴지통(삭제) 아이콘. 삭제는 행 단위 확인 후 처리.
- 상태(STATUS) 컬럼 active/inactive → 활성/비활성 한글 표시 (활성은 강조).
2026-05-27 00:27:49 +09:00
chpark b5302c52d2 feat(push): PWA 웹 푸시 — 품목이 출고요청 가능해지면 구독자에게 알림
Deploy momo-erp / deploy (push) Successful in 3m34s
- lib/push.ts: web-push + VAPID(env 우선/하드코딩 폴백) + momo_push_subscriptions
  자동 생성. sendPush() 는 만료(404/410) 구독 자동 정리.
- API: GET /api/m/push/vapid (공개키), POST /api/m/push/subscribe (구독 저장).
- sw.js: push / notificationclick 핸들러 추가 (클릭 시 /m/orders/new 열기).
- components/PushOptIn: 출고요청 페이지에 '새 품목 알림 받기' 버튼. 권한 허용 시
  구독 저장, 이미 허용이면 조용히 갱신. iOS<16.4 등 미지원 환경은 자동 숨김.
- items/save: 품목이 '출고요청 불가 → 가능' 으로 전환되면(신규 등록 포함, KST 기준
  판매기간/ACTIVE/비숨김) 구독자에게 푸시 발송. 단순 수정은 알림 안 함.

운영에서 VAPID 키 교체 원하면 .env.production 에 VAPID_* 설정(없으면 기본키 사용).
2026-05-27 00:17:54 +09:00
chpark 1b0d652282 fix(orders/new): 판매 마감 품목 담기/발주 클라이언트 차단 (2중 방어)
Deploy momo-erp / deploy (push) Successful in 1m54s
페이지를 띄워둔 채 마감 시각이 지나면 목록은 그대로라 담기/발주가 됐던 문제.
- isSaleClosed(): SALE_END_DATE(KST 벽시계) 기준 마감 판정 (자정정각=종일 규칙 동일).
- 담기(addManyToCart)/발주요청(submitOrder) 직전 마감 재확인 후 경고+차단.
- 카드/리스트에 '판매 마감' 상태 표시 + 30초 틱으로 idle 중에도 자동 전환.
- 백엔드 orders/save 의 마감 재검증과 합쳐 2중 차단.
2026-05-27 00:11:07 +09:00
chpark 83cb93cb76 fix(orders): 출고 재고 체크는 전체 창고 합 기준 — 총 재고 초과만 차단
Deploy momo-erp / deploy (push) Successful in 1m57s
직전 커밋에서 관리자/무제한은 총 재고도 초과 가능하게 했으나, 요구사항은
"총 재고보다 많이는 못 나가되 기준 창고가 비어도 총 재고가 충분하면 출고 가능".

- orders/save: 재고 차단을 다시 전체 창고 합(stock_qty) 기준으로 모두에게 적용.
  기준 창고(거래처 default_wh)가 0 이어도 총 재고가 충분하면 통과.
- orders/new(카드/리스트): 담기 한도/품절 표시를 전체 창고 합 기준으로 환원.
  unlimitedQty 는 1회 발주 한도(maxQ)만 무시, 총 재고는 못 넘김.

실제 차감(approve)은 기준 창고에서 빼며 부족분은 음수로 떨어지고(제약 없음 확인),
관리자가 재고 이동으로 정리. 판매 마감 KST 재판정/타임존 수정은 유지.
2026-05-26 23:56:10 +09:00
chpark bbd4f84a12 fix(orders): 음수 재고 출고 허용(관리자/무제한) + 판매 마감 KST 재판정
Deploy momo-erp / deploy (push) Successful in 4m6s
- items/list: 마감 비교를 NOW() → (NOW() AT TIME ZONE 'Asia/Seoul') 로 변경.
  DB 서버 TZ 가 UTC 면 마감 지난 품목이 9시간 더 노출되던 문제 해결.
- orders/save: 출고요청 시 판매기간 KST 기준 서버 재체크 — 마감 지난 품목이
  장바구니에 남아 전송돼도 차단 + 경고 메시지.
- orders/save & orders/new: 관리자/무제한(unlimited_qty='Y') 은 재고 초과(음수)
  출고 허용. 총 재고가 남아 있으면 기준 창고가 비어도 출고 후 재고이동으로 정리.
  (실제 차감 approve 는 이미 음수 허용) 카드/리스트 품절표시도 unlimited 는 해제.
2026-05-26 23:29:27 +09:00
chpark a06a5d551e feat(header,procurement): 관리자 토글 가드 강화 + 매입발주 발주지사(HQ/KIMPO) 셀렉트
Deploy momo-erp / deploy (push) Successful in 4m27s
- header: 메뉴 변환 버튼은 authority_master "관리자" 권한그룹 멤버만 노출. user_type='A' 만으로는 부족 (실무자 다수에 부여돼 있음). /api/auth/me 가 isMasterAdmin 플래그 반환.
- procurements: 발주서에 발주지사 셀렉트 추가 (기준 명세표 마스터 사용 — HQ/KIMPO 등). 통계/계산서 발행 시 지사별 집계 가능.
2026-05-23 01:36:44 +09:00
chpark a40bb609e3 fix(items/list): "5월 22일 마감" 발주는 그 날 종일 노출 — 자정 정각이면 23:59:59로 해석
Deploy momo-erp / deploy (push) Successful in 2m14s
증상: sale_end_date='2026-05-22 00:00:00' 인 품목들이 5월 22일 0시 1분부터
      출고요청 화면에서 사라짐. 사용자 의도는 "5월 22일 종일 마감".

원인: NOW() <= sale_end_date 비교가 자정 정각을 그 날의 끝이 아니라
      그 날의 시작으로 해석.

수정: CASE 로 종료시각이 자정 정각이면 (= 시간 명시 안 함)
      그 날 23:59:59 까지 노출. 시간 명시(예: 22:00)는 그 시각까지 정확히.

      NOW() <= CASE
        WHEN sale_end_date = date_trunc('day', sale_end_date)
          THEN sale_end_date + INTERVAL '1 day' - INTERVAL '1 second'
        ELSE sale_end_date
      END

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 11:57:30 +09:00
chpark 1a209ceb29 feat(daily-order-inventory): 창고 × 품목 매트릭스 뷰로 전환
Deploy momo-erp / deploy (push) Successful in 1m53s
이전: 품목 한 줄에 [발주수량 합계 + 전체창고 재고합계] 표시.
변경: 창고별 재고 현황의 "품목 가로" 패턴 차용 — 헤더=품목(가로), 좌측=창고(세로).
      각 셀에 그 창고의 [발주수량 / 재고수량] 두 줄.

API:
- WAREHOUSES + ITEMS(STOCK/ORDER 매트릭스) 형태로 응답
- 발주수량 산정:
  • APPROVED/INVOICED/PAID 발주는 momo_stock_moves OUT 이력의 실제 출고 창고 기준
  • REQUESTED 발주(아직 출고 전)는 거래처 default_wh_objid 로 가상 배정 (fallback WH001)
- 재고수량은 momo_stocks 현재값 그대로

UI:
- 상단 [전체 합계] 두 줄(발주/재고) — 모든 창고 합산
- 각 창고(WH001~WH007) 2행씩 — 발주수량 / 재고수량
- 음수 재고는 적색 강조 (창고별 재고 현황과 동일 톤)
- 엑셀: 창고별 행 + 분류(발주/재고) + 품목 컬럼

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:21:08 +09:00
chpark af6726f2b6 feat(orders/approve): 출고 시 재고 부족 검사 제거 — 음수 재고 허용
Deploy momo-erp / deploy (push) Successful in 3m54s
요구: 거래처 default 창고에 재고가 모자라도 그대로 차감해서 출고 진행.
      일자별 발주/재고 + 창고별 재고 현황에서 음수(-) 로 표시되면 관리자가
      다른 창고에서 부족 창고로 수동 재고 이동 처리하는 운영 정책.

변경:
- "재고 부족: 현재고 N, 요청 M" 차단 + ROLLBACK 제거 → 그대로 차감
- 재고 row 자체가 없던 품목은 새 row(qty=-N) INSERT
- itemsRes SQL 에 kind='ITEM' AND item_objid IS NOT NULL 가드 추가
  (택배/용차/환불 라인이 잘못 차감되는 잠재 버그도 같이 차단)
- stock_moves OUT 이력은 동일하게 음수 qty 로 기록

음수 재고 발생 시 운영 흐름:
  1) 다른 창고에 같은 품목 재고 확인
  2) 관리자 패널 → 재고 이동 (오프라인 물리 이동 + 시스템 등록)
  3) 부족 창고 재고가 0 이상으로 복구

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:13:10 +09:00
chpark 2209863ab8 feat(orders/admin): 기본 조회 필터 EDITABLE 에 입금완료(PAID) 포함
Deploy momo-erp / deploy (push) Successful in 1m58s
이전 commit(474cf79)에서 PAID 도 수정 가능해졌으므로, 기본 노출 대상에 포함.
- statuses: ["REQUESTED", "APPROVED"] → ["REQUESTED", "APPROVED", "PAID"]
- select option 라벨: "출고요청+출고완료" → "출고요청+출고완료+입금완료"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:48:58 +09:00
chpark 474cf79632 feat(orders/admin): 입금완료(PAID) 발주도 품목/택배/용차 추가·수정 허용
Deploy momo-erp / deploy (push) Successful in 1m57s
요구: 출고처리(/m/admin/orders) 에서 입금완료 후에도 admin 이 품목과
      택배/용차 라인을 추가/수정할 수 있어야 함. 계산서 발행 전 일괄 정정 케이스.

변경:
- /api/m/orders/items/add: admin 분기 신설 → REQUESTED/APPROVED/PAID 허용
  (USER 는 기존대로 REQUESTED/APPROVED 까지)
- /api/m/orders/items/update: admin 분기에 PAID 포함
- items/update 의 재고 ± 동기화 분기에 PAID 도 포함 — APPROVED 와 동일하게
  momo_stock_moves 의 OUT 이력으로 wh_objid 찾아 차이만큼 재고 조정
- /m/admin/orders StatementPreview: editable 에 PAID 도 true 처리
  → [+ 품목 추가] / 택배·용차 / 수량 입력칸 노출

INVOICED(계산서 발행) / CANCELLED 는 여전히 잠금 — 한 번 더 단계 진행하면
정정 불가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:29:31 +09:00
chpark e1618fa9d2 fix(orders/admin): 자동 list 갱신의 stale 락 결과를 클라이언트에서 보정
Deploy momo-erp / deploy (push) Successful in 1m54s
증상: 발주 15 → 16 → 17 빠른 클릭 후 본인 화면에 16(또는 더 이전 발주)에 여전히
      "내가 수정 중" 표시. 다른 사용자 화면은 17만 락으로 정상.

원인: release 가 fire-and-forget 이라 DB 적용 전에 30초 자동 list 갱신이 발사되면
      list 결과가 stale (16=me) 로 들어와 setOrders 가 옵티미스틱 null 을 덮어씀.

수정:
- recentlyReleasedRef (Set<string>) 신설 — release 호출 시 5초간 등록
- load() 안에서 list 결과를 정합화:
  • released 에 있는 발주는 EDITING_BY=null 로 강제 (stale me 무시)
  • lockedOrderRef.current 와 일치하는 발주는 me 로 보정 (자기 락 보호)
- 5초 후 자동으로 set 에서 제거 → 그 이후엔 정상 DB 반영

이전 heartbeat fix(bdccaa0) 와 합쳐 race 양쪽 다 차단.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 00:06:55 +09:00
chpark bdccaa05c1 fix(orders/lock): heartbeat 가 빈 락을 다시 잡는 race condition 차단
Deploy momo-erp / deploy (push) Successful in 1m57s
증상: 발주 15 → 16 클릭 시 본인 화면에 15, 16 모두 "내가 수정 중" 표시.
      (다른 사용자 화면에는 16만 정상 표시 — DB 가 잠시 둘 다 me 로 오염됐다가
       TTL 2분 후 알아서 풀림)

원인: heartbeat 와 acquire 가 같은 분기를 공유.
      "빈 락이거나 자기 락 → UPDATE editing_by=me, editing_at=NOW()" 로 처리.
      release(15) 직전 발사된 heartbeat(15) 가 release 응답보다 늦게 도착하면
      빈 락을 자기 락으로 다시 잡아버림.

수정: heartbeat 액션을 분리.
      - "UPDATE editing_at = NOW() WHERE objid = $1 AND editing_by = $2 AND alive"
      - 자기 락이 살아있을 때만 갱신, 빈 락은 절대 잡지 않음
      - rowCount=0 이면 409 + 현재 락 보유자 정보 반환
acquire 분기는 그대로 — 빈 락이거나 자기 락이면 신규 잡기.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:51:20 +09:00
chpark 8e29a1f9da fix(orders/admin): 락 변경 즉시 리스트 반영 — 옵티미스틱 업데이트
Deploy momo-erp / deploy (push) Successful in 1m56s
문제: 발주 A 클릭 → B 클릭 시 A 의 release/acquire 응답을 기다리지 않아
       리스트는 30초 자동 갱신 전까지 stale (A 에 여전히 "내가 수정 중" 표시)

수정:
- 이전 락 release 시 setOrders 로 previousLocked 행의 EDITING_BY 즉시 null
- 새 락 acquire 성공 시 activeId 행의 EDITING_BY 즉시 본인으로 세팅
- 다른 사람 락이라 거부된 경우도 그 정보로 즉시 업데이트
- 30초 자동 갱신은 안전망(누락된 변화 동기화)으로 유지

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:28:10 +09:00
chpark 585b7d4577 feat(orders/admin): 발주 리스트 30초 자동 갱신 + 본인 락은 초록 ✏️ "내가 수정 중"
Deploy momo-erp / deploy (push) Successful in 1m56s
- load() 를 30초 setInterval 로 주기적 호출 → 누가 새로 락을 잡았는지 실시간 반영
- 카드/테이블 row 모두:
  • 본인 락 (EDITING_BY === myUserId): 초록 배경 + ✏️ "내가 수정 중"
  • 다른 사람 락: 빨강 배경 + 🔒 보유자명 (기존)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:22:14 +09:00
chpark 9b36ae64a5 fix(orders): list/detail/items/cancel — 편집 락 컬럼 자동 증설 추가
Deploy momo-erp / deploy (push) Successful in 1m56s
이전 커밋(6be1633)에서 SQL이 momo_orders.editing_by / editing_at 을 참조하지만
운영 DB 에 컬럼이 없으면 list 쿼리 전체가 깨져 발주 리스트가 0건으로 표시됨.
(컬럼 자동 증설은 lock 라우트에만 있었는데, list 가 먼저 호출되니 시점이 안 맞음)

해결: list/detail/items.add/items.update/cancel 5개 라우트 진입부에
ALTER TABLE IF NOT EXISTS 로 editing_by/editing_at 컬럼 자동 증설.
컬럼이 이미 있으면 no-op. 첫 호출 1회만 ALTER 호출.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:14:54 +09:00
chpark 6be1633a31 feat(orders): 발주 단건 편집 락 — 동시 수정 충돌 방지
Deploy momo-erp / deploy (push) Successful in 1m57s
DB:
- momo_orders.editing_by (TEXT), editing_at (TIMESTAMP) — 자동 증설
- /api/m/admin/orders/lock 신규: action=acquire|heartbeat|release
- TTL 2분 (페이지가 죽거나 비정상 종료되어도 2분 후 자동 해제)

거래처 측 보호 (양방향 락):
- /api/m/orders/items/add, items/update, cancel : 락이 살아있고 본인 락이 아니면 409
  "○○ 담당자가 수정 중입니다" 메시지 반환
- /m/orders DetailModal: editable=false + 상단 적색 배너로 차단 안내

출고관리 (/m/admin/orders):
- activeId 변경 시 이전 락 release → 새 락 acquire (useEffect)
- 30초마다 heartbeat — 락 갱신
- 헤더 옆에 [✏️ 편집 가능] / [🔒 ○○ 수정 중] 배지
- 다른 사람 락이면 우측 미리보기 영역 pointer-events-none + opacity-60
- 발주 리스트 (테이블/카드) 행에 🔒 + 보유자명 표시
- beforeunload + 컴포넌트 언마운트 시 sendBeacon 으로 release

list/detail API: 편집중 컬럼 두 개 노출 (EDITING_BY / EDITING_BY_NAME) — 2분 TTL CASE 절로 만료된 락은 자동 NULL

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:09:44 +09:00
chpark a7fa932f9f feat(charter): 거래처별 기본 용차비 자동 셋팅 + 택배/용차 거래처 수정 차단
Deploy momo-erp / deploy (push) Successful in 1m56s
DB:
- user_info.default_charter_use (CHAR 'Y'/'N'), default_charter_price (INTEGER)
- /api/admin/users/detail: ALTER TABLE IF NOT EXISTS 로 자동 증설 + SELECT 노출
- /api/admin/users/save: 두 필드 UPDATE
- /api/auth/me: 로그인 사용자의 defaultCharterUse/Price 응답에 포함

UI:
- admin-panel/user-form: [기본 용차비 사용] 체크박스 + [금액] 입력 (사용 체크 시만 활성)
- /m/orders/new: 카트에 품목이 들어오는 순간 default_charter_use='Y' 거래처는 용차 라인 자동 추가
- /m/orders/new: 거래처는 카트 안 택배/용차 라인 수정/삭제 불가 (read-only 표시)
                [+ 택배 추가] [+ 용차 추가] 버튼도 admin 만 노출
- /m/orders DetailModal: canEditExtra=false 로 거래처 택배/용차 수정/삭제 차단
                          (출고관리 /m/admin/orders 에서만 수정 가능)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:42:55 +09:00
chpark 0aa8ce9025 fix(orders/new): 첫 클릭에도 재고 초과 경고 즉시 표시 — setCart 콜백 안 warned 변수 제거
Deploy momo-erp / deploy (push) Successful in 1m58s
원인:
- addManyToCart 가 setCart 함수형 업데이트 안에서 외부 변수 warned 에 값 세팅
- React 18 batched updates 로 콜백 실행이 한 박자 늦어 if(warned) 가 false → 첫 클릭 경고 누락
- 두 번째 클릭 때 이미 콜백이 실행돼 warned 가 true 보여 경고 표시 — 사용자가 본 현상

수정:
- 함수형 업데이터 진입 전에 cart 를 동기적으로 읽어 newQty/limit 비교
- 초과면 Swal 띄우고 return — setCart 호출 자체를 안 함 (장바구니 변경 없음)
- 통과 시에만 setCart 로 카트 갱신
- updateQty, setQty 도 동일 패턴(stale-closure 차단도 함수형 업데이터 밖에서)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:08:07 +09:00
chpark e3e4919933 fix(orders): 택배 전용 품목은 재고 무관하게 발주/수정 가능
Deploy momo-erp / deploy (push) Successful in 1m58s
프론트(addManyToCart)는 이미 isDelivery → effStock=Infinity 로 우회했지만
백엔드 3곳에서 stock 체크로 거부 — 사용자가 담아도 출고 요청이 4xx 로 실패.

- /api/m/orders/save line 117: requires_delivery='Y' 면 재고 검증 우회
- /api/m/orders/items/update line 97: 동일 처리 (수량 수정 시)
- /api/m/orders/items/add line 87: 동일 처리 (발주에 품목 추가 시)
- 세 곳 모두 select 절에 requires_delivery 컬럼 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:02:30 +09:00
chpark 1396ac2ed7 fix(orders/new): 재고/한도 초과 경고를 가운데 모달로 통일
Deploy momo-erp / deploy (push) Successful in 1m55s
기존: 카트 +/- 시도는 우상단 토스트, 신규 담기는 가운데 모달 — 일관성 없음.
변경: toastLimit 함수도 Swal.fire 가운데 모달로 변경. 메시지도 명확하게.
- 재고 초과: "재고 수량 초과 — 현재 재고 N개 보다 많은 수량은 출고 요청할 수 없습니다."
- 한도 초과: "1회 발주 한도 초과 — 1회 최대 N개까지 발주 가능합니다."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:59:17 +09:00
chpark 2a84b74488 fix(orders/new): 재고 초과 수량은 아예 담기지 않게 차단 (clamp 제거)
Deploy momo-erp / deploy (push) Successful in 1m55s
기존: 카드/리스트의 [+ 담기] 클릭 시 입력값을 limit 으로 clamp 해서 그대로 담겼음.
변경: 입력값을 그대로 addManyToCart 에 넘김 → limit 초과 시 거부 + Swal 경고
      ("재고 부족" / "1회 발주 한도 초과") + 입력칸은 그대로 두어 사용자가 직접 정정.

- 카드 input onChange의 즉시 clamp 제거 (입력은 자유롭게 표시)
- 카드 + 담기 onClick / Enter: Math.min(limit, val) 제거
- 리스트 동일 패턴 적용
- ListView 의 onLimitToast prop 미사용으로 정리

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:55:21 +09:00
chpark baa2b72169 style(orders/new): 발주 장바구니 수량 입력칸 확대 — w-12 → w-20, text-base font-extrabold
Deploy momo-erp / deploy (push) Failing after 8s
3~4자리 수량(230, 1000 등)이 잘리지 않도록 넓힘. +/- 버튼도 살짝 키움.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:52:46 +09:00
chpark 84ef9e5179 style(orders/new): 카드 사진 축소 + 품목명/단가/재고 폰트 확대
Deploy momo-erp / deploy (push) Successful in 1m54s
- 사진 비율: aspect-square → aspect-[4/3] (세로 축소)
- 품목명: text-[11px] → text-sm sm:text-base font-bold
- 단가: text-xs sm:text-sm → text-base sm:text-lg font-extrabold
- 재고: text-[10px] font-semibold → text-sm sm:text-base font-extrabold

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:51:19 +09:00
chpark 6407954fc1 style(orders/new): 카드 마감일시 폰트 확대 — text-[9px] → text-sm sm:text-base font-extrabold
Deploy momo-erp / deploy (push) Successful in 1m56s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:47:59 +09:00
chpark bbabccf70e fix(orders/m): 거래처 발주 상세 모달 — [택배 추가]/[용차 추가] 버튼 삭제
Deploy momo-erp / deploy (push) Successful in 2m4s
거래처(일반 사용자)는 발주 수정 시 택배·용차 라인을 새로 추가할 수 없게 함.
이건 출고 담당자(/m/admin/orders) 가 처리. 기존 라인의 수량/단가 수정은 그대로 유지.
- DetailModal 두 버튼 + addNewExtra 함수 제거
- 미사용 import (Truck, Package) 정리

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:43:09 +09:00
chpark 1049e9b776 chore(orders/new): 보기모드 토글 라벨 — 카드/리스트 → 상세보기/간단히보기
Deploy momo-erp / deploy (push) Successful in 2m24s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:38:51 +09:00
chpark 756924354b fix(orders/new): 카드 수량 입력칸 확대 + 담기 버튼 컴팩트화
Deploy momo-erp / deploy (push) Failing after 4m21s
- input width: w-9 (36px) → flex-1 min-w-0 (가용 폭 전부), 폰트도 키움
- 담기 버튼: flex-1 → h-7 px-2.5 (텍스트 폭에만 맞춰 축소)
- 3~4자리 수량(800~9999) 입력해도 잘리지 않음

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:38:22 +09:00
chpark b34121b597 feat(sale-period): 판매기간 분 단위 + 재고초과 차단 + 모바일 2열 카드
Deploy momo-erp / deploy (push) Successful in 2m1s
- momo_items.sale_start_date/sale_end_date DATE → TIMESTAMP 자동 승격
  (items/list ensureColumns 에 information_schema 체크 후 ALTER)
- items API (list/save/bulk-sale-range/daily-order-inventory): ::date → ::timestamp,
  CURRENT_DATE → NOW(), 응답 포맷 'YYYY-MM-DD HH24:MI'
- 품목 관리 편집/일괄적용 UI: <input type="date"> → datetime-local
  + toLocal 헬퍼로 응답값 "YYYY-MM-DD HH:MM" → "YYYY-MM-DDTHH:MM" 변환
- 출고 요청 카드 그리드 모바일 2열로 변경 + 카드/리스트에 판매 종료일시 표시
- 재고/한도 초과 수량 입력 시 즉시 clamp + 우상단 토스트 경고
  (카드/리스트 inline qty input onChange, setQty/updateQty 양쪽)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:17:47 +09:00
chpark 5ba9b9f04e feat(login): 로그인 화면에서 홈(랜딩)으로 이동 — 좌측 로고 + 우측 상단 홈으로 버튼
Deploy momo-erp / deploy (push) Successful in 1m57s
- 좌측 상단 MOMO DISTRIBUTION 로고를 <Link href="/"> 로 감싸 클릭 시 랜딩 이동
- 우측 폼 패널 상단에 [홈으로] 고정 버튼 추가 (모바일에서도 노출)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:21:52 +09:00
chpark 49352feb4a feat(landing): Play 스토어/iOS/PC 설치 섹션 + 개인정보처리방침 푸터
Deploy momo-erp / deploy (push) Successful in 1m57s
- 랜딩에 INSTALL 섹션 — Android(Play 스토어 다이렉트), iPhone(홈 화면 추가), PC(웹) 3장 카드
- /install 안드로이드 가이드 상단에 Play 스토어 다운로드 CTA(가장 쉬운 방법) 추가
- 푸터에 개인정보처리방침/계정 삭제/앱 설치/Play 스토어 링크 + mailto/tel 활성화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:35:39 +09:00
chpark 25aa33c499 feat(daily-order-inventory): 출고/정산 — 일자별 발주/재고 메뉴
Deploy momo-erp / deploy (push) Successful in 1m56s
- 새 페이지 /m/admin/daily-order-inventory: 선택 일자의 판매가능 품목 + 발주수량 합계 + 전체 재고
- 새 API /api/m/admin/daily-order-inventory: sale_start_date~sale_end_date 필터 + ORDER_QTY/STOCK_QTY 집계
- /api/menu/route.ts: ensureMomoMenus — 9000405 menu_info + 출고관리(9000401) 권한 master 자동 매핑

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:32:28 +09:00
chpark 6ddeca316c fix(inbounds): 입고 등록 버튼 — 발주요청/입고완료 상태에도 노출
Deploy momo-erp / deploy (push) Successful in 1m54s
이전: STATUS === 'PAID' || 'PARTIAL' 일 때만 [입고 등록] 버튼 표시
지금: REQUESTED + PARTIAL + PAID + RECEIVED 모두 표시.
- 입금 의존성 해제(앞선 커밋)와 일관성 맞춤.
- RECEIVED 상태에서도 라인 보정 입력이 가능하도록 버튼 유지 + '입고 완료' 배지 같이 표시.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:31:38 +09:00
chpark 1eba9aab32 fix(admin/orders): 거래명세표 컬럼 폭 재조정 — 품명 넓게, 수량·비고 좁게
Deploy momo-erp / deploy (push) Successful in 1m53s
* 수량 컬럼: w-20 → w-14 (header), QtyInput w-16 → w-11
* 비고 컬럼: w-32 → w-20
* 품명은 무제한 폭으로 둬서 줄어든 만큼 자동 확장

화면/이미지 공유/인쇄 모두 동일하게 적용 (캡처 영역 내 변경).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:29:25 +09:00
chpark d95a736701 feat(install): /install 페이지 — 안드로이드/아이폰/PC 별 PWA 설치 가이드
Deploy momo-erp / deploy (push) Successful in 4m25s
노인 사용자(거래처 사장님 등) 도 따라할 수 있도록 큰 글씨 + 단계별 안내.
User-Agent 자동 감지로 해당 기기 가이드 우선 표시, 탭으로 다른 기기 전환 가능.

* 안드로이드: Chrome → 앱 설치 배너 → 4단계
* 아이폰: Safari → 공유 → 홈 화면에 추가 → 5단계 (사파리 필수 경고 강조)
* PC: QR 코드 (휴대폰 카메라로 즉시 안내 페이지 이동)

모바일 로그인 화면 하단에 "📱 휴대폰 홈 화면에 앱처럼 설치하는 방법" 링크 추가.
middleware publicPaths 에 /install 추가 (비로그인 접근 허용).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:58:36 +09:00
chpark 7a712c164e feat(privacy): /account-deletion 페이지 — Play 데이터 보안 필수 URL
Deploy momo-erp / deploy (push) Successful in 2m4s
Google Play 데이터 보안 섹션에서 '계정 URL 삭제' 필드에 넣을 페이지.
앱 내 self-service 삭제가 없는 B2B 앱이므로 이메일/전화 요청 절차를
명시한 정적 안내 페이지로 처리.

* 삭제 요청 방법 (이메일/전화)
* 처리 기간 (14일 이내)
* 삭제되는 데이터 vs 법령상 보관되는 데이터
* /privacy 와 동일하게 middleware 인증 면제

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:09:01 +09:00
chpark 45af622afb chore(security): .gitignore — 안드로이드 서명 키/번들 차단
Deploy momo-erp / deploy (push) Successful in 1m55s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:18:40 +09:00
chpark 2419ded4ac fix(android): assetlinks.json — PWABuilder 가 발급한 실제 서명 키 SHA-256 으로 교체
Deploy momo-erp / deploy (push) Successful in 2m1s
PWABuilder 가 .aab 빌드 시 생성한 keystore 의 SHA-256 으로 갱신.
Play App Signing 활성화 후 Play 가 별도 서명 키를 발급하면 그 SHA-256 도
배열에 추가해 두 개 다 인정되도록 해야 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:15:29 +09:00
chpark b58d7e6821 feat(android): /.well-known/assetlinks.json — TWA Digital Asset Links
Deploy momo-erp / deploy (push) Successful in 2m1s
Play Store TWA(Trusted Web Activity) 풀스크린 동작에 필수. 안드로이드 앱
패키지 com.momotogether.app 의 서명 SHA-256 을 momotogether.com 도메인이
인정한다고 선언.

* 현재 SHA-256: 로컬 업로드용 키(android.keystore in ~/Downloads/momo-twa)
* Play App Signing 이 별도 서명 키를 발급하면 그 SHA-256 도 배열에 추가 필요

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:59:53 +09:00
chpark 80f490e8d6 feat(privacy): /privacy 공개 페이지 추가 — Play Store 등록용 개인정보 처리방침
Deploy momo-erp / deploy (push) Successful in 5m55s
- /privacy 라우트: 인증 미들웨어 면제. 시행일/수집항목/보유기간/제3자/안전성/연락처
- 추적·광고 SDK 없이 ERP 운영 데이터만 다루는 자체 서비스 기준으로 작성
- middleware publicPaths 에 /privacy 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:41:58 +09:00
chpark 326b790e4a fix(inbounds): 발주요청/입고완료 발주도 입고 입력 가능
Deploy momo-erp / deploy (push) Successful in 1m52s
editable 조건을 PAID/PARTIAL 만 → REQUESTED/PARTIAL/PAID/RECEIVED 로 확장.
OPEN(작성중)/CANCELLED 만 차단. 입금 의존성은 이미 해제됐고, 이번 변경으로
'발주요청 상태라 입고 입력이 불가합니다' 차단 메시지 제거.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:55:53 +09:00
chpark 461164c397 feat(procurement): 입금/입고 순서 의존성 해제 — 발주요청 즉시 입고 가능, 입고완료 후 입금 가능
Deploy momo-erp / deploy (push) Successful in 1m53s
신규 업무 흐름: 매입발주 작성 → 발주요청 → (순서 무관) 입고 / 입금
- 발주요청(REQUESTED) 단계에서 입금 처리 없이 바로 입고 가능
- 입고완료(RECEIVED) / 입고중(PARTIAL) 건도 그 이후에 입금 처리 가능
- 이미 입금완료(PAID) 인 발주에 추가 입고가 들어와도 상태는 PAID 유지

변경 파일:
- proc-payments/confirm: 입금 허용 상태 REQUESTED → REQUESTED/PARTIAL/RECEIVED
- proc-payments/list: 노출 상태 (REQUESTED,PAID) → (REQUESTED,PARTIAL,RECEIVED,PAID)
- inbounds/page: 기본 필터 PAID_OR_PARTIAL → INBOUNDABLE (REQUESTED+PARTIAL+PAID)
  드롭다운에 '발주요청만' 옵션 추가, 안내 문구 갱신
- inbounds/save: 입고 후 상태 갱신 시 PAID 면 덮어쓰지 않음

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:50:33 +09:00
chpark 209b47c7f2 fix(admin): 거래명세표/발주서 캡처 영역 폰트 사이즈 +2px 상향
Deploy momo-erp / deploy (push) Successful in 1m55s
레이아웃 영향 없는 범위에서 가독성 ↑:
- text-[11px] → text-[13px]
- text-[12px] → text-[14px]
- 작은 배지/REMARK 등은 기존 비율 유지 (9→11, 10→12)

화면/이미지 공유/인쇄 동일하게 굵고 큰 텍스트로 나옴.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:40:45 +09:00
chpark dc05d48c82 fix(admin): 거래명세표/발주서 전체 bold + 매입발주서 좌:우 비율·품명폭 조정
Deploy momo-erp / deploy (push) Successful in 1m53s
- 거래명세표(admin/orders) 캡처 영역 전체 font-bold [&_*]:font-bold — 가독성 ↑
- 발주서(admin/procurements) 캡처 영역도 동일하게 bold 적용
  화면/이미지 공유/인쇄 모두 굵게 표시
- 매입 발주서 관리 좌:우 레이아웃: 360px → 480px (왼쪽 리스트 더 넓게)
- 발주서 품명 컬럼 width 220px 로 제한 (단위/수량/단가/금액 열에 공간 양보)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:32:24 +09:00
chpark 73317166ab feat(admin): 동적 리스트 select → SearchableSelect 로 통일 (결과내 검색)
Deploy momo-erp / deploy (push) Successful in 1m53s
긴 동적 리스트(거래처/창고/품목/공급업체/매입발주)의 native <select> 를
검색 가능한 SearchableSelect 로 교체. 항목 50~100건이라도 타이핑으로 즉시 필터.

대상:
- admin/orders 출고처리: 거래처 변경
- admin/inventory: 검색 창고 / 매입입고 모달(창고+품목) / 재고이동 모달(출발+도착+품목)
- admin/inbounds/new: 매입발주 / 공급업체 / 입고창고 / 품목
- admin/procurements/new: 품목
- admin/inventory/history: 창고 필터

상태/유형 등 짧은 고정 옵션 select 는 native 그대로 (드롭다운 클릭 즉시 선택이 빠름).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:29:26 +09:00
chpark 9e4d506939 fix(admin/orders): 좌:우 비율 2:3, 좌측 리스트 압축 + 거래명세표 품명 한 줄 유지
Deploy momo-erp / deploy (push) Successful in 1m56s
- 외곽 grid 50:50 → 2fr:3fr (좌 40 / 우 60). 거래명세표 패널 폭 확보.
- 좌측 발주 리스트: 패딩/폰트 축소(px-1.5, text-[11px]), 합계 whitespace-nowrap, 업체 max-w-[100px].
- 우측 거래명세표 품명 td: whitespace-nowrap — 2줄 줄바꿈 방지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:20:43 +09:00
chpark adff1347c9 fix(admin): 관리자 패널 '← 사용자' 링크 404 — /dashboard → /m/orders/new
Deploy momo-erp / deploy (push) Successful in 6m25s
- admin-panel 헤더 '← 사용자' 링크가 삭제된 /dashboard 로 가서 404 발생
- 동일 패턴: login 페이지 fallback redirect 도 /m/orders/new 로 정정

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:04:49 +09:00
chpark 3c73c5a47a fix(admin/orders): 출고처리 — 세금계산서 발행 버튼 제거 + 기본 검색 상태 '출고요청+출고완료'
Deploy momo-erp / deploy (push) Successful in 2m2s
- 출고처리 우측 상세에서 [세금계산서 발행] 버튼 제거 (계산서(면세) 만 유지)
  업무 흐름: 출고요청 → 출고완료 → 입금완료 → 계산서 발행 → 전자세금계산서.
  입금완료 후의 발행은 계산서 관리 메뉴에서 처리.
- 검색조건 기본값: 'EDITABLE' (= REQUESTED + APPROVED) 두 상태만 노출.
  드롭다운에 '출고요청+출고완료' 옵션 추가, 기존 '전체 상태'/개별상태 옵션 유지.
- orders/list API: statuses?: string[] (IN) 파라미터 지원 (status 단일은 기존대로).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 10:59:44 +09:00