핵심 개념
SSOT (Single Source of Truth)
**단일 진실 원천(SSOT)**은 Q-Framework의 가장 핵심적인 설계 원칙입니다.
동일한 의미의 정보는 시스템 내 단 하나의 기준 정의에서만 관리되어야 한다.
Q-Framework에서 SSOT는 어노테이션 기반 선언입니다.
@QfEntity(appKey = "app", name = @QfI18n(defaultMessage = "User"))
public class UserEntity {
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true)) // <- 이것이 SSOT
@QfCrypto // <- 이것이 SSOT
@QfDisplayLabel(text = "Email") // <- 이것이 SSOT
private String email;
}이 선언 하나에서 다음이 모두 파생됩니다:
- API 요청 시 필수값 검증
- 저장 시 자동 암호화 / 조회 시 자동 복호화
- 프론트엔드 폼 검증 규칙
- Swagger 문서의 제약 조건 표시
같은 내용을 여러 곳에 중복 작성하지 않습니다.
SSOT가 아닌 것들
| 항목 | SSOT 여부 | 이유 |
|---|---|---|
| 어노테이션 선언 | ✅ SSOT | 권위 있는 유일한 정의 |
| 생성된 메타데이터 JSON | ❌ 아님 | 어노테이션에서 파생된 복사본 |
application.yml 설정 | ❌ 아님 | 런타임 환경 설정 |
| 훅(Hook) 구현 | ❌ 아님 | 비즈니스 로직, 선언이 아님 |
| API 응답 데이터 | ❌ 아님 | 런타임 상태 |
메타데이터 기반 계약
Q-Framework는 계약(Contract) 기반으로 동작합니다.
어노테이션 선언
↓ (컴파일 시점 APT 처리)
메타데이터 JSON 생성
↓ (런타임 로딩)
레지스트리 초기화
↓
API / UI 자동 처리개발자가 작성하는 어노테이션은 의미와 계약만 표현합니다. "어떻게 실행할 것인가"는 프레임워크에 위임합니다.
계약의 강제
계약 위반(잘못된 어노테이션 조합, 필수 속성 누락 등)은 컴파일 시점에 오류로 처리됩니다. 런타임까지 가지 않습니다.
3단계 생명주기
Q-Framework는 3단계 생명주기를 통해 동작합니다.
1단계: 작성 시점 (Authoring Time)
개발자가 어노테이션으로 도메인을 선언하는 단계입니다.
// 개발자가 선언
@QfEntity(appKey = "app", name = @QfI18n(defaultMessage = "Order"))
@QfCapability(key = "order_management")
public class OrderEntity {
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "Customer ID")
private String customerId;
}이 단계에서 Q-Framework의 역할:
- 어노테이션 정의 제공
- IDE 코드 완성 지원
2단계: 컴파일 시점 (Compile-time)
APT(Annotation Processing Tool, JSR-269)가 동작하는 단계입니다.
Q-Framework가 자동으로 수행:
- 어노테이션 파싱 및 의미 분석
- 계약 위반 검사 (Fail-Fast)
- 메타데이터 JSON 파일 생성
- 레지스트리 인덱스 생성
컴파일 시점에 감지되는 오류 예시:
ERROR: @QfCrypto와 @QfSearch는 동시에 사용할 수 없습니다.
암호화된 필드는 서버 사이드 검색이 불가합니다.
→ UserEntity.email
ERROR: organizationPolicy가 @QfEntity에 선언되었지만
organization provider가 설정되지 않았습니다.
→ OrderEntity3단계: 실행환경 (Runtime)
컴파일된 메타데이터를 기반으로 실제 요청을 처리하는 단계입니다.
런타임 초기화:
애플리케이션 시작
↓
메타데이터 JSON 파일 로딩
↓
엔티티 레지스트리 구성
↓
Capability / Privilege 레지스트리 구성
↓
API 라우팅 자동 등록
↓
준비 완료요청 처리 흐름:
HTTP 요청
↓
인증 / 인가 확인
↓
메타데이터 기반 검증
↓
조직 범위 데이터 필터링
↓
훅(Hook) 실행
↓
데이터 처리 (암호화 포함)
↓
응답 반환클라이언트 앱 / Capability / Privilege / Role 관계
클라이언트 앱 (Client App)
논리적으로 독립된 서비스 단위입니다.
하나의 백엔드 애플리케이션
├── app (일반 사용자 앱)
├── admin (관리자 앱)
└── mdm (마스터데이터 관리 앱)@QfClientApp(key = "app")
public class AppConfig { }
@QfClientApp(key = "admin")
public class AdminConfig { }Capability (업무 기능 영역)
메뉴를 통해 실행되는 논리적 기능 단위입니다.
@QfCapability(
key = "user-management",
name = @QfI18n(defaultMessage = "User Management", texts = { @QfI18nText(locale = "ko", message = "사용자 관리") }),
entities = { UserEntity.class },
privileges = {
@QfPrivilege(key = "user-management__create"),
@QfPrivilege(key = "user-management__update"),
@QfPrivilege(key = "user-management__delete"),
@QfPrivilege(key = "user-management__view-list")
}
)
public final class UserManagementCapability {
}Privilege (권한)
허용되는 행위 또는 접근을 표현하는 정책 단위입니다.
- 사람 단위가 아닌 행위 단위로 정의
- 키가 SSOT 기준 정의가 됨
예: user-management__create
Role (역할)
여러 Privilege를 묶은 집합입니다.
ROLE_ADMIN
├── user_management__create_user
├── user_management__delete_user
└── order_management__view_all
ROLE_ORDER_MANAGER
├── order_management__create_order
└── order_management__view_own관계 다이어그램
Client App
└── Capability (업무 기능 영역)
└── Privilege (권한)
└── Role = Set<Privilege>
└── User (런타임 할당)조직 모델 개요
Q-Framework는 계층적 조직 구조 기반의 데이터 접근 제어를 지원합니다.
본사
├── 서울 지점
│ ├── 영업팀
│ └── 지원팀
└── 부산 지점
└── 영업팀엔티티에 조직 정책(organizationPolicy)을 선언하면:
- 사용자의 소속 조직 범위에 따라 데이터가 자동 필터링됩니다.
- 별도의 WHERE 절 작성이 필요 없습니다.
- SaaS 멀티 테넌트 환경도 동일한 방식으로 처리됩니다.
자세한 내용은 조직 모델 가이드를 참고하세요.