Add a permission
StackRivet is default-deny: a protected endpoint is denied unless a permission allows it, and every protected endpoint must declare one (the architecture tests fail the build otherwise). The rule of thumb is declare the permission in the manifest first, then annotate the code.
Permission code format
Section titled “Permission code format”<module>:<resource>:<action># e.g. customer:customer:createA permission has a type: api (a server endpoint), button (a UI action) or menu (a navigation entry).
1. Declare it in the module manifest
Section titled “1. Declare it in the module manifest”Add the permission (and a menu entry if it’s new navigation) to the module manifest:
{ "permissions": [ { "code": "customer:customer:create", "type": "button", "name": "Create customer" }, { "code": "customer:customer:list", "type": "api", "name": "List customers" } ], "menus": [ { "code": "customer:customer:list", "path": "/customer/customers", "title": "Customers", "titleZh": "客户", "parent": "customer", "sortOrder": 100 } ]}The manifest is the source of truth: its permission and menu seeds load into the system tables on startup.
2. Enforce it on the controller
Section titled “2. Enforce it on the controller”Annotate the endpoint with @PreAuthorize:
@Operation(summary = "Create customer")@PostMapping@PreAuthorize("hasAuthority('customer:customer:create')")public R<CustomerResponse> create(@Valid @RequestBody CustomerCreateRequest request) { return R.ok(customerService.create(request));}An authenticated user without the authority gets 403; an unauthenticated request gets 401.
3. Gate the UI
Section titled “3. Gate the UI”Hide the button for users who lack the permission, using the StackRivet permission directive/component (button permissions). UI hiding is for UX only — the server check in step 2 is the real control.
4. Assign it to a role
Section titled “4. Assign it to a role”A permission does nothing until a role has it and a user has the role. In the admin UI, open System → Roles, edit a role, and grant the new menu/button. Users with that role pick up the permission on their next login (permissions resolve at login).
Verify
Section titled “Verify”# Without the authority → 403curl -i -H "Authorization: Bearer $TOKEN" -X POST \ http://127.0.0.1:8080/api/v1/customers# After granting the role the permission → 201/200You can also confirm the seed loaded by checking the menu tree (GET /api/v1/menus/tree) for the new entry.
Keep manifest and enforcement in sync
Section titled “Keep manifest and enforcement in sync”Declaring a permission in the manifest but forgetting @PreAuthorize leaves the endpoint unprotected — the architecture/security review catches this. Conversely, annotating with a permission code that no manifest declares means no role can ever be granted it. Keep the two in sync.