Staff 모듈
Staff 모듈(modules/staff)은 Lumie 플랫폼의 스태프(관리자) 계정과 권한을 관리합니다. 테넌트별 스태프 등록, 직책 체계 없는 플랫 구조, 세분화된 권한 제어 기능을 제공합니다.
모듈 개요
- 배포: lumie-backend 모놀리스의
modules/staff - 데이터베이스: PostgreSQL (멀티테넌트 RLS)
- 주요 의존성:
AuthService(internal-api),BillingService(internal-api)
주요 기능
관리자 관리
- 관리자 등록 및 정보 관리
- 학원별 관리자 배정
- 관리자 활성화/비활성화/퇴사 처리
- 관리자 삭제 (비활성 상태만)
직책 관리
- 직책 생성 및 관리
- 직책별 권한 템플릿
- 직책 활성화/비활성화
권한 관리
- 관리자별 세분화된 권한 설정
- 카테고리별 권한 조회
- 접근 레벨 제어 (READ, WRITE, ADMIN)
API 엔드포인트
스태프 관리 API
스태프 등록
POST /v1/staff
Content-Type: application/json
{
"userLoginId": "staff001",
"name": "김스태프",
"phone": "010-1234-5678",
"email": "staff@example.com"
}
스태프 목록 조회
GET /v1/staff?isActive=true&search=김스태프&page=0&size=20
스태프 정보 수정
PATCH /v1/staff/{id}
Content-Type: application/json
{
"name": "김스태프2",
"phone": "010-1234-5679",
"email": "staff2@example.com"
}
스태프 권한 조회
GET /v1/staff/{staffId}/permissions
응답 예시:
[
{
"permissionCode": "STUDENT_READ",
"accessLevel": "READ"
},
{
"permissionCode": "EXAM_MANAGE",
"accessLevel": "WRITE"
}
]
스태프 권한 설정
PUT /v1/staff/{staffId}/permissions
Content-Type: application/json
{
"permissions": [
{"permissionCode": "STUDENT_READ", "accessLevel": "READ"},
{"permissionCode": "EXAM_MANAGE", "accessLevel": "WRITE"}
]
}
스태프 상태 변경
POST /v1/staff/{id}/deactivate
POST /v1/staff/{id}/reactivate
POST /v1/staff/{id}/reset-password
PATCH /v1/staff/{id}/login-id
권한 관리 API
전체 권한 목록
GET /v1/permissions
카테고리별 권한 조회
GET /v1/permissions/by-category
응답 예시:
{
"STUDENT": [
{
"id": 1,
"code": "STUDENT_READ",
"name": "학생 조회",
"category": "STUDENT",
"description": "학생 정보를 조회할 수 있습니다"
}
],
"EXAM": [
{
"id": 2,
"code": "EXAM_MANAGE",
"name": "시험 관리",
"category": "EXAM",
"description": "시험을 생성하고 관리할 수 있습니다"
}
]
}
internal-api
libs/internal-api에 정의된 StaffService 인터페이스를 StaffServiceAdapter가 구현하여 다른 모듈에 스태프 정보를 제공합니다.
// libs/internal-api/src/main/java/com/lumie/staff/api/StaffService.java
public interface StaffService {
Optional<StaffData> getStaff(String tenantSlug, Long staffId);
Optional<StaffData> getStaffByUserId(String tenantSlug, Long userId);
ValidateStaffResult validateStaff(String tenantSlug, Long staffId);
StaffPermissionsData getStaffPermissions(String tenantSlug, Long staffId);
StaffListData getAllStaff(String tenantSlug, int page, int size);
StaffData createOwnerStaff(String tenantSlug, Long userId, String userLoginId,
String name, String phone, String email);
}
사용 예시
// 다른 모듈에서 스태프 권한 확인 (in-process 메서드 호출)
@Component
@RequiredArgsConstructor
public class StaffPermissionAdapter implements CheckStaffPermissionPort {
private final StaffService staffService;
@Override
public boolean hasPermission(Long staffId, String permissionCode) {
String tenantSlug = TenantContextHolder.getRequiredTenant();
StaffService.StaffPermissionsData perms =
staffService.getStaffPermissions(tenantSlug, staffId);
return perms.permissions().stream()
.anyMatch(p -> p.permissionCode().equals(permissionCode));
}
}
도메인 모델
Staff 엔티티
@Entity
@Table(name = "staff")
public class Staff extends BaseEntity {
private Long userId; // auth 모듈 사용자 ID
private String userLoginId; // 로그인 ID
private String name; // 스태프명
private String phone; // 전화번호
private String email; // 이메일
private Boolean isActive; // 활성 상태
private EmploymentStatus employmentStatus; // 재직 상태 (ACTIVE / INACTIVE / TERMINATED)
}
값 객체
public enum AccessLevel {
READ, // 조회만 가능
WRITE, // 생성/수정 가능
ADMIN // 모든 권한 (삭제 포함)
}
public enum EmploymentStatus {
ACTIVE, // 재직
INACTIVE, // 휴직
TERMINATED // 퇴사
}
비즈니스 로직
스태프 등록 프로세스
BillingService.checkQuota(tenantSlug, MAX_ADMINS)할당량 확인userLoginId중복 검증AuthService.createUser(...)(internal-api) 로 사용자 계정 생성Staff엔티티 생성 및 저장
할당량 검증
private void checkStaffQuota(String tenantSlug) {
BillingService.QuotaResult result =
billingService.checkQuota(tenantSlug, MetricType.MAX_ADMINS);
if (!result.allowed()) {
throw new StaffException(StaffErrorCode.QUOTA_EXCEEDED);
}
}
권한 설정 로직
권한(StaffPermission)은 (staffId, permissionCode) 복합 기본키로 관리됩니다. PUT /v1/staff/{staffId}/permissions 호출 시 기존 권한을 전량 삭제 후 재등록합니다.
데이터베이스 설계
주요 테이블
CREATE TABLE staff (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
user_login_id VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
phone VARCHAR(20),
email VARCHAR(255),
is_active BOOLEAN DEFAULT true,
employment_status VARCHAR(20) DEFAULT 'ACTIVE',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE permission (
id BIGSERIAL PRIMARY KEY,
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL,
description TEXT
);
CREATE TABLE staff_permission (
staff_id BIGINT NOT NULL REFERENCES staff(id),
permission_code VARCHAR(50) NOT NULL REFERENCES permission(code),
access_level VARCHAR(20) NOT NULL,
PRIMARY KEY (staff_id, permission_code)
);
에러 처리
public enum StaffErrorCode implements ErrorCode {
STAFF_NOT_FOUND("STAFF_001", "스태프를 찾을 수 없습니다", 404),
PERMISSION_NOT_FOUND("PERMISSION_001", "권한을 찾을 수 없습니다", 404),
DUPLICATE_USER_LOGIN_ID("STAFF_002", "이미 존재하는 로그인 ID입니다", 409),
DUPLICATE_PHONE("STAFF_003", "이미 존재하는 전화번호입니다", 409),
QUOTA_EXCEEDED("QUOTA_001", "스태프 수 제한을 초과했습니다", 403);
}
모니터링
주요 메트릭
- 관리자 등록/수정/삭제 횟수
- 직책 생성/수정/삭제 횟수
- 권한 설정 변경 횟수
- 데이터베이스 연결 풀 상태
로그 예시
{
"timestamp": "2024-01-15T10:30:00.000Z",
"level": "INFO",
"logger": "com.lumie.staff.application.service.StaffCommandService",
"message": "Staff registered: staff001 in tenant: inst-demo",
"tenantSlug": "inst-demo",
"userId": "123",
"staffId": "456"
}
관련 문서
- Auth Service — 사용자 계정 생성 연동
- Billing Service — 스태프 수 할당량 관리 연동