모듈 레퍼런스
Lumie 백엔드를 구성하는 22개 모듈(libs 3 + modules 19)의 책임과 주요 컴포넌트를 정리합니다.
공유 라이브러리 (libs/)
libs/common
모든 모듈이 공통으로 사용하는 컨텍스트 홀더, 예외 처리, 베이스 엔티티, Role 열거형을 제공합니다.
주요 컴포넌트
| 컴포넌트 | 설명 |
|---|---|
TenantContextHolder | ThreadLocal 기반 테넌트 슬러그·ID 저장소. withinContext(slug, tenantId, action) 으로 어댑터에서 안전하게 전환 |
UserContextHolder | ThreadLocal 기반 사용자 ID·역할 저장소 |
Role | OWNER(0) > MANAGER(1) > INSTRUCTOR(2) > STUDENT(3) 계층 열거형 |
BaseEntity | createdAt, updatedAt 공통 필드 및 JPA Auditing |
TenantScopedEntity | RLS 대상 엔티티 기반 클래스 — @PrePersist로 tenant_id 자동 설정 |
ApiResponse<T> | 표준 API 응답 래퍼 |
BusinessException | 비즈니스 예외 최상위 클래스 |
ErrorCode | 에러 코드 인터페이스 |
GlobalExceptionHandler | @RestControllerAdvice 전역 예외 처리기 |
// Role.java — 계층 권한 확인
public enum Role {
OWNER(0), MANAGER(1), INSTRUCTOR(2), STUDENT(3);
public boolean hasAuthority(Role required) {
return this.level <= required.level; // OWNER는 모든 역할에 권한 있음
}
public boolean canManage(Role target) {
return this.level < target.level; // 동급 관리 불가
}
}
libs/internal-api
모듈 간 직접 빈 주입(in-process)을 위한 인터페이스와 내부 DTO(record)를 정의합니다. 구현체(XxxServiceAdapter)는 각 모듈의 adapter/in/internal/ 에 있습니다. 소비자는 adapter/out/internal/ 에서 인터페이스를 주입받습니다.
libs/internal-api/src/main/java/com/lumie/
├── auth/api/AuthService.java
├── tenant/api/TenantService.java
├── billing/api/BillingService.java
├── student/api/StudentService.java
├── staff/api/StaffService.java
├── classroom/api/ClassService.java
├── lecture/api/LectureService.java
├── exam/api/ExamService.java
├── content/api/ContentService.java
├── file/api/FileService.java
├── assignment/api/AssignmentService.java
└── activitylog/api/ActivityLogService.java
자세한 내용은 아키텍처 — 모듈 간 통신을 참고하세요.
libs/messaging
RabbitMQ Exchange, Queue, Routing Key 상수와 공통 메시지 DTO를 정의합니다. OMR 배치 채점 워크플로우에서 사용합니다.
// RabbitMqConstants.java
public final class RabbitMqConstants {
public static final String LUMIE_COMMANDS_EXCHANGE = "lumie.commands";
public static final String LUMIE_DLX_EXCHANGE = "lumie.dlx";
public static final String GRADING_OMR_REQUEST_QUEUE = "grading.omr-request";
public static final String GRADING_OMR_REQUEST_DLQ = "grading.omr-request.dlq";
public static final String GRADING_OMR_COMPLETED_QUEUE = "grading.omr-completed";
}
도메인 모듈 (modules/)
modules/tenant
책임: 테넌트(학원/기관) 등록, 상태 관리, 커스텀 도메인 라우팅
주요 컴포넌트
| 컴포넌트 | 설명 |
|---|---|
TenantProvisioningService | 신규 테넌트 가입 시 데이터 초기화 + 프리 구독 생성 |
TenantServiceAdapter | TenantService 구현체 — 타 모듈에 테넌트 정보 제공 |
내부 API (TenantService)
Optional<TenantData> getTenant(Long tenantId);
Optional<TenantData> getTenantBySlug(String slug);
Optional<TenantData> getTenantByCustomId(String customId); // 공개 랜딩 라우팅
List<TenantData> listActiveTenants();
ValidateTenantResult validateTenant(String slug);
CreateTenantResult createTenant(String instituteName, String businessRegistrationNumber,
String ownerEmail, String ownerName);
modules/auth
책임: JWT 발급·검증, OAuth2 소셜 로그인(Google, Kakao), Redis 기반 토큰 관리
주요 컴포넌트
| 컴포넌트 | 설명 |
|---|---|
JwtAuthenticationFilter | 모든 요청에서 JWT를 추출하고 TenantContextHolder + UserContextHolder + SecurityContext 설정 |
JwtTokenProvider | 액세스·리프레시 토큰 생성, 파싱, 검증 |
AuthRegistrationService | 원장 등록 — tenant 생성 → staff 생성 이벤트 발행 |
AuthServiceAdapter | AuthService 구현체 |
JWT Claims 구조
{
"sub": "28",
"tenant_slug": "inst-c704d223",
"tenant_id": 18,
"role": "OWNER",
"type": "access",
"iss": "lumie-auth-svc",
"iat": 1775313347,
"exp": 1775316947,
"jti": "a022ead2-a80e-4091-82ea-1023b9c51560"
}
자세한 인증 플로우는 인증 & 멀티테넌시를 참고하세요.
modules/billing
책임: 테넌트 구독 플랜 관리, 기능별 사용량 할당량(Quota) 추적
주요 컴포넌트
| 컴포넌트 | 설명 |
|---|---|
SubscriptionService | 구독 플랜 생성, 갱신, 만료 처리 |
QuotaService | MetricType 기반 사용량 확인 및 차감 |
BillingServiceAdapter | BillingService 구현체 |
// exam-svc에서 OMR 할당량 확인 예시
QuotaResult quota = billingService.checkQuota(tenantSlug, MetricType.OMR_MONTHLY_QUOTA);
if (!quota.allowed()) throw new ExamException(ExamErrorCode.QUOTA_EXCEEDED);
modules/student
책임: 학생 프로필, 학부모 연락처 관리
내부 API (StudentService)
Optional<StudentData> getStudent(String tenantSlug, Long studentId);
StudentListData getStudentsByIds(String tenantSlug, List<Long> studentIds);
Optional<StudentData> getStudentByPhone(String tenantSlug, String phone);
StudentListData getStudentsByUserIds(String tenantSlug, List<Long> userIds);
ValidateStudentResult validateStudent(String tenantSlug, Long studentId);