Capability / Access Control
Overview
Q-Framework's permission model has three layers.
Client App
└── Capability (business function area)
└── Privilege (allowed action)
└── Role = Set<Privilege>@QfCapability Declaration
@QfCapability defines a logical functional unit and the privileges that belong to it.
@QfCapability(
key = "user-management",
name = @QfI18n(
defaultMessage = "User Management",
texts = { @QfI18nText(locale = "ko", message = "사용자 관리") }
),
entities = { UserEntity.class },
privileges = {
@QfPrivilege(key = "user-management__view-list"),
@QfPrivilege(key = "user-management__view-detail"),
@QfPrivilege(key = "user-management__create"),
@QfPrivilege(key = "user-management__update"),
@QfPrivilege(key = "user-management__delete")
}
)
public final class UserManagementCapability {
}Linking Entity to Capability
Declare capabilityKey on @QfEntity to link it to a Capability.
@QfEntity(
appKey = "admin",
name = @QfI18n(
defaultMessage = "User",
texts = { @QfI18nText(locale = "ko", message = "사용자") }
),
capabilityKey = "user-management"
)
public class UserEntity {
// ...
}@QfPrivilege Definition
Privileges are declared as a nested array inside @QfCapability(privileges = {...}). An optional name can be provided for display purposes.
@QfCapability(
key = "user-management",
name = @QfI18n(defaultMessage = "User Management"),
entities = { UserEntity.class },
privileges = {
@QfPrivilege(
key = "user-management__view-list",
name = @QfI18n(defaultMessage = "View User List")
),
@QfPrivilege(
key = "user-management__view-detail",
name = @QfI18n(defaultMessage = "View User Detail")
),
@QfPrivilege(
key = "user-management__create",
name = @QfI18n(defaultMessage = "Create User")
),
@QfPrivilege(
key = "user-management__update",
name = @QfI18n(defaultMessage = "Update User")
),
@QfPrivilege(
key = "user-management__delete",
name = @QfI18n(defaultMessage = "Delete User")
)
}
)
public final class UserManagementCapability {
}Privilege Key Format
{capability-key}__{privilege-name}
↓ ↓
user-management __ createSSOT Guarantee
The privilege key is the single authoritative identifier used in authorization policy, runtime checks, and UI control.
Role Configuration
Roles are composed of Privilege sets at runtime. Q-Framework does not enforce a specific Role definition approach — integration is done via SPI.
QfUserProvider SPI Implementation
@Component
public class MyUserProvider implements QfUserProvider {
@Override
public QfUser getCurrentUser(HttpServletRequest request) {
// return user information for the current request
UserPrincipal principal = SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
return QfUser.builder()
.id(principal.getId())
.name(principal.getName())
.organizationId(principal.getOrganizationId())
// privileges granted to this user
.privileges(Set.of(
"user-management__view-list",
"user-management__view-detail",
"order-management__create"
))
.build();
}
}Q-Framework automatically controls API access based on the returned privileges list.
Screen and Data Access Control
API-Level Control
GET /api/admin/users → requires user-management__view-list Privilege
GET /api/admin/users/{id} → requires user-management__view-detail Privilege
POST /api/admin/users → requires user-management__create Privilege
PUT /api/admin/users/{id} → requires user-management__update Privilege
DEL /api/admin/users/{id} → requires user-management__delete PrivilegeRequests from users without the required Privilege automatically receive 403 Forbidden.
Frontend UI Control
<template>
<!-- Buttons shown/hidden automatically based on Privileges -->
<QfEntityView
client-app="admin"
entity="user"
/>
</template>Q-Framework UI components automatically show or hide create/update/delete buttons based on the user's Privileges.
Operations Checklist
After declaring a new Capability, verify the following.
- [ ] Is the
@QfCapabilitykeyunique — no duplicates with other Capabilities? - [ ] Have all necessary
@QfPrivilegeentries been declared insideprivileges = {...}? - [ ] Is there a Role configured in
QfUserProviderthat returns the relevant Privileges? - [ ] Has at least one Privilege been granted to an admin account?
- [ ] After compilation, is the Capability registered in metadata?
Next Steps
- Organization Model — Organization-based data isolation
- SPI Extensions — Custom permission integration