notes(hjjeong): cross-tenant §11.2 부분 실패 시뮬레이션 검증 (2026-04-29)
테넌트 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) <noreply@anthropic.com>
This commit is contained in:
@@ -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) |
|
||||
|
||||
@@ -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 명령 (재현용)
|
||||
|
||||
Reference in New Issue
Block a user