Files
trackgo-be/.cursor/rules/privileges.mdc
T
shancheas 07550b3167 Add privilege management system with related migrations and guards
- Introduced a new `PrivilegesModule` to manage user privileges and access control.
- Added `RequirePrivilege` decorator to enforce privilege checks on controller handlers.
- Implemented `PrivilegesGuard` to handle authorization based on user privileges.
- Created database migrations for `privileges`, `privilege_keys`, and `privilege_details` tables.
- Updated user model to include `is_superadmin` field for enhanced access control.
- Added unit tests for the new privileges functionality and guards to ensure correct behavior.
2026-08-24 11:31:13 +07:00

38 lines
1.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: Primary modules must use @RequirePrivilege on every non-public handler; privilege_keys seeded per module
globs: "src/modules/**/*.ts,src/common/decorators/**/*.ts,src/common/guards/**/*.ts"
alwaysApply: false
---
# Privileges Authorization
## Mandatory
Every **non-public** controller handler on a primary (CRUD) resource MUST use:
```typescript
@RequirePrivilege('MODULE.RESOURCE', 'view' | 'create' | 'update' | 'delete' | 'import')
```
Map HTTP verbs to actions:
| Handler | Action |
| ------- | ------ |
| `GET` list / detail | `view` |
| `POST /` create | `create` |
| `PATCH /:id`, status, bulk-status | `update` |
| `DELETE /:id`, bulk-delete | `delete` |
| `POST /import` | `import` |
Key codes use dotted uppercase module levels (`PRIVILEGES`, `SALES.INVOICE`). New modules add a `privilege_keys` seed row via migration — do not invent a parallel permission helper.
Seed an Administrator privilege only via SQL/ops after the first user exists (`created_by` requires a user). Documented bootstrap: insert privilege + details, then `UPDATE users SET privilege_id = …`. Do not auto-grant on register.
## Guard behavior
`PrivilegesGuard` (global) allows when there is no metadata. When metadata is present, `users.is_superadmin === true` skips the matrix check. Otherwise the users assigned privilege must be **status `active`** and the matrix cell must be `value === true`, or the request is `403 Forbidden`. Missing privilege / draft / archived / missing cell / `false` → deny.
Do not set `is_superadmin` via register/login. Default is `false`; promote via SQL/ops (`UPDATE users SET is_superadmin = true`). The flag is loaded from the database on each JWT validation (not from JWT claims).
Primary tables still use `primaryEntityColumns(users)` (`status`, audit timestamps, `created_by` / `updated_by`).