@flusys/nestjs-iam 0.1.0-beta.1 → 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +665 -0
- package/cjs/config/iam.constants.js +11 -0
- package/cjs/config/index.js +18 -0
- package/cjs/controllers/action.controller.js +117 -0
- package/cjs/controllers/company-action-permission.controller.js +110 -0
- package/cjs/controllers/index.js +23 -0
- package/cjs/controllers/my-permission.controller.js +90 -0
- package/cjs/controllers/role-permission.controller.js +160 -0
- package/cjs/controllers/role.controller.js +58 -0
- package/cjs/controllers/user-action-permission.controller.js +110 -0
- package/cjs/docs/iam-swagger.config.js +202 -0
- package/cjs/docs/index.js +18 -0
- package/cjs/dtos/action.dto.js +347 -0
- package/cjs/dtos/index.js +21 -0
- package/cjs/dtos/permission.dto.js +554 -0
- package/cjs/dtos/role.dto.js +238 -0
- package/cjs/entities/action-base.entity.js +135 -0
- package/cjs/entities/action.entity.js +28 -0
- package/cjs/entities/index.js +81 -0
- package/cjs/entities/permission-base.entity.js +156 -0
- package/cjs/entities/permission-with-company.entity.js +99 -0
- package/cjs/entities/role-base.entity.js +86 -0
- package/cjs/entities/role-with-company.entity.js +55 -0
- package/cjs/entities/role.entity.js +25 -0
- package/cjs/entities/user-iam-permission.entity.js +57 -0
- package/cjs/enums/action-type.enum.js +22 -0
- package/cjs/enums/index.js +19 -0
- package/cjs/enums/permission-type.enum.js +16 -0
- package/cjs/helpers/index.js +19 -0
- package/cjs/helpers/permission-evaluator.helper.js +175 -0
- package/cjs/helpers/permission-mode.helper.js +49 -0
- package/cjs/index.js +28 -79
- package/cjs/interfaces/action.interface.js +4 -0
- package/cjs/interfaces/iam-module-async-options.interface.js +4 -0
- package/cjs/interfaces/iam-module-options.interface.js +18 -0
- package/cjs/interfaces/index.js +21 -0
- package/cjs/interfaces/role.interface.js +7 -0
- package/cjs/modules/iam.module.js +237 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/services/action.service.js +253 -0
- package/cjs/services/iam-config.service.js +107 -0
- package/cjs/services/iam-datasource.provider.js +205 -0
- package/cjs/services/index.js +23 -0
- package/cjs/services/permission-cache.service.js +308 -0
- package/cjs/services/permission.service.js +1020 -0
- package/cjs/services/role.service.js +181 -0
- package/cjs/types/index.js +18 -0
- package/cjs/types/logic-node.type.js +54 -0
- package/fesm/config/iam.constants.js +1 -0
- package/fesm/config/index.js +1 -0
- package/fesm/controllers/action.controller.js +107 -0
- package/fesm/controllers/company-action-permission.controller.js +100 -0
- package/fesm/controllers/index.js +7 -0
- package/fesm/controllers/my-permission.controller.js +80 -0
- package/fesm/controllers/role-permission.controller.js +150 -0
- package/fesm/controllers/role.controller.js +48 -0
- package/fesm/controllers/user-action-permission.controller.js +100 -0
- package/fesm/docs/iam-swagger.config.js +192 -0
- package/fesm/docs/index.js +1 -0
- package/fesm/dtos/action.dto.js +317 -0
- package/fesm/dtos/index.js +4 -0
- package/fesm/dtos/permission.dto.js +490 -0
- package/fesm/dtos/role.dto.js +214 -0
- package/fesm/entities/action-base.entity.js +128 -0
- package/fesm/entities/action.entity.js +18 -0
- package/fesm/entities/index.js +56 -0
- package/fesm/entities/permission-base.entity.js +138 -0
- package/fesm/entities/permission-with-company.entity.js +89 -0
- package/fesm/entities/role-base.entity.js +79 -0
- package/fesm/entities/role-with-company.entity.js +45 -0
- package/fesm/entities/role.entity.js +15 -0
- package/fesm/entities/user-iam-permission.entity.js +38 -0
- package/fesm/enums/action-type.enum.js +12 -0
- package/fesm/enums/index.js +2 -0
- package/fesm/enums/permission-type.enum.js +6 -0
- package/fesm/helpers/index.js +2 -0
- package/fesm/helpers/permission-evaluator.helper.js +165 -0
- package/fesm/helpers/permission-mode.helper.js +49 -0
- package/fesm/index.js +11 -79
- package/fesm/interfaces/action.interface.js +3 -0
- package/fesm/interfaces/iam-module-async-options.interface.js +3 -0
- package/fesm/interfaces/iam-module-options.interface.js +1 -0
- package/fesm/interfaces/index.js +4 -0
- package/fesm/interfaces/role.interface.js +4 -0
- package/fesm/modules/iam.module.js +227 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/services/action.service.js +243 -0
- package/fesm/services/iam-config.service.js +97 -0
- package/fesm/services/iam-datasource.provider.js +154 -0
- package/fesm/services/index.js +6 -0
- package/fesm/services/permission-cache.service.js +298 -0
- package/fesm/services/permission.service.js +1010 -0
- package/fesm/services/role.service.js +171 -0
- package/fesm/types/index.js +1 -0
- package/fesm/types/logic-node.type.js +36 -0
- package/package.json +25 -25
- package/cjs/config-index.js +0 -1
- package/cjs/controllers-index.js +0 -1
- package/cjs/docs-index.js +0 -79
- package/cjs/dtos-index.js +0 -1
- package/cjs/entities-index.js +0 -1
- package/cjs/enums-index.js +0 -1
- package/cjs/helpers-index.js +0 -1
- package/cjs/interfaces-index.js +0 -1
- package/cjs/modules-index.js +0 -1
- package/cjs/services-index.js +0 -1
- package/cjs/types-index.js +0 -1
- package/fesm/config-index.js +0 -1
- package/fesm/controllers-index.js +0 -1
- package/fesm/docs-index.js +0 -79
- package/fesm/dtos-index.js +0 -1
- package/fesm/entities-index.js +0 -1
- package/fesm/enums-index.js +0 -1
- package/fesm/helpers-index.js +0 -1
- package/fesm/interfaces-index.js +0 -0
- package/fesm/modules-index.js +0 -1
- package/fesm/services-index.js +0 -1
- package/fesm/types-index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
# IAM Package Guide
|
|
2
|
+
|
|
3
|
+
> **Package:** `@flusys/nestjs-iam`
|
|
4
|
+
> **Purpose:** Identity and Access Management with RBAC, ABAC, and permission logic
|
|
5
|
+
> **Version:** 4.4.0 | **Updated:** 2026-01-24
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Overview](#overview)
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Module Configuration](#module-configuration)
|
|
12
|
+
- [Core Concepts](#core-concepts)
|
|
13
|
+
- [Entities](#entities)
|
|
14
|
+
- [Permission Modes](#permission-modes)
|
|
15
|
+
- [Permission Logic](#permission-logic)
|
|
16
|
+
- [Services](#services)
|
|
17
|
+
- [REST API Endpoints](#rest-api-endpoints)
|
|
18
|
+
- [Multi-Tenant Support](#multi-tenant-support)
|
|
19
|
+
- [Permission Guard Integration](#permission-guard-integration)
|
|
20
|
+
- [Best Practices](#best-practices)
|
|
21
|
+
- [API Reference](#api-reference)
|
|
22
|
+
- [Package Architecture](#package-architecture)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
`@flusys/nestjs-iam` provides a comprehensive Identity and Access Management system:
|
|
29
|
+
|
|
30
|
+
- **Hierarchical Actions** - Organize permissions in tree structures
|
|
31
|
+
- **Action Types** - BACKEND (cached for guards), FRONTEND (returned to UI), BOTH
|
|
32
|
+
- **RBAC** - Role-Based Access Control
|
|
33
|
+
- **ABAC/DIRECT** - Direct user-to-action assignments
|
|
34
|
+
- **Permission Logic** - Complex AND/OR rules
|
|
35
|
+
- **Company/Branch Scoping** - Multi-tenant permissions with three-level granularity
|
|
36
|
+
- **Centralized Caching** - Automatic cache invalidation for security
|
|
37
|
+
|
|
38
|
+
### Package Hierarchy
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
@flusys/nestjs-core <- Foundation
|
|
42
|
+
|
|
|
43
|
+
@flusys/nestjs-shared <- Shared utilities
|
|
44
|
+
|
|
|
45
|
+
@flusys/nestjs-auth <- User/Company management
|
|
46
|
+
|
|
|
47
|
+
@flusys/nestjs-iam <- Permission management (THIS PACKAGE)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install @flusys/nestjs-iam @flusys/nestjs-shared @flusys/nestjs-core
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Module Configuration
|
|
61
|
+
|
|
62
|
+
### With Auth Module (Recommended)
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { AuthModule } from '@flusys/nestjs-auth';
|
|
66
|
+
import { IAMModule } from '@flusys/nestjs-iam';
|
|
67
|
+
|
|
68
|
+
@Module({
|
|
69
|
+
imports: [
|
|
70
|
+
AuthModule.forRoot({
|
|
71
|
+
includeIAM: true, // Required for single-tenant mode
|
|
72
|
+
bootstrapAppConfig: {
|
|
73
|
+
databaseMode: 'single',
|
|
74
|
+
enableCompanyFeature: true,
|
|
75
|
+
},
|
|
76
|
+
config: { /* auth config */ },
|
|
77
|
+
}),
|
|
78
|
+
|
|
79
|
+
IAMModule.forRoot({
|
|
80
|
+
global: true,
|
|
81
|
+
includeController: true,
|
|
82
|
+
bootstrapAppConfig: {
|
|
83
|
+
databaseMode: 'single',
|
|
84
|
+
enableCompanyFeature: true,
|
|
85
|
+
permissionMode: 'FULL', // 'FULL' | 'RBAC' | 'DIRECT'
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
],
|
|
89
|
+
})
|
|
90
|
+
export class AppModule {}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Core Concepts
|
|
96
|
+
|
|
97
|
+
### Actions
|
|
98
|
+
|
|
99
|
+
Actions represent permissions in the system:
|
|
100
|
+
|
|
101
|
+
| Field | Description |
|
|
102
|
+
|-------|-------------|
|
|
103
|
+
| `name` | Human-readable name |
|
|
104
|
+
| `code` | Unique identifier (e.g., `user.create`) |
|
|
105
|
+
| `actionType` | Category: `backend`, `frontend`, or `both` |
|
|
106
|
+
| `metadata` | Additional data (icon, routerLink for frontend) |
|
|
107
|
+
| `parentId` | Parent action for hierarchy |
|
|
108
|
+
| `serial` | Display order |
|
|
109
|
+
|
|
110
|
+
### Action Types
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
enum ActionType {
|
|
114
|
+
BACKEND = 'backend', // API endpoint permissions (cached for PermissionGuard)
|
|
115
|
+
FRONTEND = 'frontend', // UI features (returned in my-permissions API)
|
|
116
|
+
BOTH = 'both', // Both backend and frontend
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Roles
|
|
121
|
+
|
|
122
|
+
Roles are collections of actions:
|
|
123
|
+
|
|
124
|
+
| Field | Description |
|
|
125
|
+
|-------|-------------|
|
|
126
|
+
| `name` | Human-readable name |
|
|
127
|
+
| `description` | Role description |
|
|
128
|
+
| `companyId` | Company scope (when company feature enabled) |
|
|
129
|
+
| `isActive` | Active status |
|
|
130
|
+
|
|
131
|
+
### Permission Types
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
enum IamPermissionType {
|
|
135
|
+
USER_ROLE = 'user_role', // User assigned to role
|
|
136
|
+
ROLE_ACTION = 'role_action', // Role has action
|
|
137
|
+
USER_ACTION = 'user_action', // User has action directly
|
|
138
|
+
COMPANY_ACTION = 'company_action', // Company action whitelist
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Permission Resolution Order
|
|
143
|
+
|
|
144
|
+
1. **Company-Action Whitelist** - Filter by company (if enabled)
|
|
145
|
+
2. **UserAction (DENY)** - Explicit denials take precedence
|
|
146
|
+
3. **UserAction (GRANT)** - Explicit grants
|
|
147
|
+
4. **UserRole -> RoleAction** - Inherited from roles
|
|
148
|
+
5. **Action Permission Logic** - Complex AND/OR rules
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Entities
|
|
153
|
+
|
|
154
|
+
### ActionBase
|
|
155
|
+
|
|
156
|
+
Core action fields in `action-base.entity.ts`:
|
|
157
|
+
|
|
158
|
+
| Column | Type | Description |
|
|
159
|
+
|--------|------|-------------|
|
|
160
|
+
| `readOnly` | boolean | System-protected action |
|
|
161
|
+
| `name` | varchar(255) | Action name |
|
|
162
|
+
| `code` | varchar(255) | Unique code |
|
|
163
|
+
| `description` | varchar(500) | Description |
|
|
164
|
+
| `actionType` | enum | BACKEND, FRONTEND, BOTH |
|
|
165
|
+
| `permissionLogic` | json | AND/OR rules |
|
|
166
|
+
| `parentId` | uuid | Parent action ID |
|
|
167
|
+
| `serial` | int | Display order |
|
|
168
|
+
| `isActive` | boolean | Active status |
|
|
169
|
+
| `metadata` | json | Additional data |
|
|
170
|
+
|
|
171
|
+
### RoleBase
|
|
172
|
+
|
|
173
|
+
Core role fields in `role-base.entity.ts`:
|
|
174
|
+
|
|
175
|
+
| Column | Type | Description |
|
|
176
|
+
|--------|------|-------------|
|
|
177
|
+
| `readOnly` | boolean | System-protected role |
|
|
178
|
+
| `name` | varchar(255) | Role name |
|
|
179
|
+
| `description` | varchar(500) | Description |
|
|
180
|
+
| `isActive` | boolean | Active status |
|
|
181
|
+
| `serial` | int | Display order |
|
|
182
|
+
| `metadata` | json | Additional data |
|
|
183
|
+
|
|
184
|
+
### RoleWithCompany
|
|
185
|
+
|
|
186
|
+
Extends RoleBase with:
|
|
187
|
+
- `companyId` (uuid) - Company scope
|
|
188
|
+
|
|
189
|
+
### PermissionBase
|
|
190
|
+
|
|
191
|
+
Core permission fields in `permission-base.entity.ts`:
|
|
192
|
+
|
|
193
|
+
| Column | Type | Description |
|
|
194
|
+
|--------|------|-------------|
|
|
195
|
+
| `permissionType` | enum | USER_ROLE, ROLE_ACTION, etc. |
|
|
196
|
+
| `sourceType` | enum | USER, ROLE, COMPANY |
|
|
197
|
+
| `sourceId` | uuid | Source entity ID |
|
|
198
|
+
| `targetType` | enum | ROLE, ACTION |
|
|
199
|
+
| `targetId` | uuid | Target entity ID |
|
|
200
|
+
| `userId` | uuid | User ID (nullable) |
|
|
201
|
+
| `validFrom` | timestamp | Permission valid from |
|
|
202
|
+
| `validUntil` | timestamp | Permission valid until |
|
|
203
|
+
| `reason` | text | Reason for permission |
|
|
204
|
+
| `metadata` | json | Additional data |
|
|
205
|
+
|
|
206
|
+
### UserIamPermissionWithCompany
|
|
207
|
+
|
|
208
|
+
Extends PermissionBase with:
|
|
209
|
+
- `companyId` (uuid) - Company scope
|
|
210
|
+
- `branchId` (uuid) - Branch scope
|
|
211
|
+
|
|
212
|
+
**Permission Granularity:**
|
|
213
|
+
|
|
214
|
+
| Level | companyId | branchId | Use Case |
|
|
215
|
+
|-------|-----------|----------|----------|
|
|
216
|
+
| Global | null | null | Super admin across all companies |
|
|
217
|
+
| Company-wide | set | null | Manager for ALL branches in company |
|
|
218
|
+
| Branch-specific | set | set | Manager for specific branch only |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Permission Modes
|
|
223
|
+
|
|
224
|
+
Set in `bootstrapAppConfig.permissionMode`:
|
|
225
|
+
|
|
226
|
+
### RBAC Mode (Role-Based)
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
User -> Role -> Action
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Only role-based permissions. Users get permissions through assigned roles.
|
|
233
|
+
|
|
234
|
+
### DIRECT Mode (Action-Based)
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
User -> Action
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Only direct permissions. Users get actions assigned directly.
|
|
241
|
+
|
|
242
|
+
### FULL Mode (Combined)
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
User -> Role -> Action
|
|
246
|
+
User -> Action
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Both RBAC and direct permissions. Default mode.
|
|
250
|
+
|
|
251
|
+
### PermissionModeHelper
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { PermissionModeHelper } from '@flusys/nestjs-iam/helpers';
|
|
255
|
+
|
|
256
|
+
const mode = PermissionModeHelper.fromString('RBAC');
|
|
257
|
+
// Returns: IAMPermissionMode.RBAC
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Permission Logic
|
|
263
|
+
|
|
264
|
+
Complex rules using AND/OR operators:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface LogicNode {
|
|
268
|
+
id: string;
|
|
269
|
+
type: 'group' | 'action';
|
|
270
|
+
operator?: 'AND' | 'OR'; // Only for type: 'group'
|
|
271
|
+
children?: LogicNode[]; // Only for type: 'group'
|
|
272
|
+
actionId?: string; // Only for type: 'action'
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Example: Nested Logic
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
const logic: LogicNode = {
|
|
280
|
+
id: 'root',
|
|
281
|
+
type: 'group',
|
|
282
|
+
operator: 'AND',
|
|
283
|
+
children: [
|
|
284
|
+
{ id: '1', type: 'action', actionId: 'employee-action-id' },
|
|
285
|
+
{
|
|
286
|
+
id: '2',
|
|
287
|
+
type: 'group',
|
|
288
|
+
operator: 'OR',
|
|
289
|
+
children: [
|
|
290
|
+
{ id: '2-1', type: 'action', actionId: 'department-head' },
|
|
291
|
+
{ id: '2-2', type: 'action', actionId: 'hr-clearance' },
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
};
|
|
296
|
+
// User must have employee AND (department-head OR hr-clearance)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Services
|
|
302
|
+
|
|
303
|
+
### ActionService
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { ActionService } from '@flusys/nestjs-iam';
|
|
307
|
+
|
|
308
|
+
// Create action
|
|
309
|
+
await actionService.insert({
|
|
310
|
+
name: 'View Users',
|
|
311
|
+
code: 'user.view',
|
|
312
|
+
actionType: ActionType.BACKEND,
|
|
313
|
+
parentId: parentAction.id,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Get hierarchical tree
|
|
317
|
+
const tree = await actionService.getActionTree(user, 'search', true, false);
|
|
318
|
+
|
|
319
|
+
// Get actions for permission (company-filtered)
|
|
320
|
+
const actions = await actionService.getActionsForPermission(user);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### RoleService
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { RoleService } from '@flusys/nestjs-iam';
|
|
327
|
+
|
|
328
|
+
// Create role
|
|
329
|
+
await roleService.insert({
|
|
330
|
+
name: 'Administrator',
|
|
331
|
+
description: 'Full system access',
|
|
332
|
+
companyId: 'company-id',
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### PermissionService
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import { PermissionService } from '@flusys/nestjs-iam';
|
|
340
|
+
|
|
341
|
+
// Assign roles to user
|
|
342
|
+
await permissionService.assignUserRoles({
|
|
343
|
+
userId: 'user-id',
|
|
344
|
+
companyId: 'company-id',
|
|
345
|
+
branchId: null, // null = ALL branches
|
|
346
|
+
items: [{ id: 'role-id', action: PermissionAction.ADD }],
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Assign actions directly
|
|
350
|
+
await permissionService.assignUserActions({
|
|
351
|
+
userId: 'user-id',
|
|
352
|
+
companyId: 'company-id',
|
|
353
|
+
branchId: 'branch-id',
|
|
354
|
+
items: [{ id: 'action-id', action: PermissionAction.ADD }],
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Assign actions to role
|
|
358
|
+
await permissionService.assignRoleActions({
|
|
359
|
+
roleId: 'role-id',
|
|
360
|
+
items: [{ id: 'action-id', action: PermissionAction.ADD }],
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Get user's permissions
|
|
364
|
+
const permissions = await permissionService.getMyPermissions(
|
|
365
|
+
userId, branchId, companyId, parentCodes
|
|
366
|
+
);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### PermissionCacheService
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { PermissionCacheService } from '@flusys/nestjs-iam';
|
|
373
|
+
|
|
374
|
+
// Set permissions
|
|
375
|
+
await cacheService.setPermissions(
|
|
376
|
+
{ userId, companyId, branchId, enableCompanyFeature: true },
|
|
377
|
+
['users.read', 'users.write']
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
// Invalidate user cache
|
|
381
|
+
await cacheService.invalidateUser('user-id', 'company-id', ['branch-id']);
|
|
382
|
+
|
|
383
|
+
// Invalidate role members
|
|
384
|
+
await cacheService.invalidateRole('role-id', userIds, 'company-id');
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Cache Key Format:**
|
|
388
|
+
```
|
|
389
|
+
permissions:user:{userId} // Without company
|
|
390
|
+
permissions:company:{companyId}:branch:{branchId}:user:{userId} // With company
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## REST API Endpoints
|
|
396
|
+
|
|
397
|
+
### Actions API
|
|
398
|
+
|
|
399
|
+
| Endpoint | Method | Description |
|
|
400
|
+
|----------|--------|-------------|
|
|
401
|
+
| `/iam/actions/insert` | POST | Create action |
|
|
402
|
+
| `/iam/actions/get-all` | POST | List actions (paginated) |
|
|
403
|
+
| `/iam/actions/get/:id` | GET | Get action by ID |
|
|
404
|
+
| `/iam/actions/tree` | POST | Get hierarchical tree (ALL actions) |
|
|
405
|
+
| `/iam/actions/tree-for-permission` | GET | Get company-filtered actions |
|
|
406
|
+
| `/iam/actions/update` | POST | Update action |
|
|
407
|
+
| `/iam/actions/delete` | POST | Delete action |
|
|
408
|
+
|
|
409
|
+
### Roles API
|
|
410
|
+
|
|
411
|
+
| Endpoint | Method | Description |
|
|
412
|
+
|----------|--------|-------------|
|
|
413
|
+
| `/iam/roles/insert` | POST | Create role |
|
|
414
|
+
| `/iam/roles/get-all` | POST | List roles (paginated) |
|
|
415
|
+
| `/iam/roles/get/:id` | GET | Get role by ID |
|
|
416
|
+
| `/iam/roles/update` | POST | Update role |
|
|
417
|
+
| `/iam/roles/delete` | POST | Delete role |
|
|
418
|
+
|
|
419
|
+
### Permissions API
|
|
420
|
+
|
|
421
|
+
| Endpoint | Method | Description |
|
|
422
|
+
|----------|--------|-------------|
|
|
423
|
+
| `/iam/permissions/role-actions/assign` | POST | Assign actions to role |
|
|
424
|
+
| `/iam/permissions/role-actions/get` | POST | Get role actions |
|
|
425
|
+
| `/iam/permissions/user-roles/assign` | POST | Assign roles to user |
|
|
426
|
+
| `/iam/permissions/user-roles/get` | POST | Get user roles |
|
|
427
|
+
| `/iam/permissions/user-actions/assign` | POST | Assign actions to user |
|
|
428
|
+
| `/iam/permissions/user-actions/get` | POST | Get user actions |
|
|
429
|
+
| `/iam/permissions/company-actions/assign` | POST | Company action whitelist |
|
|
430
|
+
| `/iam/permissions/company-actions/get` | POST | Get company actions |
|
|
431
|
+
| `/iam/permissions/my-permissions` | POST | Get current user's permissions |
|
|
432
|
+
|
|
433
|
+
**My Permissions Response:**
|
|
434
|
+
```typescript
|
|
435
|
+
{
|
|
436
|
+
frontendActions: FrontendActionDto[],
|
|
437
|
+
cachedEndpoints: number
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Multi-Tenant Support
|
|
444
|
+
|
|
445
|
+
### Company Feature Toggle
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
// config/app.config.ts
|
|
449
|
+
export const bootstrapAppConfig: IBootstrapAppConfig = {
|
|
450
|
+
databaseMode: 'single',
|
|
451
|
+
enableCompanyFeature: true, // or false
|
|
452
|
+
};
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### When `enableCompanyFeature: true`
|
|
456
|
+
|
|
457
|
+
- `companyId` and `branchId` fields available in DTOs
|
|
458
|
+
- Company-Action Permissions controller registered
|
|
459
|
+
- Three-level permission granularity (Global, Company-wide, Branch-specific)
|
|
460
|
+
- Uses `UserIamPermissionWithCompany` and `RoleWithCompany` entities
|
|
461
|
+
|
|
462
|
+
### When `enableCompanyFeature: false`
|
|
463
|
+
|
|
464
|
+
- Company endpoints NOT available (404)
|
|
465
|
+
- `companyId`/`branchId` fields visible in Swagger but ignored
|
|
466
|
+
- All permissions are global
|
|
467
|
+
- Uses `UserIamPermission` and `Role` entities
|
|
468
|
+
|
|
469
|
+
### Permission Merging
|
|
470
|
+
|
|
471
|
+
When user logs in, `getMyPermissions` merges:
|
|
472
|
+
1. Company-wide roles (branchId=null) + Branch-specific roles
|
|
473
|
+
2. Actions from all merged roles
|
|
474
|
+
3. Company-wide user actions + Branch-specific user actions
|
|
475
|
+
|
|
476
|
+
**Result:** Complete permission set without duplicates.
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Permission Guard Integration
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
import { PermissionGuard } from '@flusys/nestjs-shared/guards';
|
|
484
|
+
import { RequirePermission, RequireAnyPermission } from '@flusys/nestjs-shared/decorators';
|
|
485
|
+
|
|
486
|
+
@Controller('users')
|
|
487
|
+
export class UserController {
|
|
488
|
+
@RequirePermission('user.view')
|
|
489
|
+
@Get()
|
|
490
|
+
getUsers() {}
|
|
491
|
+
|
|
492
|
+
@RequireAnyPermission('user.create', 'admin')
|
|
493
|
+
@Post()
|
|
494
|
+
createUser() {}
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Best Practices
|
|
501
|
+
|
|
502
|
+
### 1. Action Code Naming
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// Hierarchical naming for backend
|
|
506
|
+
'user.view', 'user.create', 'user.delete'
|
|
507
|
+
|
|
508
|
+
// UPPERCASE for frontend actions
|
|
509
|
+
'MENU_USERS', 'MENU_REPORTS', 'FEATURE_EXPORT'
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### 2. Company-wide vs Branch-specific
|
|
513
|
+
|
|
514
|
+
```typescript
|
|
515
|
+
// Company-wide for managers across ALL branches
|
|
516
|
+
{ companyId: 'company-a', branchId: null }
|
|
517
|
+
|
|
518
|
+
// Branch-specific for location-bound staff
|
|
519
|
+
{ companyId: 'company-a', branchId: 'branch-x' }
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### 3. Use Roles for Common Patterns
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
// Create roles for common permission sets
|
|
526
|
+
const roles = [
|
|
527
|
+
{ name: 'Viewer', actions: ['*.view'] },
|
|
528
|
+
{ name: 'Editor', actions: ['*.view', '*.create', '*.update'] },
|
|
529
|
+
{ name: 'Admin', actions: ['*'] },
|
|
530
|
+
];
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### 4. Use Direct Actions Sparingly
|
|
534
|
+
|
|
535
|
+
Direct actions should be exceptions and branch-specific overrides, not the primary permission mechanism.
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## API Reference
|
|
540
|
+
|
|
541
|
+
### Module
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
import { IAMModule, IAMPermissionMode } from '@flusys/nestjs-iam';
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Services
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
import {
|
|
551
|
+
ActionService,
|
|
552
|
+
RoleService,
|
|
553
|
+
PermissionService,
|
|
554
|
+
PermissionCacheService,
|
|
555
|
+
IAMConfigService,
|
|
556
|
+
IAMDataSourceProvider,
|
|
557
|
+
} from '@flusys/nestjs-iam';
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Entities
|
|
561
|
+
|
|
562
|
+
```typescript
|
|
563
|
+
import {
|
|
564
|
+
Action,
|
|
565
|
+
Role,
|
|
566
|
+
RoleWithCompany,
|
|
567
|
+
UserIamPermission,
|
|
568
|
+
UserIamPermissionWithCompany,
|
|
569
|
+
getIAMEntitiesByConfig,
|
|
570
|
+
} from '@flusys/nestjs-iam/entities';
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### DTOs
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
import {
|
|
577
|
+
CreateActionDto,
|
|
578
|
+
UpdateActionDto,
|
|
579
|
+
CreateRoleDto,
|
|
580
|
+
UpdateRoleDto,
|
|
581
|
+
AssignUserActionsDto,
|
|
582
|
+
AssignUserRolesDto,
|
|
583
|
+
AssignRoleActionsDto,
|
|
584
|
+
AssignCompanyActionsDto,
|
|
585
|
+
MyPermissionsResponseDto,
|
|
586
|
+
FrontendActionDto,
|
|
587
|
+
} from '@flusys/nestjs-iam/dtos';
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Enums
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
import {
|
|
594
|
+
ActionType,
|
|
595
|
+
IAMPermissionMode,
|
|
596
|
+
IamPermissionType,
|
|
597
|
+
IamEntityType,
|
|
598
|
+
} from '@flusys/nestjs-iam/enums';
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Helpers
|
|
602
|
+
|
|
603
|
+
```typescript
|
|
604
|
+
import {
|
|
605
|
+
PermissionEvaluatorHelper,
|
|
606
|
+
PermissionModeHelper,
|
|
607
|
+
} from '@flusys/nestjs-iam/helpers';
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## Package Architecture
|
|
613
|
+
|
|
614
|
+
```
|
|
615
|
+
nestjs-iam/src/
|
|
616
|
+
├── modules/
|
|
617
|
+
│ └── iam.module.ts # Main module with dynamic config
|
|
618
|
+
├── entities/
|
|
619
|
+
│ ├── action-base.entity.ts # Action base fields
|
|
620
|
+
│ ├── action.entity.ts # Action entity
|
|
621
|
+
│ ├── role-base.entity.ts # Role base fields
|
|
622
|
+
│ ├── role.entity.ts # Role (no company)
|
|
623
|
+
│ ├── role-with-company.entity.ts
|
|
624
|
+
│ ├── permission-base.entity.ts # Permission base fields
|
|
625
|
+
│ ├── user-iam-permission.entity.ts
|
|
626
|
+
│ └── permission-with-company.entity.ts
|
|
627
|
+
├── services/
|
|
628
|
+
│ ├── action.service.ts # Action CRUD
|
|
629
|
+
│ ├── role.service.ts # Role CRUD
|
|
630
|
+
│ ├── permission.service.ts # Permission management
|
|
631
|
+
│ ├── permission-cache.service.ts # Cache management
|
|
632
|
+
│ ├── iam-config.service.ts # Configuration
|
|
633
|
+
│ └── iam-datasource.provider.ts # DataSource provider
|
|
634
|
+
├── controllers/
|
|
635
|
+
│ ├── action.controller.ts
|
|
636
|
+
│ ├── role.controller.ts
|
|
637
|
+
│ ├── my-permission.controller.ts
|
|
638
|
+
│ ├── role-permission.controller.ts
|
|
639
|
+
│ ├── user-action-permission.controller.ts
|
|
640
|
+
│ └── company-action-permission.controller.ts
|
|
641
|
+
├── helpers/
|
|
642
|
+
│ ├── permission-evaluator.helper.ts
|
|
643
|
+
│ └── permission-mode.helper.ts
|
|
644
|
+
├── dtos/
|
|
645
|
+
│ ├── action.dto.ts
|
|
646
|
+
│ ├── role.dto.ts
|
|
647
|
+
│ └── permission.dto.ts
|
|
648
|
+
├── interfaces/
|
|
649
|
+
│ ├── action.interface.ts
|
|
650
|
+
│ ├── role.interface.ts
|
|
651
|
+
│ └── iam-module-options.interface.ts
|
|
652
|
+
├── enums/
|
|
653
|
+
│ ├── action-type.enum.ts
|
|
654
|
+
│ └── permission-type.enum.ts
|
|
655
|
+
└── types/
|
|
656
|
+
└── logic-node.type.ts
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
**Last Updated:** 2026-02-09 | **Version:** 4.4.1
|
|
662
|
+
|
|
663
|
+
**Recent Changes (2026-02-09):**
|
|
664
|
+
- Added explicit `@Inject()` decorators to all services for esbuild bundling compatibility
|
|
665
|
+
- All services use REQUEST scope with lazy repository initialization via DataSource Provider pattern
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "IAM_MODULE_OPTIONS", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return IAM_MODULE_OPTIONS;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const IAM_MODULE_OPTIONS = 'IAM_MODULE_OPTIONS';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./iam.constants"), exports);
|
|
6
|
+
function _export_star(from, to) {
|
|
7
|
+
Object.keys(from).forEach(function(k) {
|
|
8
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
9
|
+
Object.defineProperty(to, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return from[k];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return from;
|
|
18
|
+
}
|