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 module manifest/permission seed 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 and seed
Section titled “1. Declare it in the module manifest and seed”Add the permission (and a menu entry if it’s new navigation) to the module manifest or generated permission seed:
{ "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 and permission seed are the reviewable source of the module’s menu/permission surface. Community applies them through Flyway seed SQL or the admin role/menu UI; the runtime does not auto-load manifest permissions into system tables.
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 Flyway/admin change 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/seed but forgetting @PreAuthorize leaves the endpoint unprotected — the architecture/security review catches this. Conversely, annotating with a permission code that is never seeded into the menu/permission tables means no role can be granted it. Keep the two in sync.