Entity Definition
Basic @QfEntity Declaration
Entities are declared using the @QfEntity annotation on a class.
@QfEntity(
appKey = "app", // client app key (optional; defaults to the single declared @QfClientApp)
name = @QfI18n(
defaultMessage = "Product",
texts = { @QfI18nText(locale = "ko", message = "상품") }
)
)
public class ProductEntity {
// field declarations...
}@QfEntity Key Attributes
| Attribute | Type | Required | Description | Default |
|---|---|---|---|---|
appKey | String | Owning client app key | "" (uses the single declared app) | |
name | @QfI18n | Localized display name | @QfI18n(texts = {}) | |
autoHistoryEnabled | boolean | Enable automatic change history | false | |
treePolicy | @QfTreePolicy | Enable and configure tree structure | @QfTreePolicy (disabled) | |
organizationPolicy | @QfOrganizationPolicy | Organization-based data filtering | @QfOrganizationPolicy(enabled = false) | |
deletePolicy | @QfCrudPolicy | Delete operation policy | @QfCrudPolicy(enabled = false) | |
capabilityKey | String | Capability key for access control | "" (derived from class name) | |
excelDownloadable | boolean | Enable Excel export | true | |
excelUploadable | boolean | Enable Excel import | true |
Attribute Declaration
Fields are managed by placing display and behavior annotations directly on them. There is no @QfField marker annotation — each annotation controls a specific concern.
@QfEntity(
name = @QfI18n(defaultMessage = "Product", texts = {})
)
public class ProductEntity {
// List + detail + create + update
@QfListAttribute(sortable = true)
@QfDetailAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfUpdateAttribute
@QfDisplayLabel(text = "Product Name")
private String name;
// List + detail only (read-only price)
@QfListAttribute
@QfDetailAttribute
@QfDisplayLabel(text = "Price")
private Integer price;
// Detail + create + update with textarea control
@QfDetailAttribute
@QfCreateAttribute
@QfUpdateAttribute
@QfControlType(QfControlType.Type.textarea)
@QfDisplayLabel(text = "Description")
private String description;
}Display Annotations
| Annotation | Description |
|---|---|
@QfListAttribute | Display as a column in the list view |
@QfDetailAttribute | Display in the detail view |
@QfCreateAttribute | Display as an input field in the create form |
@QfUpdateAttribute | Display as an input field in the update form |
@QfSearch | Enable as a search filter in the list view |
@QfDisplayLabel | Set the display label (key for i18n lookup, or literal text) |
Required Fields
Required rules are declared inside @QfCreateAttribute or @QfUpdateAttribute via requiredOn:
// Always required
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfUpdateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "Name")
private String name;
// Required only when type == 'BUSINESS'
@QfCreateAttribute(
requiredOn = @QfRequiredOn(
conditions = @QfConditionExpr(expr = "type == 'BUSINESS'")
)
)
@QfDisplayLabel(text = "Business Registration Number")
private String businessNumber;@QfCrypto Encryption
Declaring @QfCrypto on a sensitive field enables automatic encryption on save and decryption on read.
@QfDetailAttribute
@QfCreateAttribute
@QfCrypto // automatic encryption
@QfControlType(QfControlType.Type.email)
@QfDisplayLabel(text = "Email")
private String email;
@QfDetailAttribute
@QfCreateAttribute
@QfUpdateAttribute
@QfCrypto
@QfDisplayLabel(text = "Phone")
private String phone;Encrypted Field Restriction
A field with @QfCrypto cannot be combined with @QfSearch. Encrypted data does not support server-side LIKE search. This is enforced as a compile error.
Organization Policy
Organization-based data filtering is configured on the entity via organizationPolicy, specifying which attribute holds the organization identifier.
@QfEntity(
name = @QfI18n(defaultMessage = "Order", texts = {}),
organizationPolicy = @QfOrganizationPolicy(
enabled = true,
attribute = "orgId" // field name that holds the organization ID
)
)
public class OrderEntity {
private String orgId; // the org filter target (declared in organizationPolicy.attribute)
@QfListAttribute
@QfDisplayLabel(text = "Order Number")
private String orderNumber;
@QfListAttribute
@QfDisplayLabel(text = "Order Amount")
private Long amount;
}Entities with organization policy enabled:
- Automatically filter to the current user's organizational scope on queries
- Automatically populate the organization ID on creation
- Require no manual WHERE clause
Capability Key
Link an entity to a Capability by setting capabilityKey:
@QfEntity(
name = @QfI18n(defaultMessage = "Product", texts = {}),
capabilityKey = "product-management" // must match a @QfCapability key
)
public class ProductEntity {
// ...
}Master-Detail Relationship
Declare that an entity is a detail of a master entity via masterRelation:
// Order item (Detail entity)
@QfEntity(
name = @QfI18n(defaultMessage = "Order Item", texts = {}),
masterRelation = @QfMasterRelation(
enabled = true,
masterEntityFqcn = "com.example.OrderEntity", // fully-qualified master class name
masterKeyAttribute = "orderId", // attribute on THIS entity holding master's ID
onMasterDelete = QfMasterRelation.OnMasterDelete.CASCADE_DELETE
)
)
public class OrderItemEntity {
private String orderId; // master's ID
@QfListAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "Product Name")
private String productName;
@QfListAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "Quantity")
private Integer quantity;
}onMasterDelete options:
CASCADE_DELETE— delete detail records when master is deletedRESTRICT— reject master deletion if details existIGNORE— leave detail records orphaned
Enabling Change History
@QfEntity(
name = @QfI18n(defaultMessage = "Product", texts = {}),
autoHistoryEnabled = true // enable automatic change history
)
public class ProductEntity {
// ...
}When autoHistoryEnabled = true:
- All update and delete operations are automatically recorded
- A history query endpoint is automatically generated
Tree Structure Entities
Configure tree behavior via treePolicy:
@QfEntity(
name = @QfI18n(defaultMessage = "Category", texts = {}),
treePolicy = @QfTreePolicy
)
public class CategoryEntity {
@QfParent
private String parentId; // parent node ID
@QfTreeDepth
private Integer depth; // depth level
@QfListAttribute(isTreeNodeTitle = true)
@QfDisplayLabel(text = "Category Name")
private String name;
}With tree policy configured, a tree query endpoint is automatically generated.
Full Example: Composite Entity
@QfEntity(
name = @QfI18n(
defaultMessage = "Employee",
texts = { @QfI18nText(locale = "ko", message = "직원") }
),
organizationPolicy = @QfOrganizationPolicy(
enabled = true,
attribute = "orgId"
),
autoHistoryEnabled = true,
deletePolicy = @QfCrudPolicy(enabled = true),
capabilityKey = "hr-management"
)
public class EmployeeEntity {
// organization scope — filtered automatically
private String orgId;
// employee number
@QfListAttribute(sortable = true)
@QfDetailAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfSearch(type = QfSearch.Type.text)
@QfDisplayLabel(text = "Employee Number")
private String employeeNumber;
// full name
@QfListAttribute(sortable = true)
@QfDetailAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfUpdateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfSearch(type = QfSearch.Type.text)
@QfDisplayLabel(text = "Full Name")
private String fullName;
// SSN — encrypted, no search
@QfDetailAttribute
@QfCreateAttribute
@QfCrypto
@QfDisplayLabel(text = "SSN")
private String ssn;
// phone — encrypted with regex validation
@QfDetailAttribute
@QfCreateAttribute
@QfUpdateAttribute
@QfCrypto
@QfValidationRule(
rule = QfValidationRule.Rule.regex,
params = "^(?:\\+82[-\\s]?)?(?:0?1[0-9])[-\\s]?\\d{3,4}[-\\s]?\\d{4}$"
)
@QfDisplayLabel(text = "Phone")
private String phone;
// rank — from code group
@QfListAttribute
@QfDetailAttribute
@QfCreateAttribute
@QfUpdateAttribute
@QfCodeGroup(code = "EMPLOYEE_RANK")
@QfDisplayLabel(text = "Rank")
private String rank;
// join date
@QfListAttribute
@QfDetailAttribute
@QfCreateAttribute
@QfDisplayLabel(text = "Join Date")
private LocalDate joinDate;
}Next Steps
- Validation — Declare validation rules
- Capability / Access Control — Configure access control
- Organization Model — Organization-based data isolation