파일 내용은 openpyxl 로 작성된 xlsx 포맷이지만
확장자만 .xls 였던 것을 실제 포맷과 맞춰 .xlsx 로 정정.
- 서버 다운로드 파일명 확장자 변경
- 프론트 fallback 파일명 변경
xls 파일을 "쓰는" 코드(xlwt 등)는 원래 없었음.
xlrd 는 입력 파일(.xls) 을 "읽는" 용도라 유지.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
콘텐츠 길이에 맞춰 열 너비를 계산해서 적용한다.
한글은 ASCII 폭의 약 2배로 가중치를 두고,
최소 10 · 최대 60 으로 클램프해 너무 좁거나 넓지 않게 한다.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 기본 선택값을 오늘 날짜로 미리 지정 (업로드 실행 버튼도 즉시 활성)
- 안내 문구를 "발주 데이터의 주문 날짜로 날짜를 선택해주세요." 로 수정
- 선택된 날짜 박스와 하단 버튼 사이 1.5rem 간격 확보
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
itemcode_db 의 single_items.sabangnet_code 가 비어 있거나
마스터에 등록되지 않은 상품(미등록 코드 / 세트 구성 단품 미등록)은
결과 엑셀의 상품코드[필수] 컬럼에 들어갈 값이 없으므로 제외한다.
- 폴백 시 sabangnet_code 자리에 내부 코드 채우던 동작 제거
- 엑셀 빌드 단계에서 사방넷 코드가 빈 행을 스킵하고 warning 로그
- success 로그에 excel_row_count / skipped_no_sabang_count 노출
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
기존 데이터는 "YYYY-MM-DD HH:MM:SS" 형식으로 저장되고
검색 쿼리도 "YYYY-MM-DD 00:00:00" 으로 문자열 비교하는데,
새 업로드는 custom_date(YYYY-MM-DD)를 그대로 저장해서
문자열 비교상 날짜 필터에 잡히지 않아
"DB 업로드가 안 된 것처럼" 보이는 문제 발생.
달력에서 고른 날짜에 시간 00:00:00 을 붙여
"YYYY-MM-DD HH:MM:SS" 로 정규화 저장한다.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 주문 날짜(custom_date) 형식 검증을 진입부로 이동 (400 응답)
- 엑셀 파싱/템플릿 컬럼 누락은 500이 아닌 400으로 분리
- 빈 행 자동 스킵으로 빈 Order 레코드 저장 방지
- safe_int_quantity 헬퍼 도입: 수량/세트 구성수량의 None·비숫자·
'1.0' 같은 문자열도 견고하게 정수 변환
- itemcode_db 엔진 생성/조회 실패 시 단품 처리로 폴백하고
치명적 오류 대신 warning 로그로 기록
- 세트 구성 단품이 single_items 에 없을 때 보강하여 결과 행 누락 방지
- 마스터 미등록 상품코드를 모아 warning 로그로 가시화
- 완료 시 단품/미등록 코드 수를 success 로그에 함께 기록
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
modal-overlay 클래스에 CSS 정의가 없어 모달이 항상 표시되는
버그를 수정: 기존 .modal/.modal.show 패턴으로 교체하고,
배경 클릭 시 모달이 닫히는 동작도 추가.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CS_RETURN_REQUEST_URL 기본값을 http://dbx-corm:8002/api/return/request 로
(docker 컨테이너 간 통신, 옛 127.0.0.1:8001 폐기).
- httpx 요청에 X-Service-Token 헤더 첨부 (CORM AuthGuard 우회용).
INTERNAL_SERVICE_TOKEN env 가 있을 때만 첨부.
- .env.example 에 두 항목 안내 추가.
- index.html: profile-name-block 제거. 이름은 이메일 span 의 title(hover tooltip)로 보존.
- app.js: 이제 표시하지 않는 user-name 관련 코드 정리.
- style.css: profile-email 흰색 + 굵게, 로그아웃 버튼도 흰색 + 어울리는 반투명 배경.
- read_root() 가 세션 미인증 시 dbx-main /login?next=/orderlist/ 로 302.
OMS 는 더 이상 자체 로그인 UI 를 가지지 않는다.
- index.html: #login-screen 블록 제거, dashboard 만 렌더.
- 우측 상단 프로필 영역을 메인 페이지 스타일로 개편:
이름 + 이메일 + 아바타(Google picture URL, 폴백 아이콘) + 로그아웃 텍스트 버튼.
- main.py 가 세션의 user_name/user_email/user_picture 를 HTML placeholder 로 치환.
- app.js checkAuth() 단순화: 화면 토글 제거, 401 시 dbx-main 로그인으로 자동 이동.
- style.css 에 새 프로필 영역 CSS 추가.
Google 아바타가 보이려면 dbx-main 도 같이 user_picture 를 세션 top-level 에
저장하도록 수정됨 (dbx-main 별도 커밋).
Starlette Mount 가 FastAPI(root_path=...) 의 값을 mount 경로에 흡수해버려서
@app.get 라우트(/health/db)는 그대로지만 mount(/static)는 /orderlist/static
으로 등록되는 비대칭이 발생했다. NPM 이 /orderlist prefix 를 잘라서 백엔드로
보내면 /health/db 는 200 이지만 /static/css/style.css 는 404 가 났다.
해결: FastAPI 생성자에서 root_path 인자 제거. 대신 Dockerfile 의 uvicorn 명령에
--root-path "${APP_ROOT_PATH:-}" 를 추가해 ASGI scope 레벨에서만 root_path 가
세팅되도록 한다. 이러면 모든 라우트/마운트가 prefix 없이 등록되고 URL 생성
시에만 prefix 가 붙는다.
APP_ROOT_PATH 환경변수와 main.py 의 HTML 경로 치환 로직은 그대로 유지.
- SESSION_SECRET_KEY 가 .env 에 없으면 컨테이너 기동 단계에서 RuntimeError.
알려진 기본값(super-secret-key) 폴백 제거로 양쪽 secret 불일치 사고 방지.
- .env.example 의 SESSION_SECRET_KEY 안내 강화 (openssl 명령, dbx-main 동기화 언급).
dbx-main 의 SessionMiddleware max_age 가 8h(28800)인데 OMS 코드 기본값은 14d였다.
운영 .env 에 SESSION_MAX_AGE 가 빠지면 한쪽만 일찍 만료돼 재로그인 루프가 생길 수 있어
코드 기본값을 28800으로 통일한다.
.env.example 은 이미 SESSION_MAX_AGE=28800 으로 표기돼 있어 변경 없음.