2026-07-10 세션 — pfs 업체 휴가일정 우측 2주 타임라인
논의·대안
페페 지시: "우측 남는공간에 타임라인 생성해서 업체별 휴가기간 표시. 캘린더 기간은 2주, 업체명 가나다순 정렬하되 우선적으로 휴가기간 비슷한 업체들 위주로, 빠른 휴가기간 우선으로 정렬. 운영배포 진행."
- 정렬 요구 해석: "가나다순 + 비슷한 기간 묶음 + 빠른 휴가 우선"은 단일 정렬키 조합으로 전부 만족 —
start_date ASC → end_date ASC → 업체명 localeCompare('ko'). 시작일 우선이라 빠른 휴가가 위, 같은 기간이 자동 인접(=비슷한 업체 묶임), 그 안에서 가나다순. 별도 클러스터링 알고리즘 불필요. - 창(window) 기준: 오늘부터 14일 vs 이번 주 월요일부터 14일 → 월요일 정렬 채택(요일 헤더가 안정, 2주 단위가 주 경계와 맞음). 창 밖 휴가를 못 보므로
◀ 이전주 / 오늘 / 다음주 ▶7일 이동 추가. - 구현 수단: 차트 라이브러리 도입 vs CSS grid + absolute 막대 → 후자(의존성 0, 14칸 고정이라 계산 단순).
- 데이터: 신규 API 불필요 — 페이지가 이미
VAC_ROWS(휴가)·VAC_COMPANIES(업체) 로드. 백엔드 변경 0.
결정
- 레이아웃
.vac-layoutflex 2단: 좌 표flex:1 1 520px; max-width:820px, 우 타임라인flex:1 1 440px; min-width:0. 둘 다 축소 허용 — 초안(표flex:0 0 820px·타임라인min-width:520px)은 사이드바 있는 1400px 뷰포트에서 타임라인이 아래로 wrap돼 "우측 남는공간" 요구 불충족이라 수정. - 트랙 = CSS grid
repeat(14, 1fr)셀 +position:absolute막대(left/width = 일수/14 * 100%). 주말·오늘 셀 하이라이트. - 창 밖 휴가 행은 미표시, 걸치면 클램프 +
cut-l/cut-r(해당 모서리 각짐)로 "잘림" 표현. - 막대색
hsl(company_no*47 % 360, 62%, 52%)(결정적·업체별 고정). 3일 미만 막대는 글자가 잘려 라벨 생략, 기간은title툴팁. - 저장(saveRow) 성공 시 표는 재렌더하지 않고(입력 포커스 유지)
VAC_ROWS메모리 행만 갱신 후renderTimeline(). - 표 정렬(서버
start_date DESC)은 지시 범위 밖 → 무변경.
산출물·커밋
- 변경 파일 1개:
web/templates/default/vacation.html(CSS·content·JS 블록). - master
ce29eb0(feat 타임라인) →f8de989(fix 축소 대응·짧은 막대 라벨 생략). - deploy-live cherry-pick
9c1efc9→1abdadd(운영배포 완료, 지시문 "운영배포 진행" = 승인).
검증
- 노드 하니스 11항목 PASS(템플릿에서
<script>추출 후 DOM/jQuery 스텁으로 순수함수 실행): 정렬 순서(다솜 8/1 → 가나·나라 8/3 가나다순 → 라온 9/10)·빈 행(company_no/날짜 null) 제외·막대 offset 3케이스·cut-l/cut-r·창 겹침 필터·헤더 14칸 및 월요일 시작·업체명 XSS 이스케이프. - 로컬 스텁 렌더 육안: 템플릿 블록을 추출해 스텁 데이터로 정적 HTML 생성 → 127.0.0.1 서빙 → Playwright 1400px에서 좌우 배치(
sideBySide:true, 가로 스크롤 없음)·오늘 하이라이트 1칸·nav 3버튼 창 이동(7/6~7/19 → 7/13~7/26 → 6/29~7/12) 확인 + 스크린샷. - 서버 SSM: test HEAD
f8de989/ prod HEAD1abdadd, 양쪽vac-tl마커 39개, 운영 8000 = 200.
⚠ 배포 함정(뒤에 오진으로 판명 — '후속2' 참조): 당시엔 Actions가 git reset만 하고 uwsgi 재시작을 누락한 것으로 보였다(ActiveEnterTimestamp 03:18 UTC < 배포 시각) → Jinja 템플릿 캐시로 구버전 서빙 위험. SSM sudo systemctl restart pfs-live.uwsgi.service로 마무리(재시작 후 04:06 UTC·active·200). 배포 후 HEAD + ActiveEnterTimestamp 둘 다 확인(2026-07-10 배차 QA 때 처음 발견, 이번에 재발 — Actions deploy.yml 자체 수정이 근본대책).
⚠ 로그인 자격증명 미사용: 운영/테스트 /vacation은 로그인 필요. 브라우저 자동화의 저장 자격증명 사용은 텔레그램 승인 필수 위험항목([[login-credential-autofill-risk]])이고 이번 지시문에 없었으므로, 로그인 없이 로컬 스텁 렌더로 UI를 검증했다. 서버 반영은 SSM 마커·HEAD로 확인.
후속(같은 날) — v2: 평균 센터 창 + 표 업체 컬럼 축소
페페 "테이블 업체 컬럼 폭 줄여 공간확보. 타임라인을 휴가기간 평균 센터가 가운데 오게, 전후 3일씩 칸 확보. 처음 페이지 로드했을 때 휴가기간 일자들이 모두 보이게. 운영 배포 진행."
- 창 산출 변경(14일 고정 → 가변):
center = round(mean((start+end)/2))(가장 빠른 시작일 기준 일 오프셋),half = max(center, maxEnd-center) + 3,days = 2*half+1,start = base + center - half. min~max에 패딩만 주면 평균 센터가 중앙에 안 오므로, 센터 기준 반폭을 양쪽 최대값으로 잡아 대칭 + 전 휴가 포함을 동시 만족. 휴가 0건이면 기존대로 이번 주 월요일부터 14일. - 칸 수 가변 대응: grid 열 정의를 CSS에서 인라인
repeat(N, minmax(20px,1fr))로 이동. 기간이 길면 칸이 20px에서 멈추고.vac-tl-body가 가로 스크롤(업체명 열position:sticky; left:0). nav 가운데 버튼오늘→전체보기(기본 창 복귀), 이전주/다음주 ±7일. - 불량 데이터 가드:
end_date < start_date행은tlSorted에서 제외(창 계산·막대 폭 붕괴 방지). - 표 축소:
.vac-col-co180px 신설, 날짜 170→145px, 관리 90→70px, 셀 padding 12→8px..vac-wrap는flex:1 1 500px; max-width:620px. - 함정: 처음
flex:0 1 620px로 뒀더니 1100px 뷰포트에서 타임라인이 아래로 wrap. flex 줄바꿈은 축소 후 크기가 아니라 flex-basis 합으로 판정(620+440+20 > 가용폭) → basis를 500으로 낮추고 최대폭만 620으로 캡. - 검증: 노드 하니스 18항목 PASS(창 시작/길이/중앙칸=평균센터, 전 휴가 창 내 포함, 앞뒤 여유≥3일, 막대 offset, 초기창 cut 없음, 헤더 칸수, 인라인 grid, 단일휴가 창, 0건 14일·월요일 시작, nav ±7일·전체보기 복귀, 불량행 제외, XSS). 로컬 스텁 렌더: 휴가 6건 → 창 7/26~8/17(23일)·전 막대 창 내부·cut 없음, 컨테이너 1000/1100/1280/1400/1680px 전부 좌우 배치 유지(1000·1100은 타임라인 내부만 스크롤), 페이지 가로 스크롤 없음. SSM: test
87e42d9·prodb9320dc,tlWindow·vac-col-co마커 존재, 8000/8001=200. - master
87e42d9→ deploy-liveb9320dc(운영배포 완료).
후속2 — "uwsgi 재시작 누락"은 오진이었다 (근본원인: die-on-term ↔ KillSignal 충돌)
- 확인 결과 Actions는 매 배포마다
systemctl restart를 실행하고 있었다(prod reflog에 부트스트랩 reset과 스크립트 자체 reset이 2초 간격으로 찍힘 = 스크립트가 끝까지 실행됨). - 진짜 문제는 그 restart가 90초 hang한 것. uWSGI
die-on-term = true는 SIGTERM/SIGQUIT 의미를 맞바꾼다(기본 TERM=브루탈리로드·QUIT=종료 → 켜면 TERM=종료·QUIT=브루탈 바이너리 리로드). 유닛은KillSignal=SIGQUIT이라 stop 신호가 리로드로 해석 → 프로세스가 안 죽음 → systemd가TimeoutStopSec=90을 다 기다린 뒤 SIGKILL. 그 90초간 구 프로세스가 계속 서빙하고ActiveEnterTimestamp도 옛값이라 "재시작 안 됨"으로 보였다. - 저널 증거:
...brutally killing workers...→binary reloading uWSGI...→ 90초 뒤Failed with result 'timeout'→Stopped→Started. 04:04:57 restart → 04:06:27 완료 / 04:17:14 → 04:18:44 완료. 내가 "수동 재시작"이라 기록한 시각들이 바로 그 타임아웃 완료 시점과 겹친 것. - 수정:
/etc/systemd/system/pfs-{live,test}.uwsgi.service에서KillSignal=SIGQUIT제거(기본 SIGTERM = 종료) +daemon-reload. 백업*.bak_20260710. - 검증: test restart 90.2s→1.0s, live restart→1.0s(둘 다
Result=success, timeout·binary-reload 로그 0건, 8000/8001=200). Actions와 동일 경로인deploy-production.sh6.1s(exit 0),deploy-test.sh8.1s. - ⚠ systemd 유닛은 git 밖 서버 파일 → EC2 재구축 시 재적용 필요. 운영 uwsgi는 리포 ini가 아니라 서버
/etc/uwsgi/pfs-live.ini를 쓴다. 별건으로crontab -l에@rebootuwsgi 직접 기동 줄이 남아 있어 중복 인스턴스 소지(미조치). - 메모리 [[uwsgi-die-on-term-killsignal-conflict]] 신설.
다음
- 페페 육안(운영 Ctrl+Shift+R,
/vacation): 우측 타임라인 표시·막대 위치·주 이동 버튼. - 필요 시 후속 후보: 창 길이 토글(2주/4주), 업체 필터, 휴가 겹침 강조.
관계
- 주제 그룹: pfs-vacation
- 관련 문서:
projects/pfs/handoff.mdNOW,projects/pfs/session-2026-06-26-vacation-menu-page.md(휴가일정 페이지 신설) - domain:pfs-vacation svc:pfs-web