변경 이력

p4-web은 Perforce로 개발됩니다 — 아래 항목은 모두 실제로 서브밋된 체인지리스트이며 최신순입니다. 소스는 GitHub에 미러링됩니다.

2026-08-02
12일차

작업이 어디로 가고 있는지

  • 69156통계 페이지가 생겼습니다 — 일·주·월·연 단위 서브밋, 드릴다운이 되는 경로별 서브밋, 계정별 서브밋 (세 차트가 하나의 필터를 함께 읽기 때문에 기간을 좁히거나 디렉토리로 들어가면 나머지도 같이 좁아지고, 막대를 누르면 그 뒤의 체인지리스트가 열립니다. 경로 차트는 고정된 깊이가 아니라 지금 보고 있는 곳의 한 단계 아래에서 시작하며, 그 깊이에 아무것도 건드리지 않은 서브밋이 몇 건인지도 함께 표시합니다 — 이 줄이 없으면 깊이 들어갈수록 총계가 조용히 줄어듭니다. 차트는 순수 SVG입니다. 필요한 도형이 막대와 축뿐인데 차트 라이브러리를 쓰면 그것 때문에 콘텐츠 보안과 공급망 고정을 다시 풀어야 합니다)
  • 69155그 뒤의 집계는 로컬 체인지리스트 인덱스에서 나옵니다 (덕분에 1년치 이력이 서버의 모든 체인지리스트를 훑는 대신 밀리초 단위 질의가 되고, 인덱스가 본인의 퍼포스 티켓으로 만들어지기 때문에 볼 수 있는 것만 세어집니다. 버킷은 사용자의 시간대로 자릅니다 — 그대로 접으면 서울의 오전 서브밋이 전날로 밀립니다 — 그리고 주는 월요일에 시작하되 오래된 SQLite가 만들지 못하는 ISO 주 번호 대신 날짜를 키로 씁니다)
  • 69151인덱스에 체인지별 디렉토리 롤업을 넣어 경로 통계가 즉시 나옵니다 (질의할 때마다 900만 개의 파일 행을 접으면 28초가 걸립니다. 각 체인지의 디렉토리를 미리 한 번 펼쳐 두면 행이 7% 늘어나는 대신 같은 질문이 한 자릿수 밀리초로 끝납니다. 이전에 만들어진 인덱스는 백그라운드에서 채워지며 그동안에도 페이지는 그대로 쓸 수 있습니다 — 기간·계정 차트는 이미 정확하고, 페이지가 그 사실을 알려 줍니다)
2026-07-26
11일차

목록은 계속 이어지고, 그림은 그림으로 열립니다

  • 67389체인지리스트에서 이미지를 누르면 다운로드가 시작되는 대신 파일 뷰어에서 바로 열립니다 (Perforce에서 .jpgbinary+F라 다른 바이너리와 함께 다운로드 경로로 갔습니다. 휴대폰에서는 그림을 보기 전에 저장/열기 시트를 먼저 닫아야 했다는 뜻입니다. 뷰어는 원래 이미지를 인라인으로 보여주고 있었고, 원본이 필요하면 뷰어 안의 Raw·Download가 그대로 있습니다. 이미지가 아닌 바이너리는 종전대로 내려받습니다)
  • 67388Changes 목록이 Load more 버튼에서 멈추지 않고 스크롤을 따라 계속 이어집니다 (바닥에 닿기 한 화면쯤 전에 다음 페이지가 도착하기 시작합니다. 빠른 색인도 이제 페이지를 넘길 수 있어서 필터를 건 검색도 첫 200줄에서 끊기지 않습니다. 스스로 굴러가면 곤란한 두 경우 — 실패한 페이지, 그리고 빈 페이지가 연달아 나올 만큼 드문 필터 — 에는 버튼이 다시 나타납니다)
2026-07-25
10일차

기능을 켜고 끄기

  • 66854상단바 톱니 아이콘에 설정 페이지가 생겼습니다 — 리뷰·코멘트·멘션·쓰기 작업·즐겨찾기·빠른 체인지 검색을 내 계정 기준으로 끌 수 있고, 테마·diff 레이아웃·마크다운 보기도 같은 자리에서 고릅니다 (기능 스위치는 계정에 저장되어 어느 브라우저에서든 따라옵니다. 표시 취향은 기기별로 남는데, 휴대폰은 다크·데스크톱은 라이트가 자연스러운 반면 "여기선 코멘트가 보이고 저기선 안 보인다"는 혼란스럽기 때문입니다)
  • 66852꺼진 기능은 눌러도 실패할 버튼을 남기는 대신 화면에서 사라집니다 — 메뉴 항목, 코멘트 패널과 diff 안 코멘트 버튼, 리뷰 바, 멘션 배지, 즐겨찾기 별, 파일 페이지의 Edit/Delete가 모두 스위치를 따릅니다 (꺼진 기능으로 향하는 링크·북마크도 그대로 열리며, 서버가 껐는지 내 설정이 껐는지 알려줍니다. 변경 전부터 열려 있던 탭은 조용히 실패하는 대신 새로고침을 안내합니다)
  • 66849서버를 운영하는 쪽은 여섯 기능 중 무엇이든 전체에 대해 끌 수 있습니다 — features.json 또는 P4WEB_FEATURE_* 환경변수를 씁니다 (꺼진 기능은 엔드포인트도 응답하지 않으므로 숨긴 버튼이 아니라 실제 경계입니다. 데이터는 지우지 않습니다 — 켜져 있는 동안 쓰인 리뷰·코멘트는 다시 켜면 그대로 돌아옵니다. 배포처마다 사정이 다릅니다: 순수 열람용으로 띄우고 싶은 곳도, 리뷰는 이미 다른 도구가 맡은 팀도 있으니까요)
2026-07-24
9일차

큰 파일도 다시 내려받기

  • 66839100 MB가 넘는 파일도 다시 내려받을 수 있습니다 — Download 링크가 File too large로 거부하던 문제를 고쳤습니다 (크기 제한은 원래 인라인 미리보기 전용이었습니다. 미리보기는 파일 전체를 페이지로 끌어오지만, 다운로드는 Perforce에서 디스크로 바로 스트리밍되어 서버 메모리에 쌓이지 않으므로 크기가 무관합니다 — 인라인 미리보기에는 100 MB 제한이 그대로 남습니다)
2026-07-22
7일차

리뷰와 멘션, 그리고 코드가 있는 자리의 코멘트

  • 66478가이드 투어가 앱을 따라잡았습니다 — diff 안에서 코멘트를 다는 단계와, 리뷰·@멘션 단계를 추가했습니다 (가상 데포에서 연출한 스크린샷을 담은 두 단계가 새로 붙었고, 랜딩 페이지의 아키텍처 설명도 함께 갱신했습니다)
  • 66477diff의 ---/+++ 머리 두 줄이 다시 헤더로 표시됩니다 — 0번 줄로 번호가 붙은 빨강·초록 편집 줄처럼 보이던 문제입니다
  • 66476휴대폰에서 화면을 당겼을 때 배경이 바깥까지 채워지고, 옆으로 스크롤한 diff의 초록·빨강이 줄 끝까지 이어집니다 (페이지 배경을 문서 루트로 옮기고, 통합 diff 행 폭을 창이 아니라 가장 긴 줄에 맞췄습니다)
  • 66472체인지리스트 안에서 펼친 diff가 휴대폰 화면 밖으로 파일 목록을 늘리지 않습니다 (셀은 표의 폭을 따르고 코드는 원래 의도대로 diff 안에서만 스크롤됩니다. 코멘트 패널은 스크롤해도 제자리에 남습니다)
  • 66471코멘트에서 @이름을 쓰면 그 사람 상단바에 배지가 뜨고, 자신이 언급된 코멘트 목록으로 이어집니다 (실제 Perforce 사용자만 인식하고 입력 중 자동완성됩니다. Changes 목록과 디팟 브라우저에도 체인지·파일별 코멘트 스레드 수와 미해결 수가 표시됩니다)
  • 66470diff 안에서 바로 그 줄에 코멘트를 답니다 — 모든 diff 줄이 앵커를 갖고, 통합 보기에도 드디어 줄번호가 표시됩니다 (체인지리스트 diff에서 연 스레드가 해당 파일 페이지에서도 보이고 그 반대도 마찬가지입니다. 이미 스레드가 있는 줄에는 개수가 표시됩니다)
  • 66468라이트 리뷰: 체인지리스트에 리뷰 중·승인·보완 필요 상태를 달고, 누가 언제 왜 바꿨는지 이력으로 남깁니다 (More 메뉴의 새 Reviews 페이지에서 모아 봅니다. 체인지리스트 자체는 아무것도 바뀌지 않고 상태는 코멘트 옆에 저장됩니다)
  • 66465가이드에 폴더 diff 단계를 추가했습니다 — 디렉토리 전체를 다른 경로와, 또는 예전 체인지리스트·날짜 시점의 자기 자신과 비교하는 방법입니다 (스크린샷은 가이드의 다른 이미지와 마찬가지로 가상의 디팟으로 촬영했습니다)
  • 66463이 사이트가 휴대폰 화면에 다시 들어맞습니다 — 배포 카드가 페이지를 옆으로 늘리던 문제를 해결했습니다 (카드 폭이 안에 든 긴 launchctl 명령줄에 끌려가고 있었습니다. 이제 명령줄은 자기 상자 안에서 가로로 스크롤되고, 섹션 표시 CL도 각 영역의 최신 체인지리스트로 갱신했습니다)
  • 66462휴대폰에서는 diff가 항상 통합(unified) 보기로 나옵니다 — 화면이 넓어지면 “좌우 비교”가 다시 켜집니다 (393 px 화면에서 코드 열이 한쪽에 130 px 남짓이라 한 줄 걸러 줄바꿈이 났습니다. 선택한 설정은 덮어쓰지 않고 기억하므로 태블릿을 돌리거나 창을 넓히면 두 창이 그대로 돌아옵니다)
  • 66458체인지리스트 안에서 연 diff가 파일 목록의 행 스타일을 물려받지 않습니다 — 두 창의 글자가 겹치던 마지막 경우가 사라졌습니다 (목록 규칙이 자기 행에만 적용되도록 좁혀, 목록 행 안에 중첩된 표는 건드리지 않습니다)
  • 66451휴대폰에서 좌우 비교 diff의 줄이 제자리에 맞습니다 — 한쪽 창이 눌리면서 반대쪽 줄 사이에 빈 공간이 생기던 것이 사라지고 두 창이 같은 폭을 가집니다 (표의 열 폭을 명시적으로 지정해 긴 파일 헤더가 표를 화면 밖으로 늘리지 않습니다. 줄간격을 좁히고, 좁은 화면에서는 줄번호 칸의 폭을 본문에 넘깁니다)
  • 66448YAML 머리말(front matter)로 시작하는 마크다운 파일이 이제 그 부분을 깔끔한 메타데이터 표로 보여줍니다 — 한 문단으로 뭉개지지 않습니다 (이전에는 구분선 하나와 산문 한 덩어리로 렌더링되면서 first_seen_build 같은 키의 밑줄이 이탤릭으로 먹혔습니다. 이제 접을 수 있는 표로 나오고, 진짜 구분선으로 시작하는 파일은 그대로 둡니다)
  • 66380이미지 미리보기가 가득한 페이지에서 벗어나도 Perforce 서버에 파일 리더가 남지 않습니다 — 취소된 다운로드가 이제 p4 print를 닫고 연결을 놓아줍니다 (스트리밍 리더를 정상 완료뿐 아니라 클라이언트 접속 종료 시에도 회수합니다. 이전에는 남은 리더가 IDLE 연결로 쌓여 앱을 재시작하기 전까지 서버 슬롯을 붙잡고 있었습니다)
2026-07-20
5일차

긴 문서도 이미지가 다 뜹니다

  • 66121스크린샷이 100장 넘게 든 마크다운 파일도 전부 표시됩니다 — 이전에는 뒤쪽 이미지들이 조용히 실패했습니다 (서버의 파일 디스크립터가 고갈된 것이 원인이었습니다: HTTP/2에서는 브라우저가 이미지 요청을 한꺼번에 열고, 요청마다 p4 프로세스가 둘씩 뜹니다. 이제 서버가 스스로 상한을 올리고 스트림을 몇 개씩 나눠 시작하며, 그래도 실패한 이미지는 페이지가 다시 요청합니다.)
2026-07-19
4일차

로그인 유지

  • 65727가이드에 3단계를 추가했습니다 — 체인지리스트 읽기(인라인 디프 + 코멘트 스레드), 디포 검색, More 메뉴입니다 (스크린샷은 새 tools/mock_shots.py가 가상 디포로 연출했습니다)
  • 65723사이트 정확성을 점검했습니다: launchd 명령, ssl 지문 신뢰 방식, 퀵스타트의 P4WEB_P4PORT, 기능 목록에 즐겨찾기와 체인지리스트 설명 수정·삭제를 반영했습니다
  • 65718Changes 페이지가 조회 전에 먼저 그려집니다 — 필터를 바로 쓸 수 있고 목록은 그 아래로 채워집니다 (인덱스 상태가 매번 파일 행 950만 개를 세지 않도록 바꿨습니다: 최초 열기 4.3초 → 0.04초)
  • 65715세션이 Perforce 티켓이 유효한 동안 그대로 유지됩니다 — 12시간 고정 로그아웃을 없앴습니다 (15분마다 티켓을 다시 확인해 갱신되면 따라 늘어나고, 다른 곳에서 무효화되면 즉시 로그아웃됩니다)
2026-07-17
2일차

검색 인덱스, 하드닝, 그리고 이 사이트

  • 65340앱 CSS/JS 캐시를 무효화합니다 — 배포가 이미 열려 있는 브라우저까지 전달됩니다 (HTML 셸에 no-store, app.js·style.css?v= 태그를 붙였습니다)
  • 65339“이전 항목 인덱싱”이 연속으로 실행됩니다 — 한 번 누르면 중지하거나 Changes 페이지를 벗어나기 전까지 인덱스를 계속 과거로 확장합니다
  • 65319배포·공급망을 하드닝했습니다 (비루트 컨테이너, p4 클라이언트 SHA-256 고정, 의존성 버전 고정, compose 루프백 전용 바인딩)
  • 65314/api/diff를 하드닝했습니다: path·path2에 디폿 경로(//) 프리픽스를 요구합니다 (인자 주입 계열이며, 다른 모든 엔드포인트와 동일한 검사입니다)
  • 65277사이트 6개 페이지 전체에 애널리틱스 스니펫을 추가했습니다
  • 65274한국어 페이지(/ko/)와 브라우저 로케일 기반 언어 전환을 추가했습니다
  • 65272Changes·Guide 페이지와 정제된 스크린샷을 넣었습니다
  • 65268랜딩 페이지에 GitHub 저장소와 소스 .zip 다운로드 링크를 달았습니다
  • 65266랜딩 페이지: 히어로 디프 오버플로로 인한 모바일 축소 렌더링을 수정했습니다
  • 65265GitHub Pages 커스텀 도메인을 붙였습니다 (docs/CNAME → p4-web.woojinkim.org)
  • 65264프로젝트 랜딩 페이지를 만들었습니다 (docs/index.html)
  • 65225Changes 뷰가 엔진을 자동으로 고릅니다 — 사용자에게 보이던 “Fast” 토글을 없앴습니다 (설명/파일명/날짜 탐색은 인덱스, 펜딩·경로 프리픽스는 라이브 p4를 씁니다)
  • 65221날짜 필터를 YYYY-MM-DD 텍스트 입력으로 바꿨습니다 (네이티브 날짜 픽커는 브라우저 로케일 형식으로 렌더링되는 문제가 있었습니다)
  • 65220사용자별 체인지리스트 검색 인덱스를 도입했습니다 — 프로텍션을 준수하면서 설명·파일명을 즉시 검색합니다
  • 65218세션 만료 UX를 개선했습니다: 재로그인 안내, 사용자명 미리 채움, 위치 보존
  • 65217운영을 하드닝했습니다: 프록시 헤더 허용 목록 고정, sessions.db 권한을 열 때마다 재조정
  • 65216DoS를 하드닝했습니다: 스트리밍 raw 다운로드, 제한된 업로드 스풀링, 세션별 API 요청 제한
2026-07-16
1일차 · 밤

리뷰 기능과 보안 점검

  • 65207상시 보안 리뷰(코드 리뷰 + 감사 + 레드팀)를 돌리고 심층 방어 수정 3건을 넣었습니다
  • 65206체인지 상세에서 파일 경로를 누를 수 있습니다 — 텍스트는 뷰어로, 바이너리는 다운로드로 갑니다
  • 65196인라인 코멘트를 추가했습니다: 파일/줄·체인지리스트 스레드, 마크다운 본문, 해결/수정/삭제
  • 65193경로 즐겨찾기와 루트 대시보드를 만들었습니다 (즐겨찾기별 최근 변경을 보여줍니다)
  • 65192마크다운을 렌더링합니다: 탐색 화면 README 패널, Rendered/Source 토글 (marked + DOMPurify를 번들로 포함했습니다)
2026-07-16
1일차 · 저녁

쓰기 작업

  • 65184다크 모드(시스템 기본 + 수동 토글)를 넣고 문서를 마무리했습니다
  • 65182디포 목록을 정렬하고 줄 번호 퍼머링크를 붙였습니다
  • 65181My Changes에서 셸브 / 언셸브 / 셸프 삭제를 할 수 있습니다
  • 65178쓰기 UI를 만들었습니다: My Changes 페이지, 웹 에디터, 업로드, 서브밋 확인
  • 65175쓰기 백엔드를 만들었습니다: 사용자별 서버 측 워크스페이스, 자기 체인지리스트 한정 가드, 감사 로그
  • 65170로그인 요청 제한(계정·IP별)과 Secure 쿠키를 넣었습니다
2026-07-16
1일차 · 오후

P4V 패리티와 운영

  • 65168모바일 UX를 정비했습니다: 행 전체 탭 타깃, 슬라이드 오버 트리, 반응형 테이블
  • 65165배포 수단을 갖췄습니다: Dockerfile + compose, launchd·systemd 유닛, SSL 최초 접속 신뢰
  • 65162체인지리스트 필터에 사용자 자동완성을 붙였습니다
  • 65161통합 이력을 담은 SVG 리비전 그래프 탭을 추가했습니다
  • 65157흔한 p4 오류를 친절한 메시지로 번역합니다
  • 65155세션을 SQLite에 보존합니다 — 재시작해도 로그아웃되지 않습니다
  • 65153모바일 레이아웃의 기반을 잡았습니다
  • 65151디포 트리 사이드바를 만들었습니다: 지연 로딩, 딥링크와 동기화
  • 65149메타데이터 브라우저를 추가했습니다: 레이블, 잡(픽스 포함), 브랜치, 스트림, 사용자 & 그룹
  • 65148raw 보기/다운로드와 인라인 이미지 미리보기를 넣었습니다 (CSP 샌드박스를 적용했습니다)
  • 65147디프 스위트를 갖췄습니다: 어디서나 side-by-side, 리비전 쌍, 폴더 디프, 타임랩스 어노테이트
  • 65145디포 검색을 추가했습니다: 디포 전역 파일명, p4 grep 기반 내용 검색
2026-07-16
1일차 · 오전

읽기 전용 코어

  • 65139README와 /api/info, 로그인 화면을 다듬었습니다
  • 65138체인지리스트 탐색을 붙였습니다: 필터, 키셋 페이징, 파일별 디프가 있는 상세 뷰
  • 65137파일 히스토리(이름 변경 포함)와 unified 디프, 어노테이트를 넣었습니다
  • 65135디포 브라우저와 오프라인 신택스 하이라이팅 파일 뷰어를 만들었습니다
  • 65134프로젝트 뼈대를 세웠습니다: FastAPI 앱, p4 -G 래퍼, 티켓 기반 로그인