@flusys/nestjs-iam 1.0.0-beta → 1.0.0
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 +284 -113
- package/cjs/controllers/action.controller.js +45 -2
- package/cjs/controllers/company-action-permission.controller.js +16 -10
- package/cjs/controllers/my-permission.controller.js +7 -3
- package/cjs/controllers/role-permission.controller.js +35 -17
- package/cjs/controllers/role.controller.js +46 -3
- package/cjs/controllers/user-action-permission.controller.js +26 -11
- package/cjs/dtos/action.dto.js +0 -27
- package/cjs/dtos/permission.dto.js +117 -27
- package/cjs/dtos/role.dto.js +0 -27
- package/cjs/entities/action-base.entity.js +3 -3
- package/cjs/entities/permission-base.entity.js +6 -18
- package/cjs/helpers/company-access.helper.js +19 -0
- package/cjs/helpers/index.js +1 -1
- package/cjs/interfaces/iam-module-options.interface.js +0 -14
- package/cjs/interfaces/index.js +0 -1
- package/cjs/modules/iam.module.js +50 -102
- package/cjs/services/action.service.js +30 -41
- package/cjs/services/iam-config.service.js +2 -5
- package/cjs/services/{iam-datasource.provider.js → iam-datasource.service.js} +33 -36
- package/cjs/services/index.js +1 -1
- package/cjs/services/permission-cache.service.js +31 -61
- package/cjs/services/permission.service.js +160 -188
- package/cjs/services/role.service.js +8 -8
- package/cjs/types/logic-node.type.js +0 -24
- package/controllers/company-action-permission.controller.d.ts +3 -3
- package/controllers/my-permission.controller.d.ts +2 -2
- package/controllers/role-permission.controller.d.ts +7 -5
- package/controllers/user-action-permission.controller.d.ts +6 -4
- package/dtos/action.dto.d.ts +0 -7
- package/dtos/permission.dto.d.ts +4 -0
- package/dtos/role.dto.d.ts +0 -7
- package/entities/permission-base.entity.d.ts +3 -7
- package/fesm/controllers/action.controller.js +47 -4
- package/fesm/controllers/company-action-permission.controller.js +18 -12
- package/fesm/controllers/index.js +1 -1
- package/fesm/controllers/my-permission.controller.js +7 -3
- package/fesm/controllers/role-permission.controller.js +37 -19
- package/fesm/controllers/role.controller.js +45 -2
- package/fesm/controllers/user-action-permission.controller.js +28 -13
- package/fesm/dtos/action.dto.js +0 -24
- package/fesm/dtos/permission.dto.js +117 -29
- package/fesm/dtos/role.dto.js +0 -24
- package/fesm/entities/action-base.entity.js +3 -3
- package/fesm/entities/permission-base.entity.js +6 -18
- package/fesm/helpers/company-access.helper.js +14 -0
- package/fesm/helpers/index.js +1 -1
- package/fesm/interfaces/iam-module-options.interface.js +3 -1
- package/fesm/interfaces/index.js +0 -1
- package/fesm/modules/iam.module.js +52 -104
- package/fesm/services/action.service.js +32 -43
- package/fesm/services/iam-config.service.js +2 -5
- package/fesm/services/{iam-datasource.provider.js → iam-datasource.service.js} +31 -34
- package/fesm/services/index.js +1 -1
- package/fesm/services/permission-cache.service.js +31 -61
- package/fesm/services/permission.service.js +161 -189
- package/fesm/services/role.service.js +8 -8
- package/fesm/types/logic-node.type.js +1 -10
- package/helpers/company-access.helper.d.ts +3 -0
- package/helpers/index.d.ts +1 -1
- package/interfaces/iam-module-options.interface.d.ts +9 -1
- package/interfaces/index.d.ts +0 -1
- package/modules/iam.module.d.ts +2 -2
- package/package.json +3 -3
- package/services/action.service.d.ts +6 -4
- package/services/iam-config.service.d.ts +2 -2
- package/services/{iam-datasource.provider.d.ts → iam-datasource.service.d.ts} +4 -5
- package/services/index.d.ts +1 -1
- package/services/permission-cache.service.d.ts +4 -6
- package/services/permission.service.d.ts +8 -4
- package/services/role.service.d.ts +3 -3
- package/types/logic-node.type.d.ts +0 -8
- package/cjs/helpers/permission-evaluator.helper.js +0 -175
- package/cjs/interfaces/iam-module-async-options.interface.js +0 -4
- package/fesm/helpers/permission-evaluator.helper.js +0 -165
- package/fesm/interfaces/iam-module-async-options.interface.js +0 -3
- package/helpers/permission-evaluator.helper.d.ts +0 -26
- package/interfaces/iam-module-async-options.interface.d.ts +0 -11
package/README.md
CHANGED
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
- [Overview](#overview)
|
|
9
9
|
- [Installation](#installation)
|
|
10
10
|
- [Module Configuration](#module-configuration)
|
|
11
|
+
- [Constants](#constants)
|
|
11
12
|
- [Core Concepts](#core-concepts)
|
|
12
13
|
- [Entities](#entities)
|
|
13
14
|
- [Permission Modes](#permission-modes)
|
|
14
15
|
- [Permission Logic](#permission-logic)
|
|
15
16
|
- [Services](#services)
|
|
17
|
+
- [Helpers](#helpers)
|
|
16
18
|
- [REST API Endpoints](#rest-api-endpoints)
|
|
17
19
|
- [Multi-Tenant Support](#multi-tenant-support)
|
|
18
20
|
- [Permission Guard Integration](#permission-guard-integration)
|
|
@@ -28,11 +30,11 @@
|
|
|
28
30
|
|
|
29
31
|
- **Hierarchical Actions** - Organize permissions in tree structures
|
|
30
32
|
- **Action Types** - BACKEND (cached for guards), FRONTEND (returned to UI), BOTH
|
|
31
|
-
- **RBAC** - Role-Based Access Control
|
|
32
|
-
- **
|
|
33
|
-
- **Permission
|
|
33
|
+
- **RBAC** - Role-Based Access Control with validation
|
|
34
|
+
- **DIRECT** - Direct user-to-action assignments with validation
|
|
35
|
+
- **Permission Mode Validation** - Throws `BadRequestException` when using wrong mode
|
|
34
36
|
- **Company/Branch Scoping** - Multi-tenant permissions with three-level granularity
|
|
35
|
-
- **
|
|
37
|
+
- **Tenant-Aware Caching** - Automatic cache invalidation with multi-tenant support
|
|
36
38
|
|
|
37
39
|
### Package Hierarchy
|
|
38
40
|
|
|
@@ -89,6 +91,34 @@ import { IAMModule } from '@flusys/nestjs-iam';
|
|
|
89
91
|
export class AppModule {}
|
|
90
92
|
```
|
|
91
93
|
|
|
94
|
+
### Async Configuration
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
IAMModule.forRootAsync({
|
|
98
|
+
global: true,
|
|
99
|
+
includeController: true,
|
|
100
|
+
bootstrapAppConfig: {
|
|
101
|
+
databaseMode: 'single',
|
|
102
|
+
enableCompanyFeature: true,
|
|
103
|
+
permissionMode: 'RBAC',
|
|
104
|
+
},
|
|
105
|
+
imports: [ConfigModule],
|
|
106
|
+
useFactory: (config: ConfigService) => ({
|
|
107
|
+
// IAM-specific options from config
|
|
108
|
+
}),
|
|
109
|
+
inject: [ConfigService],
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Constants
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Injection Token
|
|
119
|
+
export const IAM_MODULE_OPTIONS = 'IAM_MODULE_OPTIONS';
|
|
120
|
+
```
|
|
121
|
+
|
|
92
122
|
---
|
|
93
123
|
|
|
94
124
|
## Core Concepts
|
|
@@ -146,10 +176,75 @@ enum IamPermissionType {
|
|
|
146
176
|
4. **UserRole -> RoleAction** - Inherited from roles
|
|
147
177
|
5. **Action Permission Logic** - Complex AND/OR rules
|
|
148
178
|
|
|
179
|
+
### Permission Cascade Deletion
|
|
180
|
+
|
|
181
|
+
When removing company actions via `removeCompanyActionsWithCascade()`, the `PermissionService` performs cascade deletion:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Company Action Removed
|
|
185
|
+
↓
|
|
186
|
+
1. Delete COMPANY_ACTION permissions
|
|
187
|
+
↓
|
|
188
|
+
2. Find all roles in the company
|
|
189
|
+
↓
|
|
190
|
+
3. Delete ROLE_ACTION permissions for those actions
|
|
191
|
+
↓
|
|
192
|
+
4. Find all users in the company
|
|
193
|
+
↓
|
|
194
|
+
5. Delete USER_ACTION permissions for those actions
|
|
195
|
+
↓
|
|
196
|
+
6. Invalidate permission cache for affected users
|
|
197
|
+
```
|
|
198
|
+
|
|
149
199
|
---
|
|
150
200
|
|
|
151
201
|
## Entities
|
|
152
202
|
|
|
203
|
+
### Entity Groups
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Core entities (no company feature)
|
|
207
|
+
export const IAMCoreEntities = [Action, Role, UserIamPermission];
|
|
208
|
+
|
|
209
|
+
// Company-specific entities
|
|
210
|
+
export const IAMCompanyEntities = [RoleWithCompany, UserIamPermissionWithCompany];
|
|
211
|
+
|
|
212
|
+
// All entities
|
|
213
|
+
export const IAMAllEntities = [
|
|
214
|
+
Action,
|
|
215
|
+
Role,
|
|
216
|
+
RoleWithCompany,
|
|
217
|
+
UserIamPermission,
|
|
218
|
+
UserIamPermissionWithCompany,
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
// Helper function
|
|
222
|
+
export function getIAMEntitiesByConfig(
|
|
223
|
+
enableCompanyFeature: boolean,
|
|
224
|
+
permissionMode: 'FULL' | 'RBAC' | 'DIRECT' = 'FULL',
|
|
225
|
+
): any[] {
|
|
226
|
+
const entities: any[] = [Action];
|
|
227
|
+
|
|
228
|
+
// Permission entity - always included
|
|
229
|
+
if (enableCompanyFeature) {
|
|
230
|
+
entities.push(UserIamPermissionWithCompany);
|
|
231
|
+
} else {
|
|
232
|
+
entities.push(UserIamPermission);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Role entity - Only for RBAC or FULL mode (not DIRECT)
|
|
236
|
+
if (permissionMode === 'RBAC' || permissionMode === 'FULL') {
|
|
237
|
+
if (enableCompanyFeature) {
|
|
238
|
+
entities.push(RoleWithCompany);
|
|
239
|
+
} else {
|
|
240
|
+
entities.push(Role);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return entities;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
153
248
|
### ActionBase
|
|
154
249
|
|
|
155
250
|
Core action fields in `action-base.entity.ts`:
|
|
@@ -222,6 +317,16 @@ Extends PermissionBase with:
|
|
|
222
317
|
|
|
223
318
|
Set in `bootstrapAppConfig.permissionMode`:
|
|
224
319
|
|
|
320
|
+
### Permission Mode Enum
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
enum IAMPermissionMode {
|
|
324
|
+
RBAC = 1, // Role-Based: Action + RoleAction + UserRole
|
|
325
|
+
DIRECT = 2, // Direct User Permissions: Action + UserAction
|
|
326
|
+
FULL = 3, // Both RBAC + Direct permissions
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
225
330
|
### RBAC Mode (Role-Based)
|
|
226
331
|
|
|
227
332
|
```
|
|
@@ -230,6 +335,8 @@ User -> Role -> Action
|
|
|
230
335
|
|
|
231
336
|
Only role-based permissions. Users get permissions through assigned roles.
|
|
232
337
|
|
|
338
|
+
**Note:** Calling `assignUserActions()` in RBAC mode throws `BadRequestException`.
|
|
339
|
+
|
|
233
340
|
### DIRECT Mode (Action-Based)
|
|
234
341
|
|
|
235
342
|
```
|
|
@@ -238,6 +345,8 @@ User -> Action
|
|
|
238
345
|
|
|
239
346
|
Only direct permissions. Users get actions assigned directly.
|
|
240
347
|
|
|
348
|
+
**Note:** Calling `assignUserRoles()` or `assignRoleActions()` in DIRECT mode throws `BadRequestException`.
|
|
349
|
+
|
|
241
350
|
### FULL Mode (Combined)
|
|
242
351
|
|
|
243
352
|
```
|
|
@@ -245,34 +354,25 @@ User -> Role -> Action
|
|
|
245
354
|
User -> Action
|
|
246
355
|
```
|
|
247
356
|
|
|
248
|
-
Both RBAC and direct permissions. Default mode.
|
|
249
|
-
|
|
250
|
-
### PermissionModeHelper
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
import { PermissionModeHelper } from '@flusys/nestjs-iam/helpers';
|
|
254
|
-
|
|
255
|
-
const mode = PermissionModeHelper.fromString('RBAC');
|
|
256
|
-
// Returns: IAMPermissionMode.RBAC
|
|
257
|
-
```
|
|
357
|
+
Both RBAC and direct permissions. Default mode. All assignment methods available.
|
|
258
358
|
|
|
259
359
|
---
|
|
260
360
|
|
|
261
361
|
## Permission Logic
|
|
262
362
|
|
|
263
|
-
Complex rules using AND/OR operators:
|
|
363
|
+
Complex permission rules using AND/OR operators stored in `permissionLogic` field:
|
|
264
364
|
|
|
265
365
|
```typescript
|
|
266
366
|
interface LogicNode {
|
|
267
367
|
id: string;
|
|
268
368
|
type: 'group' | 'action';
|
|
269
|
-
operator?: 'AND' | 'OR';
|
|
270
|
-
children?: LogicNode[];
|
|
271
|
-
actionId?: string;
|
|
369
|
+
operator?: 'AND' | 'OR';
|
|
370
|
+
children?: LogicNode[];
|
|
371
|
+
actionId?: string;
|
|
272
372
|
}
|
|
273
373
|
```
|
|
274
374
|
|
|
275
|
-
|
|
375
|
+
**Example:** User must have "employee" AND ("department-head" OR "hr-clearance")
|
|
276
376
|
|
|
277
377
|
```typescript
|
|
278
378
|
const logic: LogicNode = {
|
|
@@ -292,13 +392,21 @@ const logic: LogicNode = {
|
|
|
292
392
|
},
|
|
293
393
|
],
|
|
294
394
|
};
|
|
295
|
-
// User must have employee AND (department-head OR hr-clearance)
|
|
296
395
|
```
|
|
297
396
|
|
|
298
397
|
---
|
|
299
398
|
|
|
300
399
|
## Services
|
|
301
400
|
|
|
401
|
+
| Service | Scope | Description |
|
|
402
|
+
|---------|-------|-------------|
|
|
403
|
+
| `ActionService` | REQUEST | Action CRUD, tree queries |
|
|
404
|
+
| `RoleService` | REQUEST | Role CRUD (RBAC/FULL mode only) |
|
|
405
|
+
| `PermissionService` | REQUEST | Permission assignments, my-permissions |
|
|
406
|
+
| `PermissionCacheService` | REQUEST | Cache management |
|
|
407
|
+
| `IAMConfigService` | SINGLETON | IAM configuration access |
|
|
408
|
+
| `IAMDataSourceService` | REQUEST | DataSource provider for multi-tenant |
|
|
409
|
+
|
|
302
410
|
### ActionService
|
|
303
411
|
|
|
304
412
|
```typescript
|
|
@@ -335,17 +443,17 @@ await roleService.insert({
|
|
|
335
443
|
### PermissionService
|
|
336
444
|
|
|
337
445
|
```typescript
|
|
338
|
-
import { PermissionService } from '@flusys/nestjs-iam';
|
|
446
|
+
import { PermissionService, PermissionAction } from '@flusys/nestjs-iam';
|
|
339
447
|
|
|
340
|
-
// Assign roles to user
|
|
448
|
+
// Assign roles to user (RBAC/FULL mode only)
|
|
341
449
|
await permissionService.assignUserRoles({
|
|
342
450
|
userId: 'user-id',
|
|
343
451
|
companyId: 'company-id',
|
|
344
|
-
branchId: null, // null =
|
|
452
|
+
branchId: null, // null = company-wide
|
|
345
453
|
items: [{ id: 'role-id', action: PermissionAction.ADD }],
|
|
346
454
|
});
|
|
347
455
|
|
|
348
|
-
// Assign actions directly
|
|
456
|
+
// Assign actions directly (DIRECT/FULL mode only)
|
|
349
457
|
await permissionService.assignUserActions({
|
|
350
458
|
userId: 'user-id',
|
|
351
459
|
companyId: 'company-id',
|
|
@@ -353,7 +461,7 @@ await permissionService.assignUserActions({
|
|
|
353
461
|
items: [{ id: 'action-id', action: PermissionAction.ADD }],
|
|
354
462
|
});
|
|
355
463
|
|
|
356
|
-
// Assign actions to role
|
|
464
|
+
// Assign actions to role (RBAC/FULL mode only)
|
|
357
465
|
await permissionService.assignRoleActions({
|
|
358
466
|
roleId: 'role-id',
|
|
359
467
|
items: [{ id: 'action-id', action: PermissionAction.ADD }],
|
|
@@ -381,12 +489,64 @@ await cacheService.invalidateUser('user-id', 'company-id', ['branch-id']);
|
|
|
381
489
|
|
|
382
490
|
// Invalidate role members
|
|
383
491
|
await cacheService.invalidateRole('role-id', userIds, 'company-id');
|
|
492
|
+
|
|
493
|
+
// Tenant-aware action code cache
|
|
494
|
+
await cacheService.setActionCodeMap(codeToIdMap, tenantId);
|
|
495
|
+
await cacheService.getActionIdsByCodes(['user.view'], tenantId);
|
|
496
|
+
await cacheService.invalidateActionCodeCache(tenantId);
|
|
384
497
|
```
|
|
385
498
|
|
|
386
|
-
**Cache Key
|
|
499
|
+
**Cache Key Formats:**
|
|
387
500
|
```
|
|
388
501
|
permissions:user:{userId} // Without company
|
|
389
502
|
permissions:company:{companyId}:branch:{branchId}:user:{userId} // With company
|
|
503
|
+
action-codes:map // Single tenant
|
|
504
|
+
action-codes:tenant:{tenantId}:map // Multi-tenant
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Helpers
|
|
510
|
+
|
|
511
|
+
### PermissionModeHelper
|
|
512
|
+
|
|
513
|
+
Centralizes conversion from string to enum to prevent duplication:
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
import { PermissionModeHelper } from '@flusys/nestjs-iam';
|
|
517
|
+
|
|
518
|
+
// Convert string to enum
|
|
519
|
+
const mode = PermissionModeHelper.fromString('RBAC');
|
|
520
|
+
// Returns: IAMPermissionMode.RBAC
|
|
521
|
+
|
|
522
|
+
const mode = PermissionModeHelper.fromString(undefined);
|
|
523
|
+
// Returns: IAMPermissionMode.FULL (default)
|
|
524
|
+
|
|
525
|
+
// Convert enum to string
|
|
526
|
+
const str = PermissionModeHelper.toString(IAMPermissionMode.RBAC);
|
|
527
|
+
// Returns: 'RBAC'
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
**Used by:**
|
|
531
|
+
- `iam.module.ts` (forRoot, forRootAsync)
|
|
532
|
+
- `iam-config.service.ts` (getPermissionMode)
|
|
533
|
+
- `main.ts` (Swagger setup)
|
|
534
|
+
|
|
535
|
+
### validateCompanyAccess
|
|
536
|
+
|
|
537
|
+
Validates user access to a company for permission operations:
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
import { validateCompanyAccess } from '@flusys/nestjs-iam';
|
|
541
|
+
|
|
542
|
+
// In a controller or service
|
|
543
|
+
validateCompanyAccess(
|
|
544
|
+
iamConfig,
|
|
545
|
+
dto.companyId,
|
|
546
|
+
user,
|
|
547
|
+
'You do not have access to this company',
|
|
548
|
+
);
|
|
549
|
+
// Throws ForbiddenException if user.companyId !== dto.companyId
|
|
390
550
|
```
|
|
391
551
|
|
|
392
552
|
---
|
|
@@ -405,7 +565,7 @@ permissions:company:{companyId}:branch:{branchId}:user:{userId} // With company
|
|
|
405
565
|
| `/iam/actions/update` | POST | Update action |
|
|
406
566
|
| `/iam/actions/delete` | POST | Delete action |
|
|
407
567
|
|
|
408
|
-
### Roles API
|
|
568
|
+
### Roles API (RBAC/FULL mode only)
|
|
409
569
|
|
|
410
570
|
| Endpoint | Method | Description |
|
|
411
571
|
|----------|--------|-------------|
|
|
@@ -417,25 +577,25 @@ permissions:company:{companyId}:branch:{branchId}:user:{userId} // With company
|
|
|
417
577
|
|
|
418
578
|
### Permissions API
|
|
419
579
|
|
|
420
|
-
| Endpoint | Method | Description |
|
|
421
|
-
|
|
422
|
-
| `/iam/permissions/role-actions/assign` | POST | Assign actions to role |
|
|
423
|
-
| `/iam/permissions/role-actions/get` | POST | Get role actions |
|
|
424
|
-
| `/iam/permissions/user-roles/assign` | POST | Assign roles to user |
|
|
425
|
-
| `/iam/permissions/user-roles/get` | POST | Get user roles |
|
|
426
|
-
| `/iam/permissions/user-actions/assign` | POST | Assign actions to user |
|
|
427
|
-
| `/iam/permissions/user-actions/get` | POST | Get user actions |
|
|
428
|
-
| `/iam/permissions/company-actions/assign` | POST | Company action whitelist |
|
|
429
|
-
| `/iam/permissions/company-actions/get` | POST | Get company actions |
|
|
430
|
-
| `/iam/permissions/my-permissions` | POST | Get current user's permissions |
|
|
431
|
-
|
|
432
|
-
**
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
580
|
+
| Endpoint | Method | Modes | Description |
|
|
581
|
+
|----------|--------|-------|-------------|
|
|
582
|
+
| `/iam/permissions/role-actions/assign` | POST | RBAC, FULL | Assign actions to role |
|
|
583
|
+
| `/iam/permissions/role-actions/get` | POST | RBAC, FULL | Get role actions |
|
|
584
|
+
| `/iam/permissions/user-roles/assign` | POST | RBAC, FULL | Assign roles to user |
|
|
585
|
+
| `/iam/permissions/user-roles/get` | POST | RBAC, FULL | Get user roles |
|
|
586
|
+
| `/iam/permissions/user-actions/assign` | POST | DIRECT, FULL | Assign actions to user |
|
|
587
|
+
| `/iam/permissions/user-actions/get` | POST | DIRECT, FULL | Get user actions |
|
|
588
|
+
| `/iam/permissions/company-actions/assign` | POST | All (company enabled) | Company action whitelist |
|
|
589
|
+
| `/iam/permissions/company-actions/get` | POST | All (company enabled) | Get company actions |
|
|
590
|
+
| `/iam/permissions/my-permissions` | POST | All | Get current user's permissions |
|
|
591
|
+
|
|
592
|
+
**Controller Registration by Mode:**
|
|
593
|
+
|
|
594
|
+
| Mode | Controllers |
|
|
595
|
+
|------|-------------|
|
|
596
|
+
| DIRECT | ActionController, MyPermissionController, UserActionPermissionController |
|
|
597
|
+
| RBAC | ActionController, MyPermissionController, RoleController, RolePermissionController |
|
|
598
|
+
| FULL | All controllers |
|
|
439
599
|
|
|
440
600
|
---
|
|
441
601
|
|
|
@@ -446,8 +606,9 @@ permissions:company:{companyId}:branch:{branchId}:user:{userId} // With company
|
|
|
446
606
|
```typescript
|
|
447
607
|
// config/app.config.ts
|
|
448
608
|
export const bootstrapAppConfig: IBootstrapAppConfig = {
|
|
449
|
-
databaseMode: 'single',
|
|
450
|
-
enableCompanyFeature: true,
|
|
609
|
+
databaseMode: 'single', // or 'multi-tenant'
|
|
610
|
+
enableCompanyFeature: true,
|
|
611
|
+
permissionMode: 'FULL',
|
|
451
612
|
};
|
|
452
613
|
```
|
|
453
614
|
|
|
@@ -465,14 +626,28 @@ export const bootstrapAppConfig: IBootstrapAppConfig = {
|
|
|
465
626
|
- All permissions are global
|
|
466
627
|
- Uses `UserIamPermission` and `Role` entities
|
|
467
628
|
|
|
629
|
+
### Multi-Tenant Database Mode
|
|
630
|
+
|
|
631
|
+
When `databaseMode: 'multi-tenant'`:
|
|
632
|
+
- Each tenant has isolated database/schema
|
|
633
|
+
- Action code cache is tenant-aware (separate cache per tenant)
|
|
634
|
+
- Uses `IAMDataSourceService` for tenant-specific connections
|
|
635
|
+
|
|
468
636
|
### Permission Merging
|
|
469
637
|
|
|
470
|
-
When
|
|
471
|
-
|
|
638
|
+
When `getMyPermissions` is called:
|
|
639
|
+
|
|
640
|
+
**With branchId specified:**
|
|
641
|
+
1. Company-wide roles (branchId=null) + Branch-specific roles for that branch
|
|
472
642
|
2. Actions from all merged roles
|
|
473
|
-
3. Company-wide user actions + Branch-specific user actions
|
|
643
|
+
3. Company-wide user actions + Branch-specific user actions for that branch
|
|
644
|
+
|
|
645
|
+
**Without branchId (null):**
|
|
646
|
+
1. ALL roles for the user in the company (any branch)
|
|
647
|
+
2. Actions from all roles
|
|
648
|
+
3. ALL user actions for the company (any branch)
|
|
474
649
|
|
|
475
|
-
**Result:** Complete permission set without duplicates.
|
|
650
|
+
**Result:** Complete permission set without duplicates, filtered by company whitelist.
|
|
476
651
|
|
|
477
652
|
---
|
|
478
653
|
|
|
@@ -537,73 +712,62 @@ Direct actions should be exceptions and branch-specific overrides, not the prima
|
|
|
537
712
|
|
|
538
713
|
## API Reference
|
|
539
714
|
|
|
540
|
-
###
|
|
715
|
+
### Exports
|
|
541
716
|
|
|
542
717
|
```typescript
|
|
543
|
-
|
|
544
|
-
|
|
718
|
+
// Config
|
|
719
|
+
export { IAM_MODULE_OPTIONS } from './config';
|
|
545
720
|
|
|
546
|
-
|
|
721
|
+
// Modules
|
|
722
|
+
export { IAMModule } from './modules';
|
|
547
723
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
} from '
|
|
557
|
-
|
|
724
|
+
// Entities
|
|
725
|
+
export { Action } from './entities/action.entity';
|
|
726
|
+
export { ActionBase } from './entities/action-base.entity';
|
|
727
|
+
export { Role } from './entities/role.entity';
|
|
728
|
+
export { RoleBase } from './entities/role-base.entity';
|
|
729
|
+
export { RoleWithCompany } from './entities/role-with-company.entity';
|
|
730
|
+
export { PermissionBase } from './entities/permission-base.entity';
|
|
731
|
+
export { UserIamPermission } from './entities/user-iam-permission.entity';
|
|
732
|
+
export { UserIamPermissionWithCompany } from './entities/permission-with-company.entity';
|
|
733
|
+
export { IAMCoreEntities, IAMCompanyEntities, IAMAllEntities, getIAMEntitiesByConfig } from './entities';
|
|
558
734
|
|
|
559
|
-
|
|
735
|
+
// Services
|
|
736
|
+
export { ActionService } from './services/action.service';
|
|
737
|
+
export { RoleService } from './services/role.service';
|
|
738
|
+
export { PermissionService } from './services/permission.service';
|
|
739
|
+
export { PermissionCacheService } from './services/permission-cache.service';
|
|
740
|
+
export { IAMConfigService } from './services/iam-config.service';
|
|
741
|
+
export { IAMDataSourceService } from './services/iam-datasource.service';
|
|
560
742
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
Role,
|
|
565
|
-
RoleWithCompany,
|
|
566
|
-
UserIamPermission,
|
|
567
|
-
UserIamPermissionWithCompany,
|
|
568
|
-
getIAMEntitiesByConfig,
|
|
569
|
-
} from '@flusys/nestjs-iam/entities';
|
|
570
|
-
```
|
|
743
|
+
// Helpers
|
|
744
|
+
export { PermissionModeHelper } from './helpers/permission-mode.helper';
|
|
745
|
+
export { validateCompanyAccess } from './helpers/company-access.helper';
|
|
571
746
|
|
|
572
|
-
|
|
747
|
+
// Enums
|
|
748
|
+
export { ActionType } from './enums/action-type.enum';
|
|
749
|
+
export { IAMPermissionMode } from './enums/permission-type.enum';
|
|
573
750
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
CreateActionDto,
|
|
577
|
-
UpdateActionDto,
|
|
578
|
-
CreateRoleDto,
|
|
579
|
-
UpdateRoleDto,
|
|
580
|
-
AssignUserActionsDto,
|
|
581
|
-
AssignUserRolesDto,
|
|
582
|
-
AssignRoleActionsDto,
|
|
583
|
-
AssignCompanyActionsDto,
|
|
584
|
-
MyPermissionsResponseDto,
|
|
585
|
-
FrontendActionDto,
|
|
586
|
-
} from '@flusys/nestjs-iam/dtos';
|
|
587
|
-
```
|
|
588
|
-
|
|
589
|
-
### Enums
|
|
751
|
+
// Types
|
|
752
|
+
export { LogicNode } from './types/logic-node.type';
|
|
590
753
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
754
|
+
// DTOs
|
|
755
|
+
export * from './dtos';
|
|
756
|
+
|
|
757
|
+
// Interfaces
|
|
758
|
+
export * from './interfaces';
|
|
759
|
+
|
|
760
|
+
// Swagger Config
|
|
761
|
+
export { iamSwaggerConfig } from './docs';
|
|
598
762
|
```
|
|
599
763
|
|
|
600
|
-
###
|
|
764
|
+
### Module Static Methods
|
|
601
765
|
|
|
602
766
|
```typescript
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
767
|
+
// Configure module
|
|
768
|
+
IAMModule.forRoot(options?: IAMModuleOptions): DynamicModule
|
|
769
|
+
IAMModule.forRootAsync(options: IAMModuleAsyncOptions): DynamicModule
|
|
770
|
+
IAMModule.forFeature(options?: IAMModuleOptions): DynamicModule
|
|
607
771
|
```
|
|
608
772
|
|
|
609
773
|
---
|
|
@@ -612,6 +776,9 @@ import {
|
|
|
612
776
|
|
|
613
777
|
```
|
|
614
778
|
nestjs-iam/src/
|
|
779
|
+
├── config/
|
|
780
|
+
│ ├── iam.constants.ts # IAM_MODULE_OPTIONS token
|
|
781
|
+
│ └── index.ts
|
|
615
782
|
├── modules/
|
|
616
783
|
│ └── iam.module.ts # Main module with dynamic config
|
|
617
784
|
├── entities/
|
|
@@ -622,14 +789,15 @@ nestjs-iam/src/
|
|
|
622
789
|
│ ├── role-with-company.entity.ts
|
|
623
790
|
│ ├── permission-base.entity.ts # Permission base fields
|
|
624
791
|
│ ├── user-iam-permission.entity.ts
|
|
625
|
-
│
|
|
792
|
+
│ ├── permission-with-company.entity.ts
|
|
793
|
+
│ └── index.ts # Entity groups & getIAMEntitiesByConfig
|
|
626
794
|
├── services/
|
|
627
795
|
│ ├── action.service.ts # Action CRUD
|
|
628
796
|
│ ├── role.service.ts # Role CRUD
|
|
629
797
|
│ ├── permission.service.ts # Permission management
|
|
630
798
|
│ ├── permission-cache.service.ts # Cache management
|
|
631
799
|
│ ├── iam-config.service.ts # Configuration
|
|
632
|
-
│ └── iam-datasource.
|
|
800
|
+
│ └── iam-datasource.service.ts # DataSource provider
|
|
633
801
|
├── controllers/
|
|
634
802
|
│ ├── action.controller.ts
|
|
635
803
|
│ ├── role.controller.ts
|
|
@@ -638,8 +806,8 @@ nestjs-iam/src/
|
|
|
638
806
|
│ ├── user-action-permission.controller.ts
|
|
639
807
|
│ └── company-action-permission.controller.ts
|
|
640
808
|
├── helpers/
|
|
641
|
-
│ ├──
|
|
642
|
-
│ └── permission-mode.helper.ts
|
|
809
|
+
│ ├── company-access.helper.ts # Company access validation
|
|
810
|
+
│ └── permission-mode.helper.ts # String to enum conversion
|
|
643
811
|
├── dtos/
|
|
644
812
|
│ ├── action.dto.ts
|
|
645
813
|
│ ├── role.dto.ts
|
|
@@ -651,10 +819,13 @@ nestjs-iam/src/
|
|
|
651
819
|
├── enums/
|
|
652
820
|
│ ├── action-type.enum.ts
|
|
653
821
|
│ └── permission-type.enum.ts
|
|
654
|
-
|
|
655
|
-
|
|
822
|
+
├── types/
|
|
823
|
+
│ └── logic-node.type.ts
|
|
824
|
+
├── docs/
|
|
825
|
+
│ └── iam-swagger.config.ts
|
|
826
|
+
└── index.ts
|
|
656
827
|
```
|
|
657
828
|
|
|
658
829
|
---
|
|
659
830
|
|
|
660
|
-
**Last Updated:** 2026-02-
|
|
831
|
+
**Last Updated:** 2026-02-21
|
|
@@ -42,7 +42,50 @@ function _ts_param(paramIndex, decorator) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
let ActionController = class ActionController extends (0, _nestjsshared.createApiController)(_actiondto.CreateActionDto, _actiondto.UpdateActionDto, _actiondto.ActionResponseDto, {
|
|
45
|
-
security:
|
|
45
|
+
security: {
|
|
46
|
+
insert: {
|
|
47
|
+
level: 'permission',
|
|
48
|
+
permissions: [
|
|
49
|
+
_nestjsshared.ACTION_PERMISSIONS.CREATE
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
insertMany: {
|
|
53
|
+
level: 'permission',
|
|
54
|
+
permissions: [
|
|
55
|
+
_nestjsshared.ACTION_PERMISSIONS.CREATE
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
getById: {
|
|
59
|
+
level: 'permission',
|
|
60
|
+
permissions: [
|
|
61
|
+
_nestjsshared.ACTION_PERMISSIONS.READ
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
getAll: {
|
|
65
|
+
level: 'permission',
|
|
66
|
+
permissions: [
|
|
67
|
+
_nestjsshared.ACTION_PERMISSIONS.READ
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
update: {
|
|
71
|
+
level: 'permission',
|
|
72
|
+
permissions: [
|
|
73
|
+
_nestjsshared.ACTION_PERMISSIONS.UPDATE
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
updateMany: {
|
|
77
|
+
level: 'permission',
|
|
78
|
+
permissions: [
|
|
79
|
+
_nestjsshared.ACTION_PERMISSIONS.UPDATE
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
delete: {
|
|
83
|
+
level: 'permission',
|
|
84
|
+
permissions: [
|
|
85
|
+
_nestjsshared.ACTION_PERMISSIONS.DELETE
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
46
89
|
}) {
|
|
47
90
|
async getActionsForPermission(user) {
|
|
48
91
|
const actions = await this.actionService.getActionsForPermission(user);
|
|
@@ -65,7 +108,7 @@ let ActionController = class ActionController extends (0, _nestjsshared.createAp
|
|
|
65
108
|
}
|
|
66
109
|
};
|
|
67
110
|
_ts_decorate([
|
|
68
|
-
(0, _common.
|
|
111
|
+
(0, _common.Post)('tree-for-permission'),
|
|
69
112
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
70
113
|
(0, _swagger.ApiBearerAuth)(),
|
|
71
114
|
(0, _swagger.ApiOperation)({
|