Releases: beyondwin/ReadMates
ReadMates v1.14.1
Fixed
- server release image security:
v1.14.0의 frontend 배포는 성공했지만Deploy Server Image가 Trivy gate에서 fixed HIGH 취약점을 발견해 GHCR release tag promotion 전에 멈췄습니다. Release image build가 Ubuntu security updates를 적용하도록 하고, runtime dependency override를 Netty4.2.15.Final과 Spring Kafka4.0.6으로 올려 server image scan blocker를 닫습니다.
Deployment Notes
- Server release repair. DB migration, public API contract, auth/BFF token, OAuth scope, frontend behavior, and deploy workflow behavior are unchanged from
v1.14.0. - Do not force-update
v1.14.0. Publishv1.14.1, confirmDeploy Server Imagescan/promote, promote OCI Compose backend toghcr.io/<owner>/<repo>/readmates-server:v1.14.1, then run sanitized BFF/OAuth/admin/host smoke checks.Deploy Frontwill also rerun from the patch tag.
Verification
v1.14.0release operation (2026-06-21):Deploy Frontpassed for tagv1.14.0;Deploy Server Imagefailed before release-tag promotion at Trivy scan on Ubuntulibssl3/openssl, Netty, and Spring Kafka fixed HIGH findings.- Local dependency verification (2026-06-21):
./server/gradlew -p server dependencyInsight --dependency netty-handler --configuration runtimeClasspathselected Netty4.2.15.Final;./server/gradlew -p server dependencyInsight --dependency spring-kafka --configuration runtimeClasspathselected Spring Kafka4.0.6. - Local server/image verification (2026-06-21):
./server/gradlew -p server clean check bootJarpassed;docker build -f server/Dockerfile.release server -t readmates-server:v1.14.1-localpassed; the local image reportslibssl3/openssl3.0.2-0ubuntu1.25and containsnetty-handler-4.2.15.Final,netty-resolver-dns-4.2.15.Final, andspring-kafka-4.0.6. - Local vulnerability verification (2026-06-21):
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.70.0 image --severity HIGH,CRITICAL --ignore-unfixed --scanners vuln readmates-server:v1.14.1-localpassed with 0 Ubuntu and Java HIGH/CRITICAL findings. - Release operation (2026-06-21):
Deploy Frontpassed for tagv1.14.1;Deploy Server Imagepassed, scannedghcr.io/beyondwin/readmates/readmates-server@sha256:9254b7ff380b6fa869ec6694acc8ea2a13010940445b52a595968712030e528f, and promoted the same digest toghcr.io/beyondwin/readmates/readmates-server:v1.14.1. - OCI backend promotion (2026-06-21):
deploy/oci/05-deploy-compose-stack.shpromoted the Compose stack toghcr.io/beyondwin/readmates/readmates-server:v1.14.1;readmates-apireported healthy liveness; post-deploy watch passed VM compose health, Cloudflare BFF auth smoke, OAuth redirect smoke, Pages marker smoke, and recent backend error scan.
ReadMates v1.13.0
Highlights
- release policy: solo-admin 운영 현실에 맞춰
mainbranch protection에서 불가능한 PR/code-owner self-review 요구를 제거하고, 필수Frontend/Backendstatus check와 DB/API release-readiness evidence path는 유지하도록 문서와 CODEOWNERS 의미를 정렬했습니다. - contract confidence: frontend Zod fixture와 server MockMvc contract test 범위를 host-only에서 admin analytics와 member current-session까지 넓혀, 운영 분석과 멤버 읽기 루프의 response shape drift를 더 빨리 잡습니다.
- release confidence: notes feed query-plan confidence now closes the
questionsfull-scan regression with an indexed SQL path and matching EXPLAIN guard; frontend/server contract confidence also checks nested fixture shapes, wires DEV parsers for current-session/admin analytics responses, and keeps current-session attendeeparticipationStatusaligned across server and frontend. - visual evidence baseline: analytics screenshot evidence now has matching host dashboard and member reading momentum E2E evidence, with desktop/mobile artifacts and public-safe leak sentinels.
- member reading momentum: member home/current-session now name the next reading or reflection action more directly and keep notes/archive continuity role-safe through the shared reading-loop model.
- platform-admin analytics confidence:
/admin/analytics를 운영 판단 표면으로 심화하고, 데이터 부족과 측정 불가 상태를 구분하며, KPI별 운영 route drilldown, analytics query-budget/EXPLAIN guard, public-safe desktop/mobile visual evidence gate, showcase/release-readiness 문서 연결을 추가했습니다.
Performance
- admin analytics series: 시계열 KPI를 버킷마다 메트릭별 스칼라 쿼리로 조회하던 N+1 구조를, 버킷 인덱스로
GROUP BY하는 메트릭당 단일 쿼리로 교체했습니다. 라운드트립이 버킷 수와 무관하게 고정되어/admin/analytics/overview(30d) query budget이 65→33으로 줄었고, 윈도우 독립성과 버킷 분할 정합성을 통합 테스트로 고정했습니다.
Changed
- notes feed ordering: 클럽 전체 notes feed를 회차(session) 우선으로 정렬하도록 바꿨습니다. 최신 회차가 먼저 묶여 보이고, 같은 회차 안에서는 작성 시각(
created_at) 순으로 정렬되어, 오래된 회차에 더 나중에 작성된 기록이 마지막 회차 기록보다 앞에 끼어드는 일이 없어집니다. keyset pagination·EXPLAIN guard·통합 테스트를 새 정렬에 맞춰 고정했고, 단일 회차 feed의 keyset 로직도 같은 형태로 정렬해 두 경로의 분기를 없앴습니다. DB migration·API contract·auth/BFF 토큰 변경은 없습니다. - member reading pace: current-session과 member-home의 다음 행동 안내에 읽기 페이스 배지를 더했습니다. 마감까지 남은 일수와 읽기 진행률만으로 페이스(여유/적정/촉박/임박/완독)를 계산하므로 별도의 읽기 시작 앵커가 필요 없고, 배지는 색상에 더해 항상 텍스트 라벨과
aria-label을 함께 노출합니다. DB migration·auth/BFF 토큰 변경은 없습니다. - host operations signal card: 호스트 대시보드의
운영 신호카드를 read-only 지표 목록에서 운영 판단 카드로 다듬었습니다. 준비 상태 배지, 상황 요약, 열린 세션/마감 대기/AI 실패/전주 대비 2x2 지표, 차단 사유, host-safe 세션 문서·알림 장부 링크를 보여 주며, 서버/API contract·auth/BFF token·DB migration 변경은 없습니다.
Fixed
- member my-page 완독률 정직성: my-page에서 출석률을 "완독률"로 잘못 표기하던 오라벨을 바로잡았습니다. 이제 참석률(출석 기준)과 완독률(
reading_checkins.reading_progress가 100%에 도달한 회차 기준)을 별도의 정직한 지표로 분리해 보여 줍니다.MyPageResponse에completedReadingCount와 회차별readingProgress가 추가됐고, DB migration·auth/BFF 토큰 변경은 없습니다. - release validation scripts: Docker 이미지 기본 entrypoint와 충돌하던 Prometheus/Alertmanager 검증 스크립트의 컨테이너 실행 방식을 고치고,
AiGenBudgetExhaustionrule의 금액 템플릿을promtool유효 문법으로 바로잡아./scripts/pre-push-check.sh --full --release가 관측 설정 검증까지 통과하도록 했습니다.
Added
- outbound resilience: Outbound adapter(외부 HTTP/Redis)에 Resilience4j CircuitBreaker 적용. fail-open 정책 유지, 회로 상태를 Micrometer 카운터와
/admin/healthoutbound-resilience카드로 관측 가능. - member my-page 독서 여정: my-page에 책별 히스토리(질문·서평 묶음)와 최근 활동 타임라인을 보여 주는 독서 여정 섹션을 더했습니다. 기록이 없을 때는 정직한 빈 상태를 노출하며, member 본인만 보는 표면 경계는 그대로 유지됩니다.
- host 회차 준비 페이스: 호스트 대시보드의 다음 운영 행동에 회차 준비 페이스 배지를 더했습니다. 책 정보·RSVP·읽기 진행률 등 준비 항목을 기존 체크리스트의 D-7/D-3/D-1 마감창에 매핑해, 모임일까지 남은 일수 대비 가장 급한 항목과 전체 페이스(여유/적정/촉박/임박/마감 지남)를 한눈에 보여 줍니다. 배지는 색상에 더해 항상 텍스트 라벨과
aria-label을 노출합니다. DB migration·API contract·auth/BFF 토큰 변경은 없습니다. - AI 생성 provider failover: provider 가용성 실패(
PROVIDER_UNAVAILABLE/PROVIDER_RATE_LIMITED) 시 기존 단일 재시도를 전역readmates.aigen.fallbackChain의 다음 provider로 돌려 자동 failover합니다(깊이 1, job당 LLM 호출 예산 불변). content 코드 실패(SCHEMA_INVALID등)는 failover하지 않습니다. 비용·audit·metrics는 실제 생성한 모델(actualModel) 기준으로 기록합니다. 체인이 비어 있으면 기능이 꺼져 동일 provider 재시도로 동작합니다. DB migration·auth/BFF 토큰 변경은 없습니다.
Testing
- visual regression harness:
shared/uiprimitive에 대한 Playwright 컴포넌트 단위 시각 회귀 하니스를 추가했습니다. baseline은mcr.microsoft.com/playwright:v1.60.0-jammy안에서만 생성해 CI 렌더러와 일치시키고, 스냅샷을 커밋 대상으로 관리합니다 (ReadmatesBrandMark / BookCover / AvatarChip 초기 커버리지). macOS 로컬에서는 Vite 8 네이티브 바인딩 부재로 Docker 경로만 사용합니다.
Deployment Notes
- Minor release. DB migration 없음. Auth/BFF token, OAuth scope, secret/session handling 변경 없음.
- Public API contract는 additive입니다.
/api/admin/analytics/overview는admin.analytics_overview.v2로 KPI trendseries를 포함하고, my-page 응답은completedReadingCount와 최근 회차readingProgress를 포함합니다. - 서버/API/frontend contract가 함께 바뀌므로 release tag push 후
Deploy Server Image가 GHCRreadmates-server:v1.13.0을 scan/promote한 것을 먼저 확인하고, OCI Compose backend를 같은 image tag로 올린 뒤 final frontend/admin smoke를 수행합니다. Cloudflare PagesDeploy Front는 tag push로 독립 실행될 수 있으나, 새 frontend는 구 analytics 응답의 누락된series를 빈 trend 상태로 normalize합니다. - 운영 smoke는
/internal/health, BFF auth, OAuth redirect, OWNER 또는 OPERATOR/admin/analytics렌더링을 포함합니다. 실제 운영 domain, VM IP, member data, provider state, secret 값은 Git에 남기지 않습니다.
Verification
- Local release readiness (2026-06-07):
git diff --check v1.12.1..HEAD- pass. - Local release readiness (2026-06-07):
pnpm --dir front lint- pass. - Local release readiness (2026-06-07):
pnpm --dir front test- pass (134 files, 1145 tests). - Local release readiness (2026-06-07):
pnpm --dir front build- pass. - Local release readiness (2026-06-07):
./server/gradlew -p server clean check architectureTest integrationTest --tests RedisAiGenerationJobStoreTest- pass. - Local release readiness (2026-06-07):
pnpm --dir front test:e2e- pass (61/61). - Local release readiness (2026-06-07):
./scripts/build-public-release-candidate.shand./scripts/public-release-check.sh .tmp/public-release-candidate- pass; gitleaks found no leaks. - Skipped before tag: production OAuth, VM, provider-console, release tag deploy smoke. These are release-operation steps after tag push, not local evidence.
ReadMates v1.12.1
Fixed
- server security: override Spring Boot's managed embedded Tomcat version to
11.0.22so the release image no longer carries thetomcat-embed-core 11.0.21vulnerabilities reported by theDeploy Server ImageTrivy gate.
Deployment Notes
- Server-only patch release. No DB migration, API contract, auth, BFF token, or frontend behavior change is included.
v1.12.0frontend deployment succeeded, but the server image workflow stopped before release-tag promotion at the vulnerability scan step. Publish and deployv1.12.1for the server image instead of promoting the failedv1.12.0image candidate.
Verification
- Local release repair (2026-05-31):
./server/gradlew -p server dependencyInsight --dependency tomcat-embed-core --configuration runtimeClasspath— pass;tomcat-embed-coreresolved to11.0.22. - Local release repair (2026-05-31):
./server/gradlew -p server check— pass. - Production deployment (2026-05-31):
Deploy Server Imagefor tagv1.12.1— pass; image scan and release-tag promotion completed. - Production deployment (2026-05-31):
Deploy Frontfor tagv1.12.1— pass. - Production deployment (2026-05-31):
./deploy/oci/05-deploy-compose-stack.shwithREADMATES_SERVER_IMAGE=ghcr.io/beyondwin/readmates/readmates-server:v1.12.1— pass; compose API container reported healthy and post-deploy watch passed.
ReadMates v1.12.0
Highlights
- Admin vNext route family:
/admin단일 페이지를 9-라우트 lazy-split 패밀리로 분해했습니다. 공유 좌측 nav · 상단 status strip · 권한 매트릭스 · URL-state onboarding modal을 갖춘AdminShellLayout위에서today·health·clubs·clubs/:clubId·notifications·ai-ops·support·audit·analytics9개 READY 라우트가admin-route-catalogSSOT로 구동됩니다. - Admin vNext 운영 콘솔 확장:
/admin/notifications를 READY 라우트로 전환해 outbox, delivery, 실패 cluster, club별 알림 health와 two-step replay preview/confirm을 제공합니다./admin/clubs/:clubId는 readiness, 멤버/세션/알림/AI 사용량을 하나의 운영 상세로 묶고,/admin/support는 사용자 검색 기반 grant 생성과 ledger/revoke 흐름을 제공합니다. - AI 운영 콘솔 + 호스트 복구:
/admin에서 AI job 상태, 실패 코드, 비용 추정, stale 후보를 보는 AI Ops 표면을 추가하고, 호스트 세션 편집기에서 자기 세션의 in-flight AI job을 다시 찾아 안전하게 취소/재시도할 수 있게 했습니다. - Query foundation 완주:
archive,feedback,publicread path를 Query loader seeding으로 이전하고, AI commit 후 full page reload 대신 관련 Query cache invalidation으로 화면을 갱신합니다. - 운영 안전망 보강: 일일 MySQL 백업 systemd timer와 복구 runbook, release-tag
Unreleasedguard(--releasegated,--no-changelog-check비상 우회), graphify 기반 코드베이스 탐색 워크플로를 도입했습니다. /admin/clubs: triage list now orders clubs by operational severity (긴급/주의/정상), shows the blocking reasons inline, and adds a severity filter so operators see at-risk clubs first./admin/clubs: triage now counts each club's recent (7-day) notification-delivery and AI-generation failures, ranks any club with a failure as 긴급, and shows알림 실패 N건/AI 실패 N건as the leading reasons so operators see member-impacting failures first./admin/clubs/:clubId: 운영 스냅샷에 최근 7일 알림/AI 실패 추이(지난 7일 대비 델타)와 readiness 차단 신호별 next-action 링크를 추가하고, 플랫폼 운영/호스트 운영 섹션을 구분했습니다.- Admin vNext S8 분석/리포팅 lite:
/admin/analytics를 마지막 COMING-SOON 라우트에서 READY로 전환했습니다. 7/30/90일 윈도우 선택(URL state)으로 활성 멤버·세션 완료율·RSVP 응답률·AI 비용/세션·알림 도달률을 현재-대비-직전 윈도우 델타로 보여주고, 클럽 간 비교(cross-club benchmark)를 제공합니다. 분모가 0인 지표는 차트를 지어내지 않고 "데이터 부족" empty state로 정직하게 표기합니다. 새 read-only 서버 슬라이스admin.analytics(controller → service → JDBC adapter)가 클럽 전반의 원시 카운트를 집계하고, 비율·델타·가용성 파생은 순수 application service에서 단위 테스트로 검증합니다. - member/host reading loop: host dashboard의 다음 운영 행동과 member home/current-session의 다음 읽기 행동을 role-safe reading-loop 상태로 정렬했습니다. 공유 모델은 admin-only 신호를 노출하지 않고, showcase 문서는 private workflow를 guest에게 열지 않은 채 sanitized 테스트와 문서 evidence로 설명합니다.
Engineering
- observability: clarified
readmates.aigen.queue.depthas Redis active AI job backlog (PENDING+RUNNING) rather than a placeholder or Kafka consumer-lag metric. Metrics catalog, dashboard copy, alert wording, runbook triage, and KDoc now use the same meaning without adding high-cardinality labels. - release-readiness: reclassified the v1.11.0 production OAuth and backup-timer residuals, then recorded both as closed after browser-profile OAuth return evidence, VM timer installation, and a manual Object Storage upload proof. The release-readiness checklist now distinguishes automated closure, manual operator evidence, and out-of-scope pre-existing risk.
- platform-admin/a11y: admin 전 라우트와 host dashboard에 하드닝 베이스라인을 적용했습니다. admin shell에 skip-link와 라벨된 nav/main 랜드마크를 추가하고, 이름 없는 상호작용 요소를 막는 의존성 없는 테스트 가드(
findUnnamedInteractiveElements)와 각 라우트 a11y 어서션을 도입했습니다. 색 대비·키보드 순서·모바일 360px는docs/development/admin-hardening-baseline.md의 수동 게이트로 문서화했습니다. - host-surface: club operations의 host-적절 신호(준비 상태·세션 진행·AI 사용량)를 중립 계약
front/shared/model/club-operations.ts로 분리해 admin·host가 공유합니다. host dashboard는/api/host/club-operations(host 인증, 자기 클럽만)로 read-only 운영 신호 카드를 렌더합니다. admin 전용 신호(support grant, raw member email, notification replay, safeLinks)는 host projection에서 제외하며, admin↔host 직접 import는 경계 테스트로 차단합니다. host에 write 명령은 추가하지 않습니다. - platform-admin:
/admin/audit의 AI 운영(AI_OPS) 감사 행 상세에/admin/ai-ops?clubId=…드릴다운 링크를 추가해, 운영자가 감사 신호에서 해당 클럽의 AI job 필터 뷰(원인→조치)로 바로 이동할 수 있게 했습니다./admin/health의 AI provider 카드는 이미/admin/ai-ops로 연결됩니다. 신규 서버 계약 없이 기존target.clubId만 사용하며, P1 필터 모델(?clubId=/?errorCode=)을 SSOT로 재사용합니다. raw provider error/transcript는 노출하지 않습니다. - platform-admin:
/admin/ai-opsnow offers an OWNER/OPERATORRetry commitaction on jobs stuck inCOMMITTING. It recovers the job toSUCCEEDED(reusing the commit service's existing recovery transition) so the host can re-commit, without admin writing any session content and without deleting the result snapshot. The action is audit-logged (RETRY_COMMIT, COMMITTING→SUCCEEDED) and SUPPORT is denied. No new generation state or transition semantics were introduced. - platform-admin:
/admin/ai-opssummary now shows a 7/30/90-day cost/usage trend (?window=) with current-vs-prior delta. The JDBC adapter returns only raw window cost/count; the application service derives delta/availability (pure, unit-tested) and reportsNOT_ENOUGH_DATAhonestly when the prior window had no jobs. No charting library added; the month-to-date headline is unchanged. aigen-local window enum keeps the slice framework-independent. - platform-admin:
/admin/ai-opsfailure codes are now drilldown controls. Selecting a failure code filters the job list to the affected clubs/sessions and reflects the filter in URL state (?errorCode=), with a "전체 보기" control to clear it. Filtered empty states stay honest ("이 필터에 해당하는 AI job이 없습니다.") and no raw provider error/content fields are exposed. - deploy:
deploy/oci/backup-mysql.service+backup-mysql.timer를 추가해 04:15 UTC에 MySQL dump → OCI Object Storage 업로드를 자동화합니다. 복구·검증·보존(30/6/1) 절차는docs/operations/runbooks/db-backup.md에 정리합니다. - deploy: post-deploy watch가 부모 attempt id를 자식 attempt로 전파하도록 수정해 배포 ledger의 attempt 계보가 정확히 이어집니다 (
deploy/oci/watch-compose-post-deploy.sh,deploy/oci/tests/watch-attempt-id.test.sh). - scripts:
scripts/pre-push-check.sh에--release/READMATES_PRE_PUSH_RELEASE=true조건의CHANGELOG Unreleasedguard를 추가했습니다. concrete 카테고리 헤더, feature-style bold marker, 두 개 이상 placeholder를 거부합니다.--no-changelog-check로 비상 우회하며, branch protection bypass 정책은docs/development/release-management.md에 함께 문서화했습니다. - docs: graphify 채택 워크플로(
docs/development/graphify.md,.graphifyignore,graphify-out/ignore)를 도입해 아키텍처 질문과 영향도 분석에 scoped graph 탐색을 사용할 수 있게 했습니다. 산출물은 공개 저장소에 push하지 않고 로컬 보조로만 사용합니다. - auth/dev-login: 로컬 로그인 패널에 platform admin OWNER fixture shortcut을 추가하고, admin-only 계정의 dev session이
/admin진입·/api/auth/me응답·admin API 권한을 모두 보존하도록 auth 응답과 통합 테스트를 보강했습니다./admin/todayloader는 AI Ops가 disabled 상태에서 503을 반환해도 나머지 운영 콘솔 데이터를 계속 렌더링합니다. - observability: wire Prometheus + Alertmanager into OCI compose with SMTP routing.
Addsdeploy/oci/prometheus/,deploy/oci/alertmanager/, rule files mirroring
docs/operations/observability/alerts.md(notification/http/jvm/security/redis/targets).
Introducesreadmates.notifications.delivery.latencyhistogram at the outbox
PUBLISHED transition and wiresreadmates.aigen.queue.depthto the Redis job
store (PENDING+RUNNING count). Reconcilesslos.yamlas SSOT withslos.md
enforced bySloCatalogDocsConsistencyTest. Addsobservability-bootstrapand
slo-monthly-reportrunbooks, and a public-release scan for observability dirs. - platform-admin: introduce health snapshot route covering service, queue, AI, outbox, deploy signals.
/admin/healthflips from COMING-SOON to READY with a 7-card grid backed by/api/admin/health/snapshot.
In-process Micrometer for DB pool, Redis, outbox backlog, and the deploy attempt tail; local Prometheus
HTTP for Kafka consumer lag, AI provider availability (readmates_aigen_jobs_completed_total), and
notification dispatch success ratio. 10-second@Scheduledrefresh into anAtomicReferencecache;
per-card failures stay isolated (one provider down → that card only isstatus=unknown). - Hardened
/admin/healthwith a pinned camelCase snapshot contract, seven-card fixture coverage, refresh/stale UI, deploy strip rendering, and isolated provider refresh behavior. - platform-admin: ship
/admin/auditas a read-only operating ledger over platform, club, notification replay, and AI audit sources. The route uses safe metadata projection, role-aware masking, cursor pagination, and S8-compatible filter vocabulary without exposing raw provider errors, email bodies, transcripts, or generated result JSON. - platform-admin:
/admin/todaynow shows an operations ledger that prioritizes club readiness, domain, notification, and AI Ops work. - platform-admin: expand the operating console with notification operations, club operations, and support workbench slices.
/api/admin/notifications/*adds read-only ledgers plus OWNER/OPERATOR two-step replay preview/confirm with an audit trail in Flyway V35.
/api/admin/clubs/{clubId}/operationsreturns aggregate-only readiness, member/session, notification, and AI usage signals without raw member email/body fields.
/api/admin/support/*adds masked user search, grant ledger, 24-hour maximum grant creation, duplicate-active protection, and revoke support. - frontend/query: move admin notification ledgers, club operations snapshots, and support search/grants into platform-admin Query modules with route loader seeding and focused invalidation.
/admin/healthoutbox drilldowns now target/admin/notifications?focus=.... - architecture: server slice registry now covers
admin.audit,admin.health, andaigen;aigenpasses application-safe actor values instead of web/session carriers. Frontend boundary tests also enforce Query module imports, and/admin/healthkeeps data orchestration in the route layer with presentation-only UI components. - public-release: public release documentation now matches the helper scripts:
docs/superpowers/remains a private historical archive outside the clean release candidate, while current sou...
ReadMates v1.11.0
Highlights
- 호스트 세션 기록 완성 UX 정리: 호스트 세션 편집기에서 단독 피드백 문서 업로드 경로를 제거하고, AI 생성 기본 경로와 외부 JSON fallback을 하나의
세션 기록 완성패널로 통합했습니다. 새 피드백 문서 저장은 세션 기록 패키지 commit을 통해서만 발생하며, 기존FEEDBACK_DOCUMENT_PUBLISHED알림 이벤트는 JSON import와 AI commit 경로에서 동일하게 기록됩니다. - platform-admin: 플랫폼 운영자용 triage 콘솔(
/admin) — 온보딩 큐, 클럽 디렉터리, 클럽 상세 + Support access grant 패널을 단일 워크벤치로 통합. OWNER 전용 support access, 라이프사이클 우선 정렬, 온보딩 결과의 즉시 선택 반영. - AI 생성 job state machine 정리: AI 세션 생성 job에
COMMITTING/COMMITTEDterminal path를 추가하고, Redis job store의 상태 전이를 CAS로 강제해 worker completion, regenerate, commit, cancel 경합이 서로 결과 payload를 덮어쓰지 않도록 했습니다. Commit/cancel 이후에는 transcript/result payload를 지우되 terminal hash는 TTL까지 남겨 프런트가COMMITTED상태를 확인하고 polling을 종료할 수 있습니다. - CI 안정화와 로컬 사전 게이트 정리:
scripts/pre-push-check.sh로 push 전 frontend coverage/build/Zod fixture/backend check/public-release scanner를 한 번에 실행할 수 있게 했고, auth context 비동기 상태 assertion과 notification logger capture 테스트에 flake 방지 락을 추가했습니다.
Engineering Proof Portfolio
- Add reviewer-facing showcase index, guest-mode walkthrough, architecture evidence, engineering confidence, and operational proof docs under
docs/showcase/. - Add a "How to Review This Project" entry point to
README.mdpointing at the showcase set. - Add
scripts/pre-push-check.shand document the standard/full/release modes inscripts/README.md,README.md, anddocs/development/test-guide.md. - Migrate
host/membersserver state to TanStack Query (route loader factory seeds query cache; mutations invalidate on success; UI remains prop-driven). Documented indocs/development/server-state-migration.md. - Plan host notifications query migration as a separate slice in
docs/superpowers/plans/2026-05-17-readmates-host-notifications-query-migration.md. - Migrate
host/notificationsserver state to TanStack Query: loader seeding, query-owned event/delivery/audit/manual ledgers, mutation invalidation for process/retry/restore/test-mail/confirm, and local-only manual preview/selection state. - Migrate
host/sessionsserver state to TanStack Query: dashboard current/session list, editor detail/manual dispatch reads, create/update/delete/open/close/publish/publication/attendance/visibility/import-commit mutation invalidation, and shared session selector cache for host notifications. - refactor(front): migrate
current-sessionroute to TanStack Query loader seeding and mutation hooks; remove the customreadmates:route-refreshevent and the route-levelcurrentSessionAction. - refactor(front): extract
front/shared/query/cursor-paginationand apply normalized helpers across host notifications/sessions/archive load-more paths. - refactor(front): move platform-admin summary/clubs/support-grants ownership to Query cache with explicit per-mutation cache strategies (targeted-update for domain check/club update/support grants; targeted-update + invalidate for onboarding commit).
- test: stabilize CI flakes by waiting for async auth state transitions in
auth-context.test.tsxand serializing notification delivery logger capture tests with@ResourceLock("NotificationDeliveryEngineLogger"). - Document the server transaction boundary policy (application-service-owned
@Transactional; adapters stay non-transactional) indocs/development/technical-decisions.md. - Refactor
JdbcHostSessionWriteAdapterto drop redundant adapter-level@Transactionalannotations, aligning with the documented policy.
AI Generation Job Lifecycle
- Added
AiGenerationJobTransitionPolicyto centralize allowed actions: worker starts only fromPENDING, worker completion only fromRUNNING, regenerate/commit only fromSUCCEEDED, and cancel only fromPENDING/RUNNING/SUCCEEDED. - Added Redis atomic operations for
transitionStatus,saveResultIfStatus,incrementLlmCallCount, and transient payload deletion. Worker success records incurred cost before theRUNNING -> SUCCEEDEDCAS so cancel races do not drop accounting, while stale completions stop without rewriting cancelled/committed jobs. - Commit now moves
SUCCEEDED -> COMMITTING -> COMMITTED, validates override snapshots before saving them, restoresSUCCEEDEDwhen downstream commit validation fails, and deletes only transcript/result payloads after a successful commit so terminal job status remains readable until TTL. - Regeneration validates the patched full snapshot before persisting and saves it only while the job is still
SUCCEEDED. The per-job LLM call counter now applies to worker retries and regenerations, returning typedMAX_CALLS_EXCEEDEDwithout calling the provider once the hard cap is crossed. - Frontend AI polling now treats
COMMITTINGas an active saving state andCOMMITTEDas the terminal success state, then calls the editor refresh callback once after the server confirms the committed job.
Test Suite Curation
- test: prune
front/tests/unit/vitest-config.test.ts(자기 자신을 동어반복하는 vitest 설정 검증)과aigen-coverage.test.tsx의 230줄 filler — PREVIEW 상태에서 localStorage draft가 server result를 이긴다는 유니크 검증만 co-location 컨벤션에 맞춰AiGenerateTab.draft-restoration.test.tsx로 추출. - test(design-system):
badge,surface컴포넌트 테스트 삭제 +avatar-chip,book-cover,button,document-panel,state-panel,text-field테스트에서 CSS class snapshot 어설션 제거. Korean initial derivation, label/input binding, region/status role, default button type 같은 a11y/동작 검증만 유지. 디자인 클래스명을 리네임해도 테스트가 깨지지 않으면서 사용자가 실제로 의존하는 계약은 보존.
Deployment Notes
- DB migration: 없음. Flyway에서 적용되는 새 V*.sql 파일이 없으므로 DB 작업은 생략 가능.
- 배포 순서: server image → 프론트 순. 1)
v*tag push가Deploy Server Imageworkflow를 트리거해 GHCRreadmates-server:v1.11.0이미지를 scan/promote합니다. 2) 같은 tag로Deploy Frontworkflow가 Cloudflare Pages production에 배포합니다. 3) 서버 코드 변경이 포함되어 있으므로 OCI Compose stack을./deploy/oci/05-deploy-compose-stack.sh로 새 image tag에 맞춰 promote해야 production 백엔드가 실제로 갱신됩니다. - 새 환경 변수: 없음. AIGEN 관련 설정은 v1.10.x에서 도입된 키를 그대로 사용합니다.
- Smoke 기대값 (배포 후):
GET /api/bff/api/auth/me→ 200 (비로그인 200 응답 —authenticated: falsebody)GET /oauth2/authorization/google→ 302 redirectGET /api/bff/api/host/sessions→ 401 when anonymous- 호스트 로그인 후
/host워크벤치에서 세션 편집기의세션 기록 완성패널이 AI 생성/JSON import 통합 형태로 표시되어야 함. - OWNER 권한 사용자에서
/admin라우트가 platform-admin 워크벤치(온보딩 큐 + 클럽 디렉터리)를 렌더링해야 함.
Verification
./scripts/pre-push-check.sh(standard) — all green- Frontend lint, test:coverage (lines 90.09 / statements 90.09 / functions 84.69 / branches 86.67 vs thresholds 87/87/83/84), build
- Backend
./server/gradlew -p server check— ktlint + detekt + unitTest + architectureTest + jacoco 모두 UP-TO-DATE, BUILD SUCCESSFUL in 5s - Zod fixtures
git diff --exit-code tests/unit/__fixtures__/zod-schemas/— no diff - Public release candidate gitleaks scan — no leaks found (7.09 MB scanned in 575ms)
pnpm design:check— design system build + test, design docs build + test 모두 통과 (13 tests passed)- 미실행:
pnpm --dir front test:e2e(Playwright),./server/gradlew -p server integrationTest(Testcontainers). E2E 스펙 변경이 없고 backend integration도 v1.10.x 이후 contract 변경이 없어 정기 CI shard에서 검증되는 범위로 충분하다고 판단. 운영 smoke에서 BFF/auth 경로를 한번 더 확인합니다.
v1.10.2: Schema collation alignment + AIGEN startup guard
v1.10.0/v1.10.1 incident chain의 사후 정리 패치. 기능 변경 없음, 운영 견고성 향상.
Added
- V33 schema-default collation alignment — 운영 schema 기본 collation을
utf8mb4_unicode_ci→utf8mb4_0900_ai_ci로 정렬해 기존 테이블 collation과 일치시킵니다. 기존 데이터/FK는 그대로 유지, 향후 COLLATE를 누락한 migration도 자동으로 호환 collation을 상속합니다. AiGenerationConfigValidator—@PostConstruct시점에readmates.aigen.enabled=true인데AiGenerationJobQueue빈이 wired되지 않은 경우 actionable 메시지로 fail-fast. v1.10.1 부팅 직후 발생한 "No qualifying bean of type 'AiGenerationJobQueue'" 류 미스컨피그를 즉시 진단 가능한 형태로 변환합니다.- FK collation 회귀 테스트 —
MySqlFlywayMigrationTest에 schema-default vsclubs.idcollation mismatch를 강제 재현하는 통합 테스트 추가. COLLATE 미지정 FK 거부 + 명시 COLLATE FK 성공 양방향 검증.
Deployment
READMATES_SERVER_IMAGEGitHub Variable::v1.10.2sync-configworkflow 실행 → compose force-recreate- Flyway: V29~V32는 그대로, V33만 새로 적용 (idempotent ALTER DATABASE)
Verification
- Local: validator unit test 3/3, MySqlFlywayMigrationTest 7/7 (새 회귀 테스트 포함), RedisAiGen 통합 17/17 (validator coexistence 확인).
- CI: PR #8 — 9/9 checks pass.
🤖 Generated with Claude Code
v1.10.1 — AIGEN GA + secrets sync + observability
Highlights
- In-app AI 세션 생성 GA: 호스트 세션 편집기 안에서 LLM(OpenAI
gpt-5.4-mini, Geminigemini-3-flash, Claude 옵션)으로 세션 회차 기록을 초안 생성 → 미리보기 편집 → 커밋하는 전체 흐름이 production에 enable됩니다. Kill switch + provider allowlist + 클럽 월 $20 cost cap이 모두 운영 가능 상태로 출시됩니다. - 운영 시크릿/설정의 단일 source-of-truth: 운영 환경변수와 시크릿 관리를 SSH 편집에서 GitHub Actions
sync-config워크플로로 이관해, 변경 이력이 Git/Actions 로그에 남고 secret 갱신·롤백 절차가 표준화됐습니다. - Observability backbone: BFF → Spring → Kafka → SMTP까지 동일한
X-Readmates-Request-Id가 흐르고 모든 컴포넌트가 JSON 로그를 출력합니다. SLO 카탈로그가 startup schema 검증으로 로드되고, Grafana dashboard 2종과 AI 생성 전용 5개 alert / 8개 panel이 함께 추가됐습니다. - Platform Admin & Design System: 클럽 생성/첫 호스트 셋업/공개 노출/도메인 준비 흐름을 호스트 앱과 분리된 platform admin 권한 경계에서 운영하고, 새 pnpm workspace 루트의
design/system패키지가 디자인 시스템 source-of-truth로 분리됐습니다.
Fixed (v1.10.0 → v1.10.1)
- db:
V31__create_ai_generation_club_defaults.sql의club_id/updated_by컬럼에CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci를 명시해clubs.id와 collation을 일치시켰습니다. 운영 schema 기본 collation이utf8mb4_unicode_ci였던 탓에 새 컬럼이unicode_ci로 생성되어 FK가 거부되던 문제를 해소합니다. - db:
V32__platform_admin_onboarding.sql의 신규invitations.invited_by_platform_admin_user_id컬럼도 동일 이유로character set utf8mb4 collate utf8mb4_0900_ai_ci를 명시해users.id와 정렬했습니다. - deploy:
sync-config워크플로가READMATES_AIGEN_KAFKA_ENABLED와READMATES_AIGEN_KAFKA_BOOTSTRAP_SERVERS환경변수를 운영.env에 전파하도록 보강.AiGenerationOrchestrator가 의존하는AiGenerationJobQueue빈의 유일한 production 구현이 Kafka adapter 이므로, AIGEN 을 켜려면 두 변수가 반드시 함께 설정되어야 합니다.
DB Migration
| Version | 설명 |
|---|---|
| V29 | correlation_request_id_columns — outbox/manual dispatch 테이블에 request_id 컬럼 추가 |
| V30 | create_ai_generation_audit_log — AI 생성 감사 로그 (provider/model/status/token/cost) |
| V31 | create_ai_generation_club_defaults — 클럽별 AI 기본 모델 + 명시적 collation |
| V32 | platform_admin_onboarding — clubs public_visibility, invitations platform-admin inviter FK + 명시적 collation |
전부 forward-only / additive. Rollback 시 schema 추가분이 남지만 v1.9.x 코드는 이를 무시합니다.
Deployment Notes
- Tag push 가
deploy-front.yml(Cloudflare Pages) 와deploy-server.yml(GHCR 빌드 + Trivy + release tag promote) 를 자동 트리거합니다. - 서버 promote 후
READMATES_SERVER_IMAGEGitHub Variable 을:v1.10.1로 bump →sync-config(restart_api=true) 실행 → compose 가 새 이미지로force-recreate. - AIGEN 운영 토글:
READMATES_AIGEN_ENABLED=true,READMATES_AIGEN_ENABLED_PROVIDERS=OPENAI,GEMINI,READMATES_AIGEN_KAFKA_ENABLED=true,READMATES_AIGEN_KAFKA_BOOTSTRAP_SERVERS=redpanda:9092가 모두 prod 변수에 설정되어 있어야 합니다. - 운영 smoke 기대값:
curl /internal/health→{"status":"UP","kind":"liveness"},GET /api/host/clubs/<club>/ai-defaults→ 401(미인증) 또는 200(호스트), 503AI_DISABLED아님, Flyway version=32.
Rollback
READMATES_SERVER_IMAGE 를 :v1.9.0 로 되돌리고 sync-config 재실행. V29~V32 schema 는 남지만 v1.9.0 코드가 이를 참조하지 않으므로 무해.
Verification
CI run 25988435608 (commit 101e0fd): 8 잡 success (Frontend 는 flake 1건, v1.10.1 main 패치로 별도 close). 로컬 ./server/gradlew integrationTest --tests "MySqlFlywayMigrationTest" pass. 운영 V31 collation dry-run pass. 운영 컨테이너 부팅 후 Flyway version=32, /internal/health UP, AIGEN 컨트롤러 401 응답으로 활성 확인.
v1.10.0 (withdrawn)
WITHDRAWN — do not deploy this tag.
v1.10.0 의 V31 Flyway migration이 운영 MySQL에서 FK collation 불일치(errno 3780)로 부팅에 실패해, 배포 직후 v1.9.0 으로 자동 롤백되었습니다. 대체 패치는 v1.10.1 을 사용하세요.
세부 변경 사항은 CHANGELOG.md v1.10.0 섹션 을 참고하세요 (기능 자체는 v1.10.1 에 그대로 포함되어 있습니다).
ReadMates v1.9.0
Highlights
v1.8.3 이후 누적된 변경은 호스트 알림 운영을 "상태 조회/재처리"에서 "세션별 수동 발송 계획, 미리보기, 확정, 감사"까지 확장하고, 호스트 세션 편집기에 외부에서 정리한 세션 기록 JSON 가져오기를 더하며, 테스트/빌드 runtime을 빠른 피드백 lane과 release baseline으로 분리하는 데 초점을 둡니다. DB migration V27, V28이 포함됩니다.
Added
- 호스트 수동 알림 발송 워크벤치:
/app/host/notifications에서 세션을 선택하고NEXT_BOOK_PUBLISHED,SESSION_REMINDER_DUE,FEEDBACK_DOCUMENT_PUBLISHED템플릿을 고른 뒤 대상 그룹(ALL_ACTIVE_MEMBERS,SESSION_PARTICIPANTS,CONFIRMED_ATTENDEES), 채널(IN_APP,EMAIL,BOTH), 멤버별 포함/제외를 조합해 알림을 발송할 수 있습니다. - 수동 발송 preview/confirm 계약:
GET /api/host/notifications/manual/options,POST /api/host/notifications/manual/preview,POST /api/host/notifications/manual,GET /api/host/notifications/manual/dispatches를 추가했습니다. Preview는 대상 수, in-app/email 예상 건수, 이메일 선호도 skip, 이메일 누락, 중복 발송 여부를 반환합니다. - 수동 발송 감사 원장:
notification_manual_dispatch_previews,notification_manual_dispatches테이블을 추가했습니다. Confirm은 preview selection hash와 10분 TTL을 확인하고, 같은 preview로 중복 confirm해도 기존 dispatch 결과를 반환하도록 hardened path를 둡니다. - 수동 발송 E2E 커버리지: Playwright
manual-notifications.spec.ts가 세션 선택, preview/confirm, 중복 재발송 확인, 피드백 문서 알림 조건, in-app 수신 확인을 검증합니다. - Backend test fast lanes: Gradle
unitTest,integrationTest,architectureTesttask를 추가하고, Gradle test JVM을 Java 21 toolchain으로 고정했습니다. - 프런트 Vitest v8 coverage gate:
@vitest/coverage-v8를 dev dep으로 추가하고pnpm --dir front test:coverage(=vitest run --coverage) 스크립트를 도입했습니다. Coverage thresholds는 현재 baseline에서 -2pp 정수 floor로 고정(lines/statements 87, functions 83, branches 84)했고, CI front job은pnpm test:coverage로 전환되어front-coverage아티팩트를 always upload(14일 보존)합니다. 기존 실패시frontend-reports업로드는 유지합니다. - 서버 ktlint baseline gate:
org.jlleitschuh.gradle.ktlint12.1.1 Gradle plugin과 ktlint tool 1.7.1(Kotlin 2.2 호환을 위해 spec의 1.3.1에서 상향)을 도입했습니다. 기존 위반은server/config/ktlint/baseline.xml(336 lines)로 grandfather 처리하고 신규 위반만 차단합니다. 1회성 auto-format으로 server/src 하위 329 파일이 line wrap, trailing comma, parameter newline, package decl 포맷을 baseline 기준으로 정렬됐습니다../gradlew check에 wiring되어 PR 회귀를 막습니다. - 서버 detekt baseline gate:
io.gitlab.arturbosch.detekt1.23.7과 defaultserver/config/detekt/detekt.yml(785 lines),server/config/detekt/baseline.xml(540 lines)을 도입했습니다. detekt 1.23.x가 호스트 JDK 25에서 동작하도록server/gradle/gradle-daemon-jvm.properties에toolchainVersion=21daemon JVM pin을 추가하고, detekt classpath는 Kotlin 2.0.10으로 고정합니다(Detekt*task는jvmTarget=21). 기존 위반은 baseline grandfather,check에 wiring되어 신규 위반을 차단합니다. - 서버 JaCoCo line coverage gate:
jacoco플러그인(toolVersion 0.8.12)을 적용해unitTesttask에JacocoTaskExtension을 붙여build/jacoco/unitTest.exec를 생성하고,jacocoTestReport는Application/dto/config클래스 디렉터리를 제외합니다.jacocoTestCoverageVerification은 LINECOVEREDRATIOminimum 0.23(현재 측정치 0.2504 − 2pp baseline)으로 고정했고,check가 verification에 의존합니다. - CI 서버 quality gate 통합: backend job의 기존
Teststep을./gradlew check(ktlint + detekt + tests + JaCoCo verify) 단일 호출로 교체하고,architectureTeststep을 별도 실행합니다. detekt/jacoco/ktlint report 아티팩트는if: always()로 항상 업로드하고, 기존 실패시backend-reports(tests/test-results) 업로드는 유지합니다. - 서버 CQRS read/write 패키지 분리 컨벤션 + ArchUnit 강제:
note/publication/archive의 read-side application service에@ReadOnlyApplicationService마커(com.readmates.shared.architecture)를 부착하고,ServerArchitectureBoundaryTest에 두 ArchUnit 규칙을 추가했습니다 —read-only application services must not depend on mutation ports(*SavePort/*UpdatePort/*DeletePort/*WriterPort/*StorePort/*WritePortsuffix 의*.port.out.*의존 차단) 와read-only application services must not be Transactional.archive/application/service/MemberArchiveReviewService는 write-side(write port 의존 +@Transactional)이므로 marker 미부착.feedback은 mixed(upload mutation + 조회)로 분류되어 marker 미부착, 향후 분리 후보. 컨벤션 전체는docs/development/architecture.md의 "CQRS Read vs Write Package Split" 섹션 참고. - 세션 기록 JSON 가져오기: 호스트 세션 편집기에서
readmates-session-import:v1JSON을 preview한 뒤 저장할 수 있습니다. 저장은 해당 회차의 공개 요약, 하이라이트, 한줄평, 피드백 문서를 한 번에 교체하고,HOST_ONLY공개 범위나 세션 metadata/참석자 매칭 오류는 저장 전에 막습니다.
Changed
- 알림 event ledger metadata 확장: host event/delivery 목록에서
source=AUTOMATIC|MANUAL과 manual dispatch metadata를 구분합니다. Host-facing 응답은 요청자 표시명, 대상 수, 예상 채널별 건수, 재발송 여부만 노출하고 raw email body는 계속 노출하지 않습니다. - 프런트 테스트 runtime 분리: Vitest config를 Node project와
jsdomproject로 나눠 순수 model/contract 테스트가 DOM 환경을 불필요하게 띄우지 않도록 했습니다. - 프런트 빌드 타겟 ES2022:
front/tsconfig.json의compilerOptions.target을ES2017→ES2022로 올렸습니다. Vite 8 + 모던 브라우저 대상이므로Object.hasOwn,Error.cause, top-levelawait, private class fields의 불필요한 downlevel을 제거합니다.lib는 그대로 유지하여 타입 표면 변화는 없습니다. - Playwright worker opt-in: 기본 worker는 seeded DB 공유 때문에 1로 유지하고,
PLAYWRIGHT_WORKERS환경 변수로만 병렬 실행을 실험할 수 있게 했습니다. - E2E DB reset 통합: E2E helper가 generated session, invited member, Google login, manual notification artifact cleanup을 한 번의 SQL batch로 묶을 수 있게 했습니다.
- 서버 Docker image layer 최적화:
server/Dockerfile과server/Dockerfile.release가 Spring Boot layertools로 dependency/application layer를 분리하고JarLauncherentrypoint를 사용합니다. - 서버 Docker build 메모리 제한: local Dockerfile builder 단계에서 Gradle max worker와 JVM 메모리 옵션을 명시해 작은 빌드 환경의 OOM 가능성을 낮췄습니다.
.env.example관심사별 재그룹화: 9개 번호 섹션(Spring 서버, Auth & BFF, Frontend / Cloudflare Pages, Local MySQL, Redis, Kafka & 알림, SMTP, OCI Compose stack, Legacy / rollback)으로 정리하고 인라인 주석을 추가했습니다. 키 이름·기본값·placeholder 포맷 변경 없음, 중복 표기되던READMATES_BFF_SECRET(S)라인은 Auth & BFF 섹션으로 통합했습니다.- 프런트 테스트 co-location 컨벤션: 신규 테스트는 대상 소스 옆
*.test.ts(x)로 두는 컨벤션을front/AGENTS.md에 명시했습니다. Vitest configinclude글롭을src/**/*.test.{ts,tsx},features/**/*.test.{ts,tsx},shared/**/*.test.{ts,tsx}로 확장하고 기존tests/unit/**패턴과 node/jsdom project 분리는 그대로 유지합니다. 기존 테스트는 server testcontainer fixture 호환성을 위해 이동하지 않습니다. - 프런트 server state를 TanStack Query v5로 이관 시작: 앱 루트(
front/src/main.tsx)에 단일QueryClient를QueryClientProvider로 주입하고, 라우터(front/src/app/router.tsx)는createReadmatesRouter()에서{router, queryClient}를 반환하도록 바뀌어 loader와 컴포넌트가 같은 cache를 공유합니다. 첫 reference migration은 호스트 초대 목록(/app/host/invitations)으로, list query는host-invitation-queries.ts의queryOptions를 통해useQuery로 읽고, create/revoke는useMutation+ targeted invalidation으로 처리하며, loader는setQueryData로 SSR 친화적 hand-off를 수행합니다. 마이그레이션 진행 상황과 다음 단계는 docs/development/server-state-migration.md에 정리합니다. - 프런트 router.tsx variant별 모듈 분리: 단일 파일에 모여 있던 route 정의를 variant별 모듈로 분리했습니다.
front/src/app/router.tsx는 24-line composition root로 축소되어createReadmatesRouter()에서QueryClient를 생성하고 sub-route 모듈을 조합하는 역할만 합니다. 실제 route 정의는front/src/app/routes/{public,auth,member,host}.tsx로 옮겨져 각각publicRoutes(),authRoutes(),memberRoutes(),hostRoutes(queryClient)로 export됩니다. URL 라우팅 매트릭스, guard(RequireAuth/RequireHost/RequireMemberApp/RequirePlatformAdmin),errorElement,lazy()경계는 그대로 유지됩니다.
Deployment Notes
- DB migration: V27(
notification_manual_dispatch_previews,notification_manual_dispatches), V28(preview consumed 상태와 preview-dispatch 1:1 제약) 적용 필요. - 새 환경 변수: 없음.
- 배포 순서: 서버 먼저 배포해 새 API와 migration을 적용한 뒤 프론트엔드를 배포합니다. 구버전 프론트는 새 수동 발송 API를 호출하지 않으므로 서버 선배포가 안전합니다.
- 운영 확인: 배포 후 호스트 알림 운영 페이지에서 수동 발송 preview가 대상 수와 경고를 반환하는지, confirm 후 event ledger에
source=MANUALrow가 생기는지, Kafka/SMTP가 꺼진 환경이면notification_event_outbox에PENDINGrow가 남는지 확인합니다.
Verification
pnpm --dir front lint— exit 0. 로컬 ignored/generatedfront/coveragereport의 unused eslint-disable warning 1건이 출력됐지만 error는 없었습니다.pnpm --dir front test— 60 files / 761 tests passed.pnpm --dir front build— exit 0.pnpm --dir front test:e2e— 28 tests passed../server/gradlew -p server clean test— BUILD SUCCESSFUL.pnpm --dir front zod:export-fixtures && git diff --exit-code front/tests/unit/__fixtures__/zod-schemas/— fixture diff 없음../scripts/build-public-release-candidate.sh && ./scripts/public-release-check.sh .tmp/public-release-candidate— passed, gitleaks found no leaks.git diff --check -- CHANGELOG.md README.md docs/deploy/README.md docs/deploy/release-publish-runbook.md docs/development/release-management.md— 출력 없음.- 변경 문서 대상 공개 안전 스캔(
rg정규식) — 실제 secret, private host, 로컬 절대 경로 없음. 일반 path와 placeholder만 확인됨.
ReadMates v1.8.3
Highlights
ReadMates v1.8.3은 v1.8.2 서버 이미지 Trivy 스캔에서 남은 Netty DNS codec 취약점 한 건을 해소하는 패치 릴리스입니다. DB migration 없음. 사용자 기능 변경 없음.
Fixed
- 서버 이미지 Trivy 스캔 Netty 잔여 항목 복구:
io.netty:netty-codec-dns를 4.2.13.Final로 고정해 CVE-2026-42579가 포함된 4.2.12.Final 런타임 jar가 이미지에 들어가지 않도록 했습니다.
Deployment Notes
- DB migration: 없음.
- 배포 순서: v1.8.3 태그 이미지의 Trivy 스캔과 release tag promotion이 성공한 뒤 OCI compose stack에 반영하고, 같은 태그의 Cloudflare Pages 프론트엔드 배포 상태를 확인합니다.
- v1.8.2 주의: v1.8.2 main CI와 프론트엔드 배포는 통과했지만, 서버 이미지 promotion은 Netty DNS codec 스캔 실패로 완료되지 않았습니다. 운영 서버에는 v1.8.3 이미지를 사용하세요.
Verification
./server/gradlew -p server dependencyInsight --dependency netty-codec-dns --configuration runtimeClasspath— Netty DNS codec 4.2.13.Final 확인../server/gradlew -p server clean test bootJar— BUILD SUCCESSFUL../scripts/build-public-release-candidate.sh && ./scripts/public-release-check.sh .tmp/public-release-candidate— passed, gitleaks found no leaks.- v1.8.2
Deploy Server Imageworkflow의 Trivy 로그에서 CVE-2026-42579 단일 HIGH 실패 원인 확인 후 반영.