테넌트 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>
설계서 §11.1 (행복 경로) 의 첫 다회사 실증.
SUPER_ADMIN 토큰으로 /_active-companies + 4개 fan-out 엔드포인트 직접 curl.
검증 결과 (TEST01 + TEST02 둘 다 active):
- /users total=10 q=2 failed=0 by={'*':8, 'TEST01':1, 'TEST02':1}
- /roles total=1 q=2 failed=0 by={'TEST01':1}
- /batches total=14 q=2 failed=0 by={'TEST01':7, 'TEST02':7} ← 균등 머지
- /lang-keys total=0 q=2 failed=0 by={} ← 회사 DB 시드 없음
발견:
- /users 의 '*' 8행은 버그 아님 — listUsers 만 includeMeta=true 호출,
메타 DB SUPER_ADMIN 들을 company_code='*' 로 prepend (의도된 설계).
- runFanOut 의 마지막 boolean 은 wrapSearchWithPercent 일 뿐 includeMeta 아님
(시그니처 분리). roles/batches/lang-keys 는 모두 includeMeta=false.
- /lang-keys 0건은 회사 DB MULTI_LANG_KEY_MASTER 가 비어있는 것 (failed=0).
이전 §3 의 "TEST01: 646건" 은 시점/컨텍스트 다른 측정으로 추정.
문서 갱신:
- 설계 27.md §11: 11.1 ✅, 11.3 fan-out 검증 추가 인용
- 실행 28.md §6 #3 → ✅, §8 활성 회사 TEST02 추가
- 실행 28.md §9 신설 — 결과 표 + 해석 + 검증된 항목 + 미검증 + 재현용 명령
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
설계 27.md
- 상단 최종 갱신 + 실행 로그 링크 + Phase A/B/C 완료 배너
- §10 단계별 체크리스트: A 4/5, B 3/4, C 3/14, 페이지네이션 cap ✓, D 미진행, E 일부
- §11 검증 시나리오: 5개 시나리오 상태 표 + TEST01 실 검증 결과 인용
- §14 다음 세션 진입 시: 즉시 가능한 4개 작업 우선순위 (TEST02 fan-out 검증 1순위)
- gbpark/ 의 2026-04-24 두 문서 참조를 ../gbpark/ 로 보정
실행 로그 28.md
- 상단 최종 갱신 + 핸드오프 문서 참조
- TL;DR: 푸시·커밋 안 함 → 3 커밋 푸시 완료, TEST02 활성 명기
- §4.4 신규 — *.localhost 라우팅이 같은 커밋 배치에 묶인 사실 + 2026-04-29 검증 결과
- §5: 워킹트리 → 3개 커밋 분배 의도 표
- §6: 권장 단계 8개 → 9개 (Gitea PR 추가), 각 항목 ✅/🟡/⏳/❌ 표기
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CLAUDE.md "notes/{git-user}/{date}-{slug}.md" 규약대로 정리.
git config user.name=hjjeong 인데 gbpark/ 에 쌓이고 있던 3개 분리.
- 2026-04-27-cross-tenant-admin-aggregation.md (설계, 내용 갱신: Phase A/B/C 체크리스트, §11 검증 시나리오 실 결과 병기, §14 다음 단계)
- 2026-04-28-cross-tenant-execution-log.md (실행 로그, 내용 갱신: 커밋·푸시 상태, §4.4 *.localhost 같은 배치 묶음 기재, §5 커밋 분배 의도, §6 권장 단계 ✅/🟡/⏳/❌ 표시)
- 2026-04-28-localhost-tenant-routing-handoff.md (순수 이동)
cross-tenant 27.md 의 같은 폴더 참조였던 2026-04-24 두 문서는
gbpark/ 에 그대로 남아 ../gbpark/ 로 경로 보정. 외부 참조(../../docs,
../../backend-spring 등) 는 깊이 동일해 무수정.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scrollContainer 모드의 flex 기반 height 계산이 shadcn Table 의 내부 wrapper
(data-slot="table-container", overflow-x-auto) 와 충돌해 잘림 발생.
flex-1/min-h-0 대신 max-h-[calc(100vh-280px)] + overflow-y-auto 로 강제.
hack 성이지만 안정적으로 동작.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SubdomainResolverFilter.extractSubdomain() 가 2파트 {sub}.localhost 호스트도
첫 파트로 파싱 (RFC 6761). 운영 3파트 경로 무변경. 단위 테스트 8건 추가.
frontend/lib/api/client.ts 에 *.localhost (bare 제외) 직접 호출 분기 1-b 추가.
8081 로 직결해 Host 헤더 보존. subdomain.ts 도 동일 규칙 적용.
application.yml CORS 디폴트에 http://*.localhost:[*] 패턴 추가.
docs/MULTI_TENANCY_ARCHITECTURE.md §4.2 (실행 모드 A/B) + §6 (1-b 분기) 갱신.
.gitignore 에 .envrc/.direnv 추가, .java-version=21 명시 (jenv 호환).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SUPER_ADMIN 토큰(company_code=*)이면 등록 회사들 DB 를 순회해 결과를
집계해 돌려주는 CrossTenantAggregator/Controller 추가. 사용자/권한그룹/
배치/다국어 키 4개 도메인의 list API 가 cross-tenant 모드 지원.
UserTable + ResponsiveDataView 에 compact/scrollContainer prop 추가.
페이지 헤더/툴바/페이지네이션은 고정, 테이블만 자체 스크롤.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
화면 폭:
- 4개 페이지(사용자/권한 그룹/권한/부서) max-w 제거 → 화면 전체 사용
- 헤더 텍스트 컴팩트화 (text-xl + 작은 설명문)
부서관리 dept_info 스키마 1:1 매핑:
- 누락 필드 6개 추가: master_sabun, master_user_id, location, location_name, data_type, sales_yn
- frontend types/department.ts: Department / DepartmentFormData 확장
- frontend deptMngList: 폼 추가 + handleSelectDepartment / payload 매핑
- backend mapper: INSERT/UPDATE에 6개 컬럼 추가
- backend DepartmentService: insertParams/updateParams에 6개 필드 추가
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 사용자/권한 그룹/권한/부서 관리 4개 페이지 풀HD 기준 max-w 제한, 헤더 컴팩트화
- 권한 그룹 관리: 그리드 4~5열로 카드 컴팩트화, 검색 추가, 호버/액션 디자인 개선
- 부서관리: '일괄등록' 모달(CSV 라인 입력) / '변경이력' 모달 onClick 핸들러 연결
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 백엔드 TenantController: GET /api/tenant/check?subdomain=xxx
(메타 DB 강제 라우팅 + CompanyResolver 로 존재 여부 반환)
- frontend/lib/tenant/subdomain.ts: 호스트 파싱 + 예약어(solution/www/admin 등) 제외
- TenantGuard 클라이언트 컴포넌트: layout.tsx 에서 wrap,
sessionStorage 로 같은 서브도메인 재체크 방지
- /tenant-not-found 페이지: v5 solid+glow 스타일
등록되지 않은 서브도메인 접속 시 즉시 /tenant-not-found 로 리다이렉트.
- application.yml, k8s configmap, docker-compose 4종: SPRING_DATASOURCE_URL path
- provisioning 코드: {prefix}_vexplor → {prefix}_invyone 테넌트 DB 네이밍 규칙
- 프론트 마법사: Step1Basic, Step4Run 미리보기 라벨
- CompanyAccordionRow: 기본 DB 이름 포맷
- 마이그레이션/멀티테넌시 문서 동기화
- Traefik 와일드카드 설정 산출물 보관 (notes/)
비밀번호(vexplor0909!!) 및 역사 기록 문서(INVYONE_CONCEPT,
DDD1542, test-output, dashboard-runtime-fixes) 는 의도적으로 미변경.
- /admin 홈을 단순 링크 카드 → Welcome/Stats/SystemStatus/회사활동/최근변경/빠른진입 구성의 관리자 대시보드로 교체 (mock 데이터, 실데이터 배선은 후속)
- PopupTemplateRenderer 신규 — 팝업은 canvas 1:1 유지가 필요하므로 반응형 TemplateRenderer 와 경로 분리, absolute 좌표 + transform scale 로 창을 꽉 채움. form-popup 이 templateId 로 자체 fetch 해서 stale views(screenResolutions 누락) 문제 해소
- DashboardCard: 팝업 outer 크기를 canvas + 브라우저 크롬 보정치로 계산, 부모가 template 객체 직접 전달하던 것 제거
- TemplateRenderer: BlockRenderer export, formRow 기반 columnName/value/onChange/onRowSelect 등 바인딩 props 전달 강화
- TableComponent: 행 클릭/체크박스 선택 시 onRowSelect / onSelectedRowsChange emit, 헤더 전체 선택 동작 구현, 싱글/멀티 선택 분기 정리
- AppLayout: 모드 전환 연출 강화(burst ring + particles / 헤더 sweep / breadcrumb swap / glow flash), horizontal nav + 데스크톱에서 햄버거 자동 접힘, 헤더 도구군 래핑 구조 정리
- DashboardEmpty 삭제 → 공통 EmptyDashboard 로 통합
- dashboard.css: ud-htools stagger(오른쪽 → 왼쪽 슬라이드) 애니메이션 적용
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- 타이포 스케일: body 12→14px, caption 9.6→12px, display 25.6→32px, 위계 강화
- 헤더 우측 3그룹화 (대시보드액션 | 테마/알림/설정 | 모드+프로필), v5-hdr-sep 구분자 추가
- 사이드바 SUPER_ADMIN 회사 카드 borderless slim 라벨로 압축
- 메뉴명 빈 텍스트 방어 + title 속성 추가
- 빈 대시보드(EmptyDashboard) 리디자인: 탭없음/위젯없음 2상태 분리, 2-CTA 카드
- 로그인 코스믹 공연 축소: 별 150→30, 파티클 20→0, 카피 한글화 (로그인 버튼/서브타이틀)
- 모드 전환 burst/sweep/badge-zoom 제거, sidebar stagger morph만 유지 (handleModeSwitch 100→25줄)
- View transitions duration 1800ms → 500ms
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>