조직 모델
Q-Framework는 계층적 조직 구조 기반의 데이터 접근 제어를 지원합니다. 별도의 WHERE 절 작성 없이 선언만으로 조직 범위 데이터 격리가 자동으로 적용됩니다.
조직 계층 구조
본사 (ROOT)
├── 서울 본부 (BRANCH)
│ ├── 영업1팀 (TEAM)
│ ├── 영업2팀 (TEAM)
│ └── 지원팀 (TEAM)
└── 부산 지사 (BRANCH)
├── 영업팀 (TEAM)
└── 지원팀 (TEAM)각 조직은 고유 ID를 가지며, 부모-자식 계층 관계로 구성됩니다.
조직 가시 범위 (Organization Visibility Scope)
사용자가 어떤 조직의 데이터를 볼 수 있는지를 결정합니다.
핵심 구성 요소
| 구성 요소 | 설명 |
|---|---|
| Anchor (기준점) | 데이터 접근의 기준이 되는 조직 |
| Include Rule (포함 범위) | 기준점 기준으로 어디까지 포함할지 |
| Depth Limit (깊이 제한) | 포함 범위의 최대 깊이 |
Include Rule 옵션
| 규칙 | 설명 | 예시 |
|---|---|---|
SELF | 기준점 조직만 | 자신의 팀 데이터만 |
CHILDREN | 기준점 하위 조직 포함 | 자신과 하위 팀 모두 |
ROOT_TO_SELF | 루트부터 기준점까지 | 본사부터 자신의 팀까지 상위 모두 |
조직 정책 선언
java
@QfEntity(
appKey = "app",
name = @QfI18n(defaultMessage = "Sales Record", texts = { @QfI18nText(locale = "ko", message = "영업 실적") }),
organizationPolicy = @QfOrganizationPolicy(enabled = true)
)
public class SalesRecordEntity {
@QfDisplayLabel(text = "Amount")
@QfListAttribute(sortable = true)
private Long amount;
@QfDisplayLabel(text = "Sales Date")
@QfListAttribute(sortable = true)
private LocalDate salesDate;
}조직 가시 정책 설정
application.yml에서 조직 가시 정책을 설정합니다.
yaml
qf:
organization:
visibility:
anchor: SELF # 기준점: 본인 조직
include-rule: CHILDREN # 범위: 본인 + 하위 조직
depth-limit: 2 # 최대 2단계 하위까지정책별 동작 예시
시나리오: 서울 본부 소속 사용자가 데이터를 조회하는 경우
조직 트리:
본사
└── 서울 본부 ← 현재 사용자
├── 영업1팀
├── 영업2팀
└── 지원팀| anchor | include-rule | depth-limit | 접근 가능 범위 |
|---|---|---|---|
| SELF | SELF | — | 서울 본부 데이터만 |
| SELF | CHILDREN | 1 | 서울 본부 + 직속 팀 3개 |
| SELF | CHILDREN | 무제한 | 서울 본부 + 모든 하위 조직 |
| SELF | ROOT_TO_SELF | — | 본사 + 서울 본부 |
런타임 적용 방식
조직 범위 쿼리는 자동으로 생성됩니다. 개발자가 직접 작성할 필요가 없습니다.
sql
-- Q-Framework가 자동 생성하는 조건 예시
-- (anchor=SELF, include-rule=CHILDREN, depth-limit=2)
WHERE organization_id IN (
SELECT id FROM organization
WHERE id = :currentUserOrgId
OR parent_id = :currentUserOrgId
OR (parent_id IN (
SELECT id FROM organization WHERE parent_id = :currentUserOrgId
))
)SaaS 환경에서의 조직 모델 활용
Q-Framework의 조직 모델은 멀티 테넌트 SaaS 환경을 자연스럽게 지원합니다.
테넌트 = 최상위 조직
테넌트A (Root) 테넌트B (Root)
└── 서울 지점 └── 본사
└── 영업팀 └── 개발팀각 테넌트가 루트 조직이 되며, anchor=SELF, include-rule=CHILDREN으로 설정하면 다른 테넌트의 데이터가 자동으로 격리됩니다.
일반적인 Tenant 중심 모델과의 차이
| 구분 | 일반 멀티 테넌트 | Q-Framework 조직 모델 |
|---|---|---|
| 격리 방식 | tenant_id 컬럼 하드코딩 | 계층 조직 가시 범위 |
| 내부 계층 지원 | 별도 구현 필요 | 기본 제공 |
| 권한 세분화 | 복잡한 RBAC 구현 | 조직 계층 + Privilege |
| 선언 방식 | 코드 레벨 구현 | 어노테이션 선언 |
조직 정보 제공 (SPI)
조직 정보는 QfOrganizationProvider SPI를 통해 제공합니다.
java
@Component
public class MyOrganizationProvider implements QfOrganizationProvider {
@Override
public List<QfOrganization> getOrganizationHierarchy(String rootOrgId) {
// 조직 계층 데이터 반환
return organizationRepository.findHierarchyByRoot(rootOrgId)
.stream()
.map(org -> QfOrganization.builder()
.id(org.getId())
.parentId(org.getParentId())
.name(org.getName())
.depth(org.getDepth())
.build())
.collect(Collectors.toList());
}
}