Skip to content

Releases: beyondwin/ReadMates

ReadMates v1.14.1

21 Jun 15:14

Choose a tag to compare

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를 Netty 4.2.15.Final과 Spring Kafka 4.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. Publish v1.14.1, confirm Deploy Server Image scan/promote, promote OCI Compose backend to ghcr.io/<owner>/<repo>/readmates-server:v1.14.1, then run sanitized BFF/OAuth/admin/host smoke checks. Deploy Front will also rerun from the patch tag.

Verification

  • v1.14.0 release operation (2026-06-21): Deploy Front passed for tag v1.14.0; Deploy Server Image failed before release-tag promotion at Trivy scan on Ubuntu libssl3/openssl, Netty, and Spring Kafka fixed HIGH findings.
  • Local dependency verification (2026-06-21): ./server/gradlew -p server dependencyInsight --dependency netty-handler --configuration runtimeClasspath selected Netty 4.2.15.Final; ./server/gradlew -p server dependencyInsight --dependency spring-kafka --configuration runtimeClasspath selected Spring Kafka 4.0.6.
  • Local server/image verification (2026-06-21): ./server/gradlew -p server clean check bootJar passed; docker build -f server/Dockerfile.release server -t readmates-server:v1.14.1-local passed; the local image reports libssl3/openssl 3.0.2-0ubuntu1.25 and contains netty-handler-4.2.15.Final, netty-resolver-dns-4.2.15.Final, and spring-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-local passed with 0 Ubuntu and Java HIGH/CRITICAL findings.
  • Release operation (2026-06-21): Deploy Front passed for tag v1.14.1; Deploy Server Image passed, scanned ghcr.io/beyondwin/readmates/readmates-server@sha256:9254b7ff380b6fa869ec6694acc8ea2a13010940445b52a595968712030e528f, and promoted the same digest to ghcr.io/beyondwin/readmates/readmates-server:v1.14.1.
  • OCI backend promotion (2026-06-21): deploy/oci/05-deploy-compose-stack.sh promoted the Compose stack to ghcr.io/beyondwin/readmates/readmates-server:v1.14.1; readmates-api reported 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

07 Jun 09:39

Choose a tag to compare

Highlights

  • release policy: solo-admin 운영 현실에 맞춰 main branch protection에서 불가능한 PR/code-owner self-review 요구를 제거하고, 필수 Frontend/Backend status 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 questions full-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 attendee participationStatus aligned 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%에 도달한 회차 기준)을 별도의 정직한 지표로 분리해 보여 줍니다. MyPageResponsecompletedReadingCount와 회차별 readingProgress가 추가됐고, DB migration·auth/BFF 토큰 변경은 없습니다.
  • release validation scripts: Docker 이미지 기본 entrypoint와 충돌하던 Prometheus/Alertmanager 검증 스크립트의 컨테이너 실행 방식을 고치고, AiGenBudgetExhaustion rule의 금액 템플릿을 promtool 유효 문법으로 바로잡아 ./scripts/pre-push-check.sh --full --release가 관측 설정 검증까지 통과하도록 했습니다.

Added

  • outbound resilience: Outbound adapter(외부 HTTP/Redis)에 Resilience4j CircuitBreaker 적용. fail-open 정책 유지, 회로 상태를 Micrometer 카운터와 /admin/health outbound-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/ui primitive에 대한 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/overviewadmin.analytics_overview.v2로 KPI trend series를 포함하고, my-page 응답은 completedReadingCount와 최근 회차 readingProgress를 포함합니다.
  • 서버/API/frontend contract가 함께 바뀌므로 release tag push 후 Deploy Server Image가 GHCR readmates-server:v1.13.0을 scan/promote한 것을 먼저 확인하고, OCI Compose backend를 같은 image tag로 올린 뒤 final frontend/admin smoke를 수행합니다. Cloudflare Pages Deploy 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.sh and ./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

31 May 13:22

Choose a tag to compare

Fixed

  • server security: override Spring Boot's managed embedded Tomcat version to 11.0.22 so the release image no longer carries the tomcat-embed-core 11.0.21 vulnerabilities reported by the Deploy Server Image Trivy gate.

Deployment Notes

  • Server-only patch release. No DB migration, API contract, auth, BFF token, or frontend behavior change is included.
  • v1.12.0 frontend deployment succeeded, but the server image workflow stopped before release-tag promotion at the vulnerability scan step. Publish and deploy v1.12.1 for the server image instead of promoting the failed v1.12.0 image candidate.

Verification

  • Local release repair (2026-05-31): ./server/gradlew -p server dependencyInsight --dependency tomcat-embed-core --configuration runtimeClasspath — pass; tomcat-embed-core resolved to 11.0.22.
  • Local release repair (2026-05-31): ./server/gradlew -p server check — pass.
  • Production deployment (2026-05-31): Deploy Server Image for tag v1.12.1 — pass; image scan and release-tag promotion completed.
  • Production deployment (2026-05-31): Deploy Front for tag v1.12.1 — pass.
  • Production deployment (2026-05-31): ./deploy/oci/05-deploy-compose-stack.sh with READMATES_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

31 May 13:12
1c321b4

Choose a tag to compare

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·analytics 9개 READY 라우트가 admin-route-catalog SSOT로 구동됩니다.
  • 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, public read path를 Query loader seeding으로 이전하고, AI commit 후 full page reload 대신 관련 Query cache invalidation으로 화면을 갱신합니다.
  • 운영 안전망 보강: 일일 MySQL 백업 systemd timer와 복구 runbook, release-tag Unreleased guard(--release gated, --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.depth as 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-ops now offers an OWNER/OPERATOR Retry commit action on jobs stuck in COMMITTING. It recovers the job to SUCCEEDED (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-ops summary 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 reports NOT_ENOUGH_DATA honestly 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-ops failure 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 Unreleased guard를 추가했습니다. 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/today loader는 AI Ops가 disabled 상태에서 503을 반환해도 나머지 운영 콘솔 데이터를 계속 렌더링합니다.
  • observability: wire Prometheus + Alertmanager into OCI compose with SMTP routing.
    Adds deploy/oci/prometheus/, deploy/oci/alertmanager/, rule files mirroring
    docs/operations/observability/alerts.md (notification/http/jvm/security/redis/targets).
    Introduces readmates.notifications.delivery.latency histogram at the outbox
    PUBLISHED transition and wires readmates.aigen.queue.depth to the Redis job
    store (PENDING+RUNNING count). Reconciles slos.yaml as SSOT with slos.md
    enforced by SloCatalogDocsConsistencyTest. Adds observability-bootstrap and
    slo-monthly-report runbooks, and a public-release scan for observability dirs.
  • platform-admin: introduce health snapshot route covering service, queue, AI, outbox, deploy signals.
    /admin/health flips 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 @Scheduled refresh into an AtomicReference cache;
    per-card failures stay isolated (one provider down → that card only is status=unknown).
  • Hardened /admin/health with a pinned camelCase snapshot contract, seven-card fixture coverage, refresh/stale UI, deploy strip rendering, and isolated provider refresh behavior.
  • platform-admin: ship /admin/audit as 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/today now 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}/operations returns 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/health outbox drilldowns now target /admin/notifications?focus=....
  • architecture: server slice registry now covers admin.audit, admin.health, and aigen; aigen passes application-safe actor values instead of web/session carriers. Frontend boundary tests also enforce Query module imports, and /admin/health keeps 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...
Read more

ReadMates v1.11.0

18 May 11:31

Choose a tag to compare

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/COMMITTED terminal 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.md pointing at the showcase set.
  • Add scripts/pre-push-check.sh and document the standard/full/release modes in scripts/README.md, README.md, and docs/development/test-guide.md.
  • Migrate host/members server state to TanStack Query (route loader factory seeds query cache; mutations invalidate on success; UI remains prop-driven). Documented in docs/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/notifications server 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/sessions server 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-session route to TanStack Query loader seeding and mutation hooks; remove the custom readmates:route-refresh event and the route-level currentSessionAction.
  • refactor(front): extract front/shared/query/cursor-pagination and 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.tsx and serializing notification delivery logger capture tests with @ResourceLock("NotificationDeliveryEngineLogger").
  • Document the server transaction boundary policy (application-service-owned @Transactional; adapters stay non-transactional) in docs/development/technical-decisions.md.
  • Refactor JdbcHostSessionWriteAdapter to drop redundant adapter-level @Transactional annotations, aligning with the documented policy.

AI Generation Job Lifecycle

  • Added AiGenerationJobTransitionPolicy to centralize allowed actions: worker starts only from PENDING, worker completion only from RUNNING, regenerate/commit only from SUCCEEDED, and cancel only from PENDING/RUNNING/SUCCEEDED.
  • Added Redis atomic operations for transitionStatus, saveResultIfStatus, incrementLlmCallCount, and transient payload deletion. Worker success records incurred cost before the RUNNING -> SUCCEEDED CAS 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, restores SUCCEEDED when 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 typed MAX_CALLS_EXCEEDED without calling the provider once the hard cap is crossed.
  • Frontend AI polling now treats COMMITTING as an active saving state and COMMITTED as 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 Image workflow를 트리거해 GHCR readmates-server:v1.11.0 이미지를 scan/promote합니다. 2) 같은 tag로 Deploy Front workflow가 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: false body)
    • GET /oauth2/authorization/google → 302 redirect
    • GET /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

17 May 11:47
507ba2b

Choose a tag to compare

v1.10.0/v1.10.1 incident chain의 사후 정리 패치. 기능 변경 없음, 운영 견고성 향상.

Added

  • V33 schema-default collation alignment — 운영 schema 기본 collation을 utf8mb4_unicode_ciutf8mb4_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 vs clubs.id collation mismatch를 강제 재현하는 통합 테스트 추가. COLLATE 미지정 FK 거부 + 명시 COLLATE FK 성공 양방향 검증.

Deployment

  • READMATES_SERVER_IMAGE GitHub Variable: :v1.10.2
  • sync-config workflow 실행 → 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

17 May 11:18

Choose a tag to compare

Highlights

  • In-app AI 세션 생성 GA: 호스트 세션 편집기 안에서 LLM(OpenAI gpt-5.4-mini, Gemini gemini-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.sqlclub_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_ENABLEDREADMATES_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_IMAGE GitHub 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(호스트), 503 AI_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)

17 May 11:18

Choose a tag to compare

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

14 May 19:34

Choose a tag to compare

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, architectureTest task를 추가하고, 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.ktlint 12.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.detekt 1.23.7과 default server/config/detekt/detekt.yml(785 lines), server/config/detekt/baseline.xml(540 lines)을 도입했습니다. detekt 1.23.x가 호스트 JDK 25에서 동작하도록 server/gradle/gradle-daemon-jvm.propertiestoolchainVersion=21 daemon 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)을 적용해 unitTest task에 JacocoTaskExtension을 붙여 build/jacoco/unitTest.exec를 생성하고, jacocoTestReportApplication/dto/config 클래스 디렉터리를 제외합니다. jacocoTestCoverageVerification은 LINE COVEREDRATIO minimum 0.23(현재 측정치 0.2504 − 2pp baseline)으로 고정했고, check가 verification에 의존합니다.
  • CI 서버 quality gate 통합: backend job의 기존 Test step을 ./gradlew check(ktlint + detekt + tests + JaCoCo verify) 단일 호출로 교체하고, architectureTest step을 별도 실행합니다. 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/*WritePort suffix 의 *.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:v1 JSON을 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와 jsdom project로 나눠 순수 model/contract 테스트가 DOM 환경을 불필요하게 띄우지 않도록 했습니다.
  • 프런트 빌드 타겟 ES2022: front/tsconfig.jsoncompilerOptions.targetES2017ES2022로 올렸습니다. Vite 8 + 모던 브라우저 대상이므로 Object.hasOwn, Error.cause, top-level await, 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/Dockerfileserver/Dockerfile.release가 Spring Boot layertools로 dependency/application layer를 분리하고 JarLauncher entrypoint를 사용합니다.
  • 서버 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 config include 글롭을 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)에 단일 QueryClientQueryClientProvider로 주입하고, 라우터(front/src/app/router.tsx)는 createReadmatesRouter()에서 {router, queryClient}를 반환하도록 바뀌어 loader와 컴포넌트가 같은 cache를 공유합니다. 첫 reference migration은 호스트 초대 목록(/app/host/invitations)으로, list query는 host-invitation-queries.tsqueryOptions를 통해 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=MANUAL row가 생기는지, Kafka/SMTP가 꺼진 환경이면 notification_event_outboxPENDING row가 남는지 확인합니다.

Verification

  • pnpm --dir front lint — exit 0. 로컬 ignored/generated front/coverage report의 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

13 May 06:45

Choose a tag to compare

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 Image workflow의 Trivy 로그에서 CVE-2026-42579 단일 HIGH 실패 원인 확인 후 반영.