Skip to content

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.

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

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

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

SSOT 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

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

Requests from users without the required Privilege automatically receive 403 Forbidden.

Frontend UI Control

vue
<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 @QfCapability key unique — no duplicates with other Capabilities?
  • [ ] Have all necessary @QfPrivilege entries been declared inside privileges = {...}?
  • [ ] Is there a Role configured in QfUserProvider that 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

Released under the Apache 2.0 License.