Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5ca5c43
feat(server): publish feedback events from session imports
beyondwin May 17, 2026
f3ebec0
fix(admin): restrict support access grants to owners
beyondwin May 17, 2026
71c5662
feat(admin): add triage workbench model
beyondwin May 17, 2026
c17e6eb
refactor(server): remove standalone feedback uploads
beyondwin May 17, 2026
2b1c879
feat(admin): render triage console with selected-club support grants
beyondwin May 17, 2026
b74b3cd
feat(front): unify session record completion
beyondwin May 17, 2026
9728795
feat(admin): sync onboarding results into triage state
beyondwin May 17, 2026
86e209e
fix(front): surface ai unavailable fallback
beyondwin May 17, 2026
40e2741
style(admin): polish triage console layout
beyondwin May 17, 2026
5034082
docs: document session record completion workflow
beyondwin May 17, 2026
1884704
fix(front): replace stale upload copy on host dashboard and editor
beyondwin May 17, 2026
0309c62
docs(admin): document platform triage console
beyondwin May 17, 2026
f0bc331
Merge: session record completion (AI-first, JSON fallback)
beyondwin May 17, 2026
fa42375
fix(admin): render 5th overview metric for domain action required
beyondwin May 17, 2026
d45c08e
Merge branch 'readmates-platform-admin-triage-console-implementation-…
beyondwin May 17, 2026
884f41c
test(aigen): clean notification_event_outbox in integration test tear…
beyondwin May 17, 2026
94d4f7f
docs: add engineering proof portfolio spec
beyondwin May 17, 2026
08d14b9
docs: add engineering proof portfolio plan
beyondwin May 17, 2026
1d16702
docs: align engineering proof portfolio plan and spec with code
beyondwin May 17, 2026
7ff9192
docs: add showcase index
beyondwin May 17, 2026
1bbeb8a
docs: add guest mode walkthrough
beyondwin May 17, 2026
35554da
docs: add architecture evidence map
beyondwin May 17, 2026
dacc892
docs: document engineering confidence evidence
beyondwin May 17, 2026
45c0e4d
docs: add operational proof guide
beyondwin May 17, 2026
21970c3
docs: document transaction boundary policy
beyondwin May 17, 2026
52659e1
docs: add reviewer entry path
beyondwin May 17, 2026
0ee172a
refactor(server): clarify session transaction boundary
beyondwin May 17, 2026
71a8190
feat(front): migrate host members to query cache
beyondwin May 17, 2026
6e66332
docs: plan host notifications query migration
beyondwin May 17, 2026
08087e5
docs: close engineering proof portfolio review
beyondwin May 17, 2026
a521aed
fix(server): wrap host session write adapter expression bodies
beyondwin May 17, 2026
8e0e2b2
build(server): complete ktlint baseline rollout
beyondwin May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ ReadMates는 Git tag와 GitHub Releases를 함께 사용합니다. 이 파일은
### Highlights

- 다음 릴리즈 후보 변경을 이 섹션에 기록합니다.
- **호스트 세션 기록 완성 UX 정리**: 호스트 세션 편집기에서 단독 피드백 문서 업로드 경로를 제거하고, AI 생성 기본 경로와 외부 JSON fallback을 하나의 `세션 기록 완성` 패널로 통합했습니다. 새 피드백 문서 저장은 세션 기록 패키지 commit을 통해서만 발생하며, 기존 `FEEDBACK_DOCUMENT_PUBLISHED` 알림 이벤트는 JSON import와 AI commit 경로에서 동일하게 기록됩니다.
- **platform-admin:** 플랫폼 운영자용 triage 콘솔(`/admin`) — 온보딩 큐, 클럽 디렉터리, 클럽 상세 + Support access grant 패널을 단일 워크벤치로 통합. OWNER 전용 support access, 라이프사이클 우선 정렬, 온보딩 결과의 즉시 선택 반영.

### 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.
- 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`.
- 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.

## v1.10.2 - 2026-05-17

Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ ReadMates는 여러 정기 독서모임의 세션 준비, 참여 관리, 기록

이 저장소는 외부 공개를 전제로 정리되어 있습니다. 운영 secret, 실제 멤버 데이터, private deployment state, DB dump, 로컬 경로, OCI OCID는 문서와 예시에 포함하지 않습니다.

## How to Review This Project

처음 보는 리뷰어라면 아래 순서가 가장 빠릅니다.

1. **제품 표면 확인** — 게스트로 공개 클럽 소개, 공개 기록, 공개 세션 상세를 확인합니다. 시작점은 [Guest-mode walkthrough](docs/showcase/guest-mode-walkthrough.md)입니다.
2. **아키텍처 판단** — Cloudflare Pages Functions BFF, Spring API, MySQL/Flyway, Redis/Kafka, AI generation, release safety가 어떻게 연결되는지 [Architecture evidence](docs/showcase/architecture-evidence.md)에서 봅니다.
3. **유지보수 품질 확인** — frontend boundary, server ArchUnit, query budget, public release scan 같은 검증은 [Engineering confidence](docs/showcase/engineering-confidence.md)에 정리합니다.
4. **운영 증거 확인** — release readiness, deploy runbook, post-deploy watch, postmortem 흐름은 [Operational proof](docs/showcase/operational-proof.md)에서 봅니다.

Showcase 문서는 현재 동작의 source of truth가 아니라 읽는 순서입니다. 실제 경계와 동작은 코드, 테스트, scripts, migrations, [아키텍처 문서](docs/development/architecture.md)를 우선합니다.

## Engineering Highlights

운영 중인 서비스에서 풀어낸 비자명한 문제들입니다. 각 항목은 deep-dive로 연결됩니다.
Expand All @@ -36,14 +47,16 @@ README는 제품과 아키텍처의 첫 진입점입니다. 실제 작업에서

ReadMates는 이 문제를 단순 게시판이나 CRUD 목록으로 풀지 않습니다. 공개 사이트, 멤버 앱, 호스트 운영 도구, 공개 기록, 참석자 전용 피드백 문서를 하나의 제품 흐름으로 연결해 세션 전후의 실제 운영을 줄이는 데 초점을 둡니다.

리뷰어가 로그인 없이 확인할 수 있는 공개 표면은 guest-mode walkthrough에 따로 묶었습니다. 공개 접근은 클럽 소개, 공개 기록, 공개 세션 상세로 제한되며 멤버, 호스트, platform admin, AI 생성, 알림 운영 흐름은 권한을 열지 않고 sanitized evidence로 설명합니다.

## 역할별 기능

| 역할 | 할 수 있는 일 |
| --- | --- |
| 게스트 | 로그인 없이 클럽별 공개 소개, 공개 기록, 공개 세션 상세를 볼 수 있습니다. |
| 둘러보기 멤버 | 초대 없이 Google로 로그인한 계정입니다. 비공개 세션 기록, 현재 세션 현황, 멤버 공개 예정 세션을 읽을 수 있지만 RSVP, 체크인, 질문/서평 작성, 피드백 문서 열람, 호스트 도구는 제한됩니다. |
| 정식 멤버 | 초대 링크를 수락했거나 호스트가 전환한 계정입니다. 현재 세션 참여, 예정 세션 확인, RSVP, 읽은 분량 제출, 질문, 한줄평, 장문 서평 작성, 본인 표시 이름과 이메일 알림 설정 변경, `/app/notifications` 알림함 확인이 가능하며 참석한 회차의 피드백 문서를 읽을 수 있습니다. |
| 호스트 | 정식 멤버 권한에 운영 권한이 추가됩니다. 초대 생성, 둘러보기 멤버 전환, 멤버 상태와 표시 이름 관리, 예정 세션 생성/수정, 공개 범위 설정, 현재 세션 시작, 참석 확정, 진행 세션 닫기, 닫힌 기록 발행, 세션 기록 JSON 가져오기, 피드백 문서 업로드, 세션별 수동 알림 발송과 발송 원장 운영을 수행합니다. |
| 호스트 | 정식 멤버 권한에 운영 권한이 추가됩니다. 초대 생성, 둘러보기 멤버 전환, 멤버 상태와 표시 이름 관리, 예정 세션 생성/수정, 공개 범위 설정, 현재 세션 시작, 참석 확정, 진행 세션 닫기, 닫힌 기록 발행, AI 생성 또는 JSON 가져오기를 통한 세션 기록 패키지 저장, 세션별 수동 알림 발송과 발송 원장 운영을 수행합니다. |
| 플랫폼 관리자 | 클럽 생성, 첫 호스트 온보딩, 공개/비공개 상태, domain alias 생성, Cloudflare Pages marker 기반 상태 확인을 관리합니다. 클럽별 호스트/멤버 권한과 별도 권한입니다. |

로그인은 Google OAuth를 사용하며, 로컬 개발에서는 fixture 기반 dev-login을 사용할 수 있습니다.
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ReadMates 문서의 진입점입니다. 어떤 일을 할 때 어디 문서를

## 디렉터리 의미

- [Showcase](showcase/README.md): 처음 보는 리뷰어를 위한 guest-mode walkthrough, architecture evidence, engineering confidence, operational proof 진입점입니다.
- [`development/`](development) — 현재 동작 기준의 정전 가이드 (architecture, local setup, test, technical decisions, versioning, release management). 코드와 충돌하면 코드와 함께 갱신합니다.
- [`../design/`](../design) — 재사용 UI source package와 정적 디자인 catalog. 제품 코드가 공유하는 디자인 primitive와 pattern preview를 확인합니다.
- [`deploy/`](deploy) — 운영 배포 runbook. Cloudflare Pages, OCI Compose stack, OCI MySQL HeatWave, multi-club domain, public repo safety.
Expand Down
16 changes: 6 additions & 10 deletions docs/development/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ReadMates는 여러 정기 독서모임의 공개 소개, 멤버 세션 준비,
| 공개 사이트 | `/clubs/:slug`, `/clubs/:slug/about`, `/clubs/:slug/records`, `/clubs/:slug/sessions/:sessionId`, `/`, `/about`, `/records`, `/sessions/:sessionId`, `/login`, `/clubs/:slug/invite/:token`, `/invite/:token`, `/reset-password/:token` | 게스트, 로그인 사용자 | 클럽 소개, 공개 기록, 공개 세션 상세, Google OAuth 시작, 클럽 context가 있는 초대 수락 진입, 종료된 비밀번호 경로 안내. Unscoped public route는 호환성을 위해 baseline club을 사용 |
| 로그인 후 진입 | `/app`, `/clubs/:slug/app`, 등록된 club host의 `/app` | 로그인 사용자 | 가입 클럽이 하나면 해당 클럽 앱으로 이동하고, 여러 개면 클럽 선택 화면을 보여주며, 선택한 클럽 context로 앱에 진입 |
| 멤버 앱 | `/clubs/:slug/app`, `/clubs/:slug/app/pending`, `/clubs/:slug/app/session/current`, `/clubs/:slug/app/notes`, `/clubs/:slug/app/archive`, `/clubs/:slug/app/sessions/:sessionId`, `/clubs/:slug/app/feedback/:sessionId`, `/clubs/:slug/app/feedback/:sessionId/print`, `/clubs/:slug/app/me`, `/clubs/:slug/app/notifications`, 등록된 club host의 `/app/**` | 둘러보기 멤버, 정식 멤버, 호스트 | 현재 세션 확인, 멤버 공개 예정 세션 확인, 둘러보기 멤버 안내, RSVP, 읽은 분량, 질문, 한줄평, 장문 서평, 아카이브, 참석 회차 피드백 문서, 본인 표시 이름과 알림 설정 변경, 클럽별 멤버 알림함 확인 |
| 호스트 앱 | `/clubs/:slug/app/host`, `/clubs/:slug/app/host/notifications`, `/clubs/:slug/app/host/members`, `/clubs/:slug/app/host/invitations`, `/clubs/:slug/app/host/sessions/new`, `/clubs/:slug/app/host/sessions/:sessionId/edit`, 등록된 club host의 `/app/host/**` | 현재 클럽의 호스트 | 예정 세션 생성/수정, 공개 범위 설정, 현재 세션 시작, 참석 확정, 진행 세션 닫기, 닫힌 기록 발행, 세션 기록 JSON 가져오기, 초대 관리, 멤버 상태와 표시 이름 관리, 피드백 문서 업로드, 알림 발송 운영 |
| 호스트 앱 | `/clubs/:slug/app/host`, `/clubs/:slug/app/host/notifications`, `/clubs/:slug/app/host/members`, `/clubs/:slug/app/host/invitations`, `/clubs/:slug/app/host/sessions/new`, `/clubs/:slug/app/host/sessions/:sessionId/edit`, 등록된 club host의 `/app/host/**` | 현재 클럽의 호스트 | 예정 세션 생성/수정, 공개 범위 설정, 현재 세션 시작, 참석 확정, 진행 세션 닫기, 닫힌 기록 발행, 세션 기록 JSON 가져오기, 초대 관리, 멤버 상태와 표시 이름 관리, 세션 기록 패키지 저장, 알림 발송 운영 |
| 플랫폼 관리 | `/admin` | platform admin | 클럽 생성, 클럽 목록 확인, 공개/비공개 상태 관리, 공개 소개 정보 관리, 등록형 domain alias 요청과 상태 확인, 첫 호스트 온보딩 상태 확인. 세션/멤버/알림 같은 클럽 내부 운영은 호스트 앱 책임 |

## 프런트엔드 route-first 경계
Expand Down Expand Up @@ -330,17 +330,13 @@ Public route/API에는 명시적으로 공개된 데이터만 나갑니다.
피드백 문서는 모임 후 운영 산출물을 저장하고 읽기 좋게 제공하기 위한 기능입니다.

```text
External operating workflow
Session record package commit
|
| Markdown or text feedback document
| AI generation result or readmates-session-import:v1 JSON
v
Host upload
SessionImportService validation and replacement
|
| POST /api/host/sessions/{sessionId}/feedback-document
v
Spring validation and parser
|
| UTF-8, .md/.txt, size, filename, structured sections
| UTF-8, structured feedback template, session metadata, attendee authors
v
MySQL session_feedback_documents
|
Expand All @@ -349,7 +345,7 @@ MySQL session_feedback_documents
Readable response for host or attended full member
```

호스트는 `.md` 또는 `.txt` 피드백 문서를 업로드합니다. 서버는 파일명, 크기, UTF-8 텍스트 여부를 검증하고 `FeedbackDocumentParser`로 문서를 typed response 형태로 파싱합니다. 저장은 원문 텍스트와 metadata를 versioned document로 남깁니다.
호스트는 더 이상 피드백 문서만 별도로 업로드하지 않습니다. 새 피드백 문서는 AI 생성 또는 `readmates-session-import:v1` JSON import commit이 세션 기록 패키지를 저장할 때 함께 교체됩니다.

프런트엔드에는 `/app/feedback/:sessionId/print` route와 browser print 기반 helper가 남아 있지만, 현재 `front/shared/config/readmates-feature-flags.ts`의 `feedbackDocumentPdfDownloadsEnabled`가 `false`라서 사용자는 `PDF로 저장` 또는 자동 print action을 보지 않습니다. 이 기능을 다시 켤 때는 archive, my page, feedback document route, E2E print smoke를 함께 검증합니다.

Expand Down
18 changes: 14 additions & 4 deletions docs/development/server-state-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@

본 문서는 TanStack Query 마이그레이션 진행 상황을 추적합니다.

## 이번 분기 계획

Engineering proof portfolio 분기에서는 다음 순서로 server state migration을 진행합니다.

1. `host/members` — 멤버 목록과 lifecycle/profile/viewer mutation을 Query invalidation 패턴으로 정리합니다.
2. `host/notifications` — 수동 알림 options/preview/confirm/dispatch ledger를 route-owned state와 Query cache로 분리합니다.
3. `host/sessions` — 세션 목록/read path부터 좁게 시작하고 editor mutation은 별도 pass로 나눕니다.

각 migration은 UI 컴포넌트가 API를 직접 호출하지 않는다는 route-first 경계를 유지해야 합니다.

## 완료
- `host/invitations` — list query + create/revoke mutation + loader hand-off
- `host/members` — list query + lifecycle/profile/viewer mutation refresh + loader hand-off

## 패턴
- query: `features/<feature>/queries/<area>-queries.ts` 에 `queryOptions` + `useXxxMutation` export
Expand All @@ -12,8 +23,7 @@
- 컴포넌트는 actions props 인터페이스를 유지 — 테스트는 wrapper + mock actions 로 동일하게 작성

## 후속 후보 (우선순위)
1. `host/members`
1. `host/notifications` — detailed migration plan: `docs/superpowers/plans/2026-05-17-readmates-host-notifications-query-migration.md`
2. `host/sessions`
3. `host/notifications`
4. `current-session` (actions 4개)
5. `archive`, `feedback`, `public` — 읽기 중심, loader 와 결합도 높음
3. `current-session` (actions 4개)
4. `archive`, `feedback`, `public` — 읽기 중심, loader 와 결합도 높음
2 changes: 1 addition & 1 deletion docs/development/session-import-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## 모드 병존 안내 (in-app AI 생성과의 관계)

ReadMates 호스트 세션 편집기는 이 외부 JSON 업로드 흐름과 **in-app AI 생성** 두 모드를 함께 제공합니다. 편집기 상단의 `[ 외부 도구 JSON 업로드 ]` / `[ AI 결과 가져오기 ]` 토글로 모드를 전환하며, 모드 선택은 `?aigen=1` URL query로 보존됩니다.
호스트 세션 편집기는 `세션 기록 완성` 패널에서 AI 생성을 기본 경로로 보여주고, 외부 JSON 가져오기를 fallback으로 제공합니다. 단독 `.md` 또는 `.txt` 피드백 문서 업로드는 더 이상 제공하지 않습니다.

| 모드 | 입력 | LLM 호출 위치 | 운영 게이트 |
| --- | --- | --- | --- |
Expand Down
8 changes: 8 additions & 0 deletions docs/development/technical-decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,11 @@ boot 시 Kafka listener bean이 등록되지 않는지 log 확인.
**Trade-off:** token bucket이 주 경계에서 reset되는 의도된 부작용이 있습니다. 율 제한은 단기(분~시간 단위) 정책이므로 실질적인 영향은 없습니다. 토큰·세션 ID 해시에는 여전히 `stableHash`(salt 없음)를 사용해 주 경계 영향을 받지 않습니다.

**관련 문서와 검증:** `./server/gradlew -p server test --tests '*ClientIpHashing*'`

## Transaction Boundary Policy

Application services own business transaction boundaries. Controllers parse HTTP and call use cases; persistence adapters execute SQL and mapping. When an application service coordinates more than one write port, the service method owns the transaction so cache invalidation, notification event recording, and state mutation share one visible boundary.

Adapter-level `@Transactional` is allowed only when the adapter is called by an inbound scheduler, Kafka listener, or other path that does not already pass through an application service transaction. If both service and adapter carry `@Transactional`, the service boundary is treated as the authoritative boundary and the adapter annotation should be removed in a narrow cleanup once tests pin the behavior.

Isolation is specified only where the operation depends on claim/read-modify-write behavior that needs a non-default guarantee. Existing examples include session/login restoration and notification delivery claiming. New isolation choices must be explained in the service or adjacent decision record.
26 changes: 26 additions & 0 deletions docs/showcase/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# ReadMates Showcase

이 디렉터리는 ReadMates를 처음 보는 리뷰어가 제품, 아키텍처, 운영 증거, 유지보수 품질을 빠르게 따라갈 수 있도록 만든 reviewer-facing guide입니다.

현재 동작의 source of truth는 코드, 테스트, scripts, migrations, `docs/development/architecture.md`입니다. Showcase 문서는 그 자료를 대체하지 않고 읽는 순서를 제공합니다.

## 추천 리뷰 순서

1. `README.md`에서 제품 문제와 역할 모델을 확인합니다.
2. `docs/showcase/guest-mode-walkthrough.md`에서 로그인 없이 볼 수 있는 공개 제품 표면을 따라갑니다.
3. `docs/showcase/architecture-evidence.md`에서 BFF, Spring API, MySQL, Redis/Kafka, AI generation, release safety가 어떻게 연결되는지 봅니다.
4. `docs/showcase/engineering-confidence.md`에서 테스트와 경계 검증이 어떤 회귀를 막는지 확인합니다.
5. `docs/showcase/operational-proof.md`에서 release, deploy, observability, postmortem 흐름을 확인합니다.

## 문서별 역할

| 문서 | 답하는 질문 |
| --- | --- |
| `guest-mode-walkthrough.md` | 로그인 없이 무엇을 볼 수 있고, private workflow는 어떤 evidence로 확인하는가? |
| `architecture-evidence.md` | 이 프로젝트가 단순 CRUD가 아니라 운영형 제품인 근거는 무엇인가? |
| `engineering-confidence.md` | 코드베이스가 커져도 무너지지 않게 하는 경계와 검증은 무엇인가? |
| `operational-proof.md` | 배포, 공개 릴리즈 안전, 장애 대응은 어떤 흐름으로 관리되는가? |

## 공개 안전 기준

Showcase 문서는 실제 멤버 데이터, private domain, 운영 secret, deployment state, OCID, token-shaped example, local absolute path를 포함하지 않습니다. Private workflow는 접근 권한을 넓히지 않고 sanitized 설명, fixture, 테스트, runbook으로 설명합니다.
Loading