• 4.8.0

    4.7.0 대비 변경사항

    기능

    • Hitomi 수집 기록 무시 재검사 — 명시 범위 수집에 재검사 옵션을 추가했습니다. GC 뒤 이미 닫힌 수집 범위를 다시 검사할 수 있고 기존 coverage와 저장 원장을 보존합니다. 일반 범위·latest에서는 삭제·차단 표시 작품과 이미 닫힌 후보를 요청 없이 처리합니다.
    • 태그 제외 검색 — 카드와 상세의 태그 메뉴에 제외하고 검색을 추가했습니다. 홈의 기존 포함·제외 필터를 함께 사용할 수 있습니다.
    • 묶음 조회 API — 카드 요약(POST /api/galleries/cards)·작가/그룹 미리보기(POST /api/galleries/creator-previews)·중복 대기 수 전용 조회(GET /api/duplicates/review-groups/counts)를 추가해 북마크·게스트 기록·운영 요약의 반복 요청을 줄였습니다.

    UI/UX

    • 디자인 토큰과 공용 로딩·빈 화면·오류·권한·진행률 표시를 전 화면에 적용했습니다. 다크 입력 윤곽을 보강하고 좁은 화면의 버튼·메뉴·필터 배치를 정리했습니다.
    • 모바일 메뉴의 첫 포커스·바깥 영역 비활성화·닫은 뒤 포커스 복귀, dialog 설명·첫 포커스, 정렬·태그 메뉴의 키보드 조작과 터치 영역을 개선했습니다.
    • 운영 화면을 작업별로 묶고 접힌 섹션에도 상태를 표시합니다. 권한을 잃으면 상태 조회를 멈추고 재확인을 안내하며, 조회 실패를 빈 상태·0개로 보이지 않게 했습니다.
    • GC 확인 창에 대상·용량·실행 중 작업을 표시하고 확인 중 시작 불가로 바뀌면 이유를 안내합니다. 용량 표시와 로그·블랙리스트 상태를 통일했습니다.
    • 홈 이어 읽기는 기본 접힘이며 사용자의 펼치기 선택을 저장합니다. 오프라인 배너·일괄 GC 바·PWA 안내가 모바일 검색창이나 하단 도구를 덮지 않게 했습니다.
    • 작가·그룹 북마크 삭제 뒤 시간 제한 없는 되돌리기, 이미지 검색 미리보기, 뷰어 상태·페이지 제외 확인과 중복 비교 이전/다음 조작을 개선했습니다.

    수집·중복 검사·성능·안정성

    • Hitomi galleryinfo 재사용, 받은 바이트의 저장 단계 재시도, E-Hentai overlap detail 재요청·불필요한 checkpoint 쓰기 제거로 외부 요청을 줄였습니다.
    • E-Hentai 정상 페이지의 보호 문구 오판정을 막고 차단 만료 시각을 읽습니다. 진전 없는 Hitomi 반복 보호 정지는 자동 재개 간격을 늘립니다.
    • DB 단절 때 background 작업의 기록 실패가 backend·crawler를 종료시키지 않게 했습니다. 중복 검사 일시 DB 오류는 시도 횟수를 차감하지 않고, GC 통계 갱신은 재시도하며 저장소 전면 장애의 GC는 연속 5개 실패 뒤 중단합니다.
    • crawler DB 연결 획득 대기는 30초, idle-in-transaction은 300초, 문장 상한은 기본 15분입니다. 유휴 이미지 색인의 불필요한 잠금 연결·동일 상태 쓰기를 줄였습니다.
    • 개인 차단 검색에 태그 LOWER 표현식 index와 한 번의 규칙 해석을 적용했습니다. DB 통계는 11개 순차 query에서 4개로, GC 통계는 이미지 사전 집계 1회로 줄이고 읽기 진행률 저장도 gallery 확인을 포함한 단일 upsert로 바꿨습니다.
    • 북마크·작가 미리보기·dashboard의 창 focus 재조회는 마지막 조회 5분 뒤로 제한하고 고급 태그 검색에 300ms debounce·요청 취소·인기 태그 재사용을 적용했습니다.
    • 지문 블록 통계를 추가해 중복 후보·이미지 검색 실행 계획을 개선했습니다. 업로드 캡처의 검은 여백·상태바를 검색 전용으로 trim해 원본과 함께 검색하고, trim 실패 시 원본 검색을 유지합니다. 영구 색인 실패는 반복 대기하지 않고 종료·복구 원인을 표시합니다.

    버그 수정

    • Hitomi 게시 시각 저장 누락으로 작가·그룹 알림 대상에서 빠지던 문제와 다른 브라우저 구독 때문에 알림 스위치가 틀리거나 해제되지 않던 문제를 고쳤습니다.
    • Push는 사용자별로 독립 발송해 한 사용자의 장애가 다른 발송을 막지 않습니다. 410은 즉시, 다른 영구 4xx는 연속 3회 뒤 구독을 비활성화하며 재시도 간격은 1분~1시간입니다.
    • 썸네일 유지 생성의 일시 오류 뒤 매시간 생성이 끊기던 문제, 부분 실패한 crawler 상태·미종료 GC를 유휴로 표시하던 문제를 고쳤습니다.
    • 공개 /api/health/crawling 활동에 이미지 색인·썸네일 생성도 반영하고 Hitomi 매일 예약 수집을 서울 오후 10시로 옮겼습니다.

    의존성·정리·문서

    • NestJS 12.1.2, TypeORM 1.1.1, React 19.3.0, SimpleWebAuthn 14, Sharp 0.35.5와 개발·브라우저 검증 도구를 갱신했습니다. Nest 구버전 peer 중복 설치를 제거하고 ESM·TypeScript 호환 설정을 맞췄습니다.
    • 내부 미사용 경로·export·Redis 플래그·중복 설정·무동작 Nginx cache 지시어를 정리했습니다. DB 설정은 문서의 DATABASE_*, crawler 내부 주소는 현재 계약을 사용합니다.
    • 화면·API·수집 복구·DB·검증·운영 문서를 현재 구현에 맞췄습니다.

    기존 기능·데이터를 유지하는 새 기능과 API가 추가돼 minor 버전입니다. 데이터 재설정이나 필수 수동 데이터 전환은 없습니다. 내부 private 패키지의 manifest 버전은 4.6.0→4.7.0과 같이 유지하고 릴리스 버전은 Git 태그·이미지 OCI label로 관리합니다.

    DB migration (backend 시작 시 자동 적용, 데이터 보존)

    • ImageSearchBlockStatistics1790991300000 — image_search_hashes의 4개 지문 블록 표현식 통계와 ANALYZE를 추가합니다. transaction 안에서 statement timeout을 해제합니다.
    • AddTagLowerNameIndexes1791769000000 — tags의 LOWER(name)·LOWER(namespace || ':' || name) index 2개를 CREATE INDEX CONCURRENTLY로 생성합니다. 실패한 invalid index는 재시도 때 재생성하고 원래 statement timeout을 복원합니다.

    이미지 게시 범위

    4.7.0 latest의 빌드 입력 label과 최종 소스를 대조해 nginx·backend·crawler·web만 새로 빌드하고 4.8.0·latest를 게시했습니다(publish-images.ps1 -ChangedOnly). nginx는 CSP·설정, backend·crawler·web은 앱·공유 패키지·lockfile·빌드 입력이 바뀌었습니다. byedpi는 지문이 같아 기존 latest digest를 유지하며 4.8.0 태그를 추가하지 않습니다. log-reader는 backend 이미지를 공유하고 PostgreSQL·Redis·Silo는 별도 자체 이미지 게시 대상이 아닙니다.

    NAS 업데이트

    compose.yml이 바뀌었으므로 먼저 이 태그의 파일을 받습니다. 아래는 운영자 안내이며 이번 릴리스 작업에서는 NAS 배포를 실행하지 않습니다.

    cd /volume1/2ex-hentai
    curl -fsSL https://git.2ex.dev/hanyul/2Ex-Hentai/raw/tag/4.8.0/compose.yml -o compose.yml
    grep -n CRAWLER_DB_STATEMENT_TIMEOUT_MS compose.yml
    docker login git.2ex.dev
    sh ops/deploy-production.sh
    docker compose --env-file .env.production ps
    
    • 새 CRAWLER_DB_STATEMENT_TIMEOUT_MS는 기본 900000ms(15분), 0은 상한 해제입니다. 키가 없어도 Compose 기본값으로 동작합니다.
    • backend·crawler·web을 함께 반영합니다. 배포 스크립트는 backend 변경 시 crawler를 먼저 멈춰 migration과 옛 crawler 쓰기의 deadlock을 피합니다.
    • 대형 태그·지문 테이블의 index 생성·통계 수집은 시간이 걸릴 수 있습니다. NAS 실측 시간은 미확인이며 수집·백필이 적은 시간에 배포하고 migration 완료와 backend healthy를 확인합니다. 이미지 rollback은 migration을 되돌리지 않습니다.
    • 이전 오류로 운영 썸네일 백필이 paused 상태라면 배포 뒤 운영 화면에서 생성 시작을 한 번 누릅니다.
    • 작가 알림을 쓰면 운영 VAPID 공개·비밀 키가 설정돼 있고 같은 키 쌍인지 확인합니다. 키 값은 로그나 게시 기록에 남기지 않습니다.
    • nginx CSP에 Cloudflare Web Analytics의 static.cloudflareinsights.com script와 cloudflareinsights.com 연결을 허용했습니다. 운영 Cloudflare를 거친 브라우저에서 CSP 오류를 확인합니다. Inter 폰트 preload 경고도 제거했습니다.

    알려진 주의사항

    • -ChangedOnly로 변경 서비스에만 4.8.0 태그가 있으므로 전체 서비스를 IMAGE_TAG=4.8.0으로 일괄 지정하거나 일괄 rollback할 수 없습니다. 운영은 기본 latest를 사용하고 rollback은 서비스별 기존 digest·Compose·migration 호환성을 확인합니다.
    • 실제 원본 정확도 runner run-duplicate-accuracy.ps1은 기존 입력 표본 디렉터리가 없어 미실행입니다. 합성 fixture·golden raster·검색 회귀 결과를 운영 원본 정확도로 해석하지 않습니다.
    • NAS 배포·실제 NAS 부하 및 migration 소요 시간·운영 원본 검색 정확도·실제 Push provider·실제 인증기·운영 Cloudflare 브라우저 확인은 미실행입니다.

    4.7.0 대비 전체 변경

    검증

    • 합친 main 36b77df2에서 코디네이터가 확인한 run-unit.ps1 -Workspace all -TimeZoneRegression(backend 436·crawler 670·web 962), crawler recovery 일반·EHentaiOnly, duplicate benchmark·near-miss 결과를 재사용했습니다. 이후 앱 실행 코드 변경은 없고 UI fixture 한 줄(698924a0)과 게시 준비 기록(b70e66b9)만 추가했습니다.
    • 게시 준비 소스에서 schema, search benchmark(rel-480-search), integration 전체, operations DeploymentOnly, 이미지 검색·운영 UI(1440/320px), 북마크 UI(1440/450/320px), passkey viewer/admin 검증이 통과했습니다. 실제 저장소 통합과 mock UI·가상 인증기 검증을 구분합니다.
    • 이미지 검색 UI의 최초 실패는 새 개수 API fixture 누락이었고 실제 backend 응답 형태를 추가한 뒤 해당 격리 UI만 재실행해 통과했습니다.
    • 합성 tmpfs 검색 fixture의 개인 차단 100/500개 p95는 39.817/53.119ms(같은 실행 baseline 394.532/137.928ms)였습니다. NAS 성능이 아닙니다.
    • 현재 lockfile의 root production/전체·integration API/browser·passkey audit 모두 0건이며 DI 공유 의존성은 단일 버전입니다.
    • 실제 E-Hentai는 direct TLS/DPI 실패를 분류하고 선택 ByeDPI로 목록·상세·WebP 이미지·showpage를 확인했습니다(7요청). 전체 외부 이미지 host 가용성을 보증하지 않습니다.

    게시 확인

    • 릴리스 소스: b70e66b9764958941ca663bc2e53e65b5e671573 (주석 태그 4.8.0).
    • nginx 4.8.0·latest: sha256:e40f31f88d0af2c48b739d2cd3165cefcfd83e92603510b4b0c22fe3010df7ee
    • backend 4.8.0·latest: sha256:8a45d2408182b31b0dd58d642dc04c2ae2bc31ac0ed36195131d22aae265b932
    • crawler 4.8.0·latest: sha256:6ee14a74a3992e892a0612881bfd311755827e2649e173768d04fb5e02d02466
    • web 4.8.0·latest: sha256:66fee185ad4b28b250fe29b64d784dd7d3395ae202b56cf0880ce47b2ceae93d
    • 네 이미지 모두 OCI version 4.8.0·revision b70e66b9764958941ca663bc2e53e65b5e671573·빌드 입력 hash 일치를 확인했습니다. byedpi는 기존 latest digest sha256:15ac60ab852a92219573aa3e3795f700e9da0692022af47233590e6a78a1a40a 유지·4.8.0 태그 부재를 확인했습니다.
    Downloads 2