Core Concepts
SSOT (Single Source of Truth)
Single Source of Truth (SSOT) is the most fundamental design principle of Q-Framework.
A single authoritative definition must exist for any piece of meaningful information in the system.
In Q-Framework, the SSOT is the annotation-based declaration.
@QfEntity(appKey = "app", name = @QfI18n(defaultMessage = "User"))
public class UserEntity {
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true)) // <- this is the SSOT
@QfCrypto // <- this is the SSOT
@QfDisplayLabel(text = "Email") // <- this is the SSOT
private String email;
}From this single declaration, all of the following are derived:
- Required field validation on API requests
- Automatic encryption on save / decryption on read
- Frontend form validation rules
- Constraint display in Swagger documentation
The same information is never written in multiple places.
What is NOT a SSOT
| Item | Is SSOT? | Reason |
|---|---|---|
| Annotation declaration | ✅ Yes | The single authoritative definition |
| Generated metadata JSON | ❌ No | A derived copy from annotations |
application.yml settings | ❌ No | Runtime environment configuration |
| Hook implementations | ❌ No | Business logic, not declarations |
| API response data | ❌ No | Runtime state |
Metadata-Based Contract
Q-Framework operates on a contract model.
Annotation declaration
↓ (APT processing at compile time)
Metadata JSON generation
↓ (loaded at runtime)
Registry initialization
↓
Automatic API / UI handlingAnnotations written by developers express only semantics and contracts. The framework is delegated responsibility for "how to execute."
Contract Enforcement
Contract violations — invalid annotation combinations, missing required attributes, etc. — are treated as compile errors. They never reach runtime.
3-Stage Lifecycle
Q-Framework operates through a 3-stage lifecycle.
Stage 1: Authoring Time
The stage where developers declare their domain using annotations.
// Developer declares
@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's role at this stage:
- Provide annotation definitions
- Support IDE code completion
Stage 2: Compile Time
The stage where APT (Annotation Processing Tool, JSR-269) operates.
Q-Framework automatically performs:
- Annotation parsing and semantic analysis
- Contract violation checks (Fail-Fast)
- Metadata JSON file generation
- Registry index generation
Examples of errors detected at compile time:
ERROR: @QfCrypto and @QfSearch cannot be used together.
Encrypted fields do not support server-side search.
→ UserEntity.email
ERROR: organizationPolicy declared on @QfEntity but
organization provider is not configured.
→ OrderEntityStage 3: Runtime
The stage where compiled metadata is used to process actual requests.
Runtime initialization:
Application startup
↓
Load metadata JSON files
↓
Build entity registry
↓
Build Capability / Privilege registry
↓
Auto-register API routes
↓
ReadyRequest processing flow:
HTTP request
↓
Authentication / Authorization
↓
Metadata-based validation
↓
Organization-scoped data filtering
↓
Hook execution
↓
Data processing (including encryption)
↓
Response returnedClient App / Capability / Privilege / Role Relationships
Client App
A logically independent service unit.
Single backend application
├── app (end-user app)
├── admin (administrator app)
└── mdm (master data management app)@QfClientApp(key = "app")
public class AppConfig { }
@QfClientApp(key = "admin")
public class AdminConfig { }Capability (Business Function Area)
A logical functional unit accessed through a menu.
@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
A policy unit representing an allowed action or access.
- Defined per action, not per person
- The key serves as the SSOT definition
Example: user_management__create_user
Role
A set of Privileges grouped together.
ROLE_ADMIN
├── user_management__create_user
├── user_management__delete_user
└── order_management__view_all
ROLE_ORDER_MANAGER
├── order_management__create_order
└── order_management__view_ownRelationship Diagram
Client App
└── Capability (business function area)
└── Privilege (allowed action)
└── Role = Set<Privilege>
└── User (assigned at runtime)Organization Model Overview
Q-Framework supports data access control based on hierarchical organizational structures.
Headquarters
├── Seoul Branch
│ ├── Sales Team
│ └── Support Team
└── Busan Branch
└── Sales TeamWhen organization policy is declared on an entity:
- Data is automatically filtered based on the user's organizational scope.
- No manual WHERE clause is needed.
- SaaS multi-tenant environments are handled the same way.
For details, see the Organization Model Guide.
Next Steps
- Entity Definition — Build entities in real code
- Architecture Overview — Deep dive into internal structure