본문으로 건너뛰기

테넌트 스키마

목적

Lumie는 더 이상 tenant별 스키마 persistence를 사용하지 않습니다. tenant 소유 레코드는 공유 public 테이블에 있으며 tenant_id와 RLS로 격리됩니다. 이 페이지는 데이터 모델의 tenant 범위 영역과 이를 변경할 때의 규칙을 설명합니다.

소스 경로

경로역할
V18__rls_baseline.sqltenant 범위 baseline 테이블과 policy
V26__rename_admin_tables_to_staff.sqlstaff 용어 migration
V54__create_file_links.sqltenant-safe file link 모델
V55__create_announcement_class_targets.sqlannouncement targeting 조인 테이블
V57__create_lecture_class_targets.sqllecture targeting 조인 테이블
V62__add_read_receipt_tables.sqlannouncement 및 textbook 읽음 추적
V65__repair_read_receipt_and_file_download_rls.sqlread/download 테이블용 RLS 수리

도메인 그룹

그룹테이블비고
Identityusers, staff, staff_permissions, students사용자 행은 tenant 범위이며 role을 가짐
Class and lectureclasses, class_enrollments, lectures, lecture_class_targetsclass-target 조인 행에도 tenant_id 유지
Contentannouncements, announcement_class_targets, qna_boards, textbooks, textbook_foldersread receipt와 file link도 tenant 범위
Examexams, questions, question_results, exam_results, omr_grading_jobsworker 콜백도 여전히 백엔드 소유 tenant 테이블에 기록됨
Attendanceattendance_sessions, attendance_records세션 고유성은 class/date 패턴 기준으로 유지
Communicationsms_messages, sms_templates, ai_chat_messages, ai_conversationschat persistence는 여전히 백엔드 소유
File metadatafile_metadata, file_links, file_downloadtenant-safe FK 패턴에는 (id, tenant_id) 쌍 포함

교차 모듈 참조 정책

모든 관계가 데이터베이스 FK인 것은 아닙니다. Lumie는 같은 모듈 경계를 지원하거나 tenant-safe FK 형태가 명시적인 경우 hard FK를 유지하고, hard FK가 모듈 결합을 과도하게 만들면 soft reference를 사용합니다.

예시:

  • file link는 교차 tenant 첨부 실수를 막기 위해 (file_id, tenant_id)로 file metadata를 참조합니다
  • announcement와 lecture target 조인은 tenant_id와 tenant-safe 참조를 포함합니다
  • tuition 테이블은 billing과 identity/class 모듈 경계를 분리하기 위해 일부 user/class 개념을 hard FK 없이 의미적으로만 참조합니다

변경 규칙

  1. 새로운 tenant 범위 테이블에는 tenant_id bigint not null이 있어야 합니다.
  2. RLS는 활성화되고 강제되어야 합니다.
  3. insert/update 코드는 사용자 입력을 믿지 말고 현재 tenant id를 기록해야 합니다.
  4. 전역적으로 고유한 값이 아닌 한 unique index에는 tenant_id를 포함해야 합니다.
  5. hard FK가 없는 교차 모듈 참조는 migration 주석에 문서화해야 합니다.

운영 실패 양상

증상가능성 높은 원인첫 확인 포인트
유효한 tenant 데이터인데 결과가 비어 있음app.tenant_id 컨텍스트 누락호출자에서 tenant 컨텍스트 설정 여부 검색
교차 tenant 쓰기 거부RLS WITH CHECK가 쓰기를 차단삽입된 tenant_id 확인
tenant 간 duplicate-key 충돌unique index에 tenant_id 누락migration index 정의 확인
worker callback이 job을 업데이트하지 못함tenantSlug 또는 tenant 컨텍스트 누락/오류백엔드 callback listener와 tenant 조회 확인

검증

rg -n "CREATE TABLE|tenant_id|ENABLE ROW LEVEL SECURITY|tenant_isolation" \
lumie-backend/app/src/main/resources/db/migration/public
rg -n "tenant_id|TenantContextHolder" lumie-backend/modules

성공 기준은 migration이 tenant_id, RLS 활성화, tenant-isolation policy가 있는 tenant 소유 테이블을 보여주고, 백엔드 모듈은 tenant 범위 읽기/쓰기에 앞서 요청 시점 tenant 컨텍스트 전파를 보여주는 것입니다.