From 280e25a4dfd8cbe6a528aa6b537d464f6c72f031 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Wed, 29 Apr 2026 11:42:12 +0900 Subject: [PATCH] =?UTF-8?q?notes(hjjeong):=20cross-tenant=20=C2=A711.2=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=8B=A4=ED=8C=A8=20=EC=8B=9C=EB=AE=AC?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=85=98=20=EA=B2=80=EC=A6=9D=20(2026-04-29)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테넌트 DB 만 만져도 됨 — 메타 DB 무수정. TEST02 의 USER_INFO 를 임시 RENAME 해서 SELECT 실패 유도 → fan-out 호출 → 즉시 롤백. 메타 DB·다른 테이블 일체 영향 없음. 결과: - RENAME 후 /users → HTTP 200, header X-CrossTenant-Failed: TEST02 total=9 q=2 failed=1 by={'*':8, 'TEST01':1} (TEST02 0) - 롤백 후 /users → total=10 failed=0 by 원복 검증된 항목: - fail-open: 한 회사 실패해도 전체 응답 200 - 회사 격리: TEST01·메타 행 영향 없음 - companies_failed: 1 + failed_company_codes: ["TEST02"] - 응답 헤더 X-CrossTenant-Failed: TEST02 문서 갱신: - 설계 27.md §11.2: ⏳ → ✅ + 실행로그 §9.4 링크 - 실행 28.md §9.4 신설 — 시뮬레이션 SQL + 결과 + 검증 항목 5개 - 실행 28.md §9.5 — 남은 시나리오 (§11.4 락 비획득 / §11.5 캐시 N/A) Co-Authored-By: Claude Opus 4.7 (1M context) --- ...26-04-27-cross-tenant-admin-aggregation.md | 2 +- .../2026-04-28-cross-tenant-execution-log.md | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/notes/hjjeong/2026-04-27-cross-tenant-admin-aggregation.md b/notes/hjjeong/2026-04-27-cross-tenant-admin-aggregation.md index f5fc7c07..50faad2a 100644 --- a/notes/hjjeong/2026-04-27-cross-tenant-admin-aggregation.md +++ b/notes/hjjeong/2026-04-27-cross-tenant-admin-aggregation.md @@ -424,7 +424,7 @@ const editUrl = `https://${row.subdomain}.invyone.com/admin/userMng/userMngList? | 시나리오 | 상태 | |---|---| | 11.1 행복 경로 | ✅ 2회사 (TEST01 + TEST02) 머지 실증 완료 (2026-04-29). [실행로그 §9](2026-04-28-cross-tenant-execution-log.md) 참조 | -| 11.2 부분 실패 | ⏳ 미검증 — TEST02 DB pg_terminate 시뮬레이션 필요 | +| 11.2 부분 실패 | ✅ 완료 (2026-04-29) — TEST02 USER_INFO RENAME 으로 SELECT 실패 유도, fail-open + `X-CrossTenant-Failed` 헤더 + `companies_failed: 1` 모두 확인. [실행로그 §9.4](2026-04-28-cross-tenant-execution-log.md) 참조 | | 11.3 권한 | ✅ `super_admin_required` (토큰 없이 호출 → 403) — 스모크 (실행로그 §1) + fan-out 검증 (실행로그 §9.3) 모두 통과 | | 11.4 락 비획득 | ⏳ 미검증 | | 11.5 캐시 무효화 | ⏳ N/A — 캐시 미구현 (Phase D) | diff --git a/notes/hjjeong/2026-04-28-cross-tenant-execution-log.md b/notes/hjjeong/2026-04-28-cross-tenant-execution-log.md index 0f14aaea..c3cc917a 100644 --- a/notes/hjjeong/2026-04-28-cross-tenant-execution-log.md +++ b/notes/hjjeong/2026-04-28-cross-tenant-execution-log.md @@ -333,10 +333,38 @@ curl http://localhost:8081/api/auth/status - [x] 페이지네이션 cap — 모든 회사가 cap 200 미만이라 `truncated: false`. cap 동작은 2026-04-28 §3.5 에서 이미 검증 (646→200) - [x] 권한 가드 — 토큰 없이 `/_active-companies` 호출 → `403 super_admin_required` -### 9.4 미검증 (남은 시나리오) +### 9.4 §11.2 부분 실패 시뮬레이션 (2026-04-29 추가) -- §11.2 부분 실패 — TEST02 DB pg_terminate 후 fan-out, `companies_failed: 1` + `X-CrossTenant-Failed: TEST02` 확인 -- §11.4 락 비획득 — TEST02 풀 maxPool 점유 후 `connection-timeout` +테넌트 DB 만 만져도 된다는 사용자 OK 받고 진행. 메타 DB 무수정. + +**플랜:** TEST02 의 `USER_INFO` 테이블을 임시 RENAME 해서 SELECT 실패 유도 → fan-out 호출 → 즉시 롤백. + +```sql +-- test02_invyone 만 +ALTER TABLE USER_INFO RENAME TO USER_INFO_HJTEST_BAK; -- 시뮬레이션 시작 +-- (curl /users) +ALTER TABLE USER_INFO_HJTEST_BAK RENAME TO USER_INFO; -- 즉시 롤백 +``` + +**결과:** + +| 단계 | 응답 | +|---|---| +| 1. RENAME 후 `/users` | HTTP 200, header `X-CrossTenant-Failed: TEST02`, body `total=9 q=2 failed=1 by={'*':8, 'TEST01':1}` | +| 2. 롤백 후 `/users` | `total=10 failed=0 by={'*':8, 'TEST01':1, 'TEST02':1}` — 완전 복귀 | + +**검증된 것:** +- [x] **fail-open** — 한 회사 SELECT 실패해도 전체 응답 200, 다른 회사 + 메타 결과 그대로 반환 +- [x] **회사 격리** — TEST01·메타 행은 영향 없음 (`'*': 8, 'TEST01': 1` 그대로) +- [x] **`companies_failed: 1`** + `failed_company_codes: ["TEST02"]` +- [x] **응답 헤더 `X-CrossTenant-Failed: TEST02`** — 클라이언트가 토스트 띄우기에 충분한 정보 +- [x] 백엔드 로그에 `[CrossTenant] mapper=admin-cross-tenant.listUsers failed for company=TEST02 db=test02_invyone : ...` 형태 메시지 (Aggregator line 159-161) + +설계서 §11.2 가 이 결과로 ✅ 처리됨. + +### 9.5 여전히 미검증 (남은 시나리오) + +- §11.4 락 비획득 — TEST02 풀 maxPool 점유 후 `connection-timeout`. Hikari 풀 점유 시뮬레이션 필요 (별도 부하 테스트 환경) - §11.5 캐시 무효화 — 캐시 자체가 Phase D 라 N/A ### 9.5 명령 (재현용)