Skip to content

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.

java
@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

ItemIs SSOT?Reason
Annotation declaration✅ YesThe single authoritative definition
Generated metadata JSON❌ NoA derived copy from annotations
application.yml settings❌ NoRuntime environment configuration
Hook implementations❌ NoBusiness logic, not declarations
API response data❌ NoRuntime 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 handling

Annotations 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.

java
// 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:

  1. Annotation parsing and semantic analysis
  2. Contract violation checks (Fail-Fast)
  3. Metadata JSON file generation
  4. 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.
       → OrderEntity

Stage 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

Ready

Request processing flow:

HTTP request

Authentication / Authorization

Metadata-based validation

Organization-scoped data filtering

Hook execution

Data processing (including encryption)

Response returned

Client 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)
java
@QfClientApp(key = "app")
public class AppConfig { }

@QfClientApp(key = "admin")
public class AdminConfig { }

Capability (Business Function Area)

A logical functional unit accessed through a menu.

java
@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_own

Relationship 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 Team

When 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

Released under the Apache 2.0 License.