permissions-contractx 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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1397 -0
  3. package/dist/constants/contractx-permissions.constants.d.ts +310 -0
  4. package/dist/constants/contractx-permissions.constants.d.ts.map +1 -0
  5. package/dist/constants/contractx-permissions.constants.js +1061 -0
  6. package/dist/constants/contractx-roles.constants.d.ts +295 -0
  7. package/dist/constants/contractx-roles.constants.d.ts.map +1 -0
  8. package/dist/constants/contractx-roles.constants.js +238 -0
  9. package/dist/constants/index.d.ts +3 -0
  10. package/dist/constants/index.d.ts.map +1 -0
  11. package/dist/constants/index.js +18 -0
  12. package/dist/constants/security.constants.d.ts +77 -0
  13. package/dist/constants/security.constants.d.ts.map +1 -0
  14. package/dist/constants/security.constants.js +139 -0
  15. package/dist/decorators/current-user.decorator.d.ts +73 -0
  16. package/dist/decorators/current-user.decorator.d.ts.map +1 -0
  17. package/dist/decorators/current-user.decorator.js +91 -0
  18. package/dist/decorators/index.d.ts +5 -0
  19. package/dist/decorators/index.d.ts.map +1 -0
  20. package/dist/decorators/index.js +20 -0
  21. package/dist/decorators/permissions.decorator.d.ts +97 -0
  22. package/dist/decorators/permissions.decorator.d.ts.map +1 -0
  23. package/dist/decorators/permissions.decorator.js +106 -0
  24. package/dist/decorators/public.decorator.d.ts +18 -0
  25. package/dist/decorators/public.decorator.d.ts.map +1 -0
  26. package/dist/decorators/public.decorator.js +22 -0
  27. package/dist/decorators/roles.decorator.d.ts +79 -0
  28. package/dist/decorators/roles.decorator.d.ts.map +1 -0
  29. package/dist/decorators/roles.decorator.js +87 -0
  30. package/dist/guards/index.d.ts +4 -0
  31. package/dist/guards/index.d.ts.map +1 -0
  32. package/dist/guards/index.js +19 -0
  33. package/dist/guards/jwt-auth.guard.d.ts +21 -0
  34. package/dist/guards/jwt-auth.guard.d.ts.map +1 -0
  35. package/dist/guards/jwt-auth.guard.js +115 -0
  36. package/dist/guards/permissions.guard.d.ts +14 -0
  37. package/dist/guards/permissions.guard.d.ts.map +1 -0
  38. package/dist/guards/permissions.guard.js +77 -0
  39. package/dist/guards/roles.guard.d.ts +13 -0
  40. package/dist/guards/roles.guard.d.ts.map +1 -0
  41. package/dist/guards/roles.guard.js +59 -0
  42. package/dist/index.d.ts +8 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +28 -0
  45. package/dist/interfaces/index.d.ts +2 -0
  46. package/dist/interfaces/index.d.ts.map +1 -0
  47. package/dist/interfaces/index.js +17 -0
  48. package/dist/interfaces/jwt-payload.interface.d.ts +93 -0
  49. package/dist/interfaces/jwt-payload.interface.d.ts.map +1 -0
  50. package/dist/interfaces/jwt-payload.interface.js +2 -0
  51. package/dist/modules/index.d.ts +2 -0
  52. package/dist/modules/index.d.ts.map +1 -0
  53. package/dist/modules/index.js +17 -0
  54. package/dist/modules/permissions-contractx.module.d.ts +41 -0
  55. package/dist/modules/permissions-contractx.module.d.ts.map +1 -0
  56. package/dist/modules/permissions-contractx.module.js +215 -0
  57. package/dist/services/contractx-authorization.service.d.ts +107 -0
  58. package/dist/services/contractx-authorization.service.d.ts.map +1 -0
  59. package/dist/services/contractx-authorization.service.js +362 -0
  60. package/dist/services/contractx-document-compliance.service.d.ts +85 -0
  61. package/dist/services/contractx-document-compliance.service.d.ts.map +1 -0
  62. package/dist/services/contractx-document-compliance.service.js +536 -0
  63. package/dist/services/contractx-validation.service.d.ts +76 -0
  64. package/dist/services/contractx-validation.service.d.ts.map +1 -0
  65. package/dist/services/contractx-validation.service.js +305 -0
  66. package/dist/services/index.d.ts +6 -0
  67. package/dist/services/index.d.ts.map +1 -0
  68. package/dist/services/index.js +20 -0
  69. package/dist/services/user-context.service.d.ts +114 -0
  70. package/dist/services/user-context.service.d.ts.map +1 -0
  71. package/dist/services/user-context.service.js +199 -0
  72. package/dist/test-document-compliance.d.ts +7 -0
  73. package/dist/test-document-compliance.d.ts.map +1 -0
  74. package/dist/test-document-compliance.js +118 -0
  75. package/package.json +405 -0
package/README.md ADDED
@@ -0,0 +1,1397 @@
1
+ # ๐Ÿ” Permissions ContractX
2
+
3
+ A comprehensive **NestJS authentication and authorization package** designed for microservices in the ContractX ecosystem. This package provides JWT-based authentication, role-based access control (RBAC), and granular permission management.
4
+
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=flat&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
+ [![NestJS](https://img.shields.io/badge/NestJS-E0234E?style=flat&logo=nestjs&logoColor=white)](https://nestjs.com/)
7
+ [![JWT](https://img.shields.io/badge/JWT-000000?style=flat&logo=JSON%20web%20tokens)](https://jwt.io/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## โœจ Features
11
+
12
+ - ๐Ÿ”‘ **JWT Authentication** - Secure token-based authentication
13
+ - ๐Ÿ‘ฅ **Role-Based Access Control** - Hierarchical role system
14
+ - ๐Ÿ” **Permission-Based Authorization** - Granular permission control
15
+ - ๐Ÿข **Multi-Tenant Support** - Client/Provider organizational structure
16
+ - ๐Ÿš€ **Easy Integration** - Simple decorator-based API
17
+ - ๐Ÿ›ก๏ธ **Security First** - Built-in security best practices
18
+ - ๐Ÿ“Š **Request Context** - User context service for easy access
19
+ - ๐Ÿ”ง **TypeScript** - Full TypeScript support with strict typing
20
+ - ๐Ÿ“– **Comprehensive Documentation** - Detailed examples and guides
21
+
22
+ ## ๐Ÿ“ฆ Installation
23
+
24
+ ```bash
25
+ npm install permissions-contractx
26
+ ```
27
+
28
+ ### Peer Dependencies
29
+
30
+ Make sure you have the required peer dependencies installed:
31
+
32
+ ```bash
33
+ npm install @nestjs/common @nestjs/core @nestjs/jwt @nestjs/config jsonwebtoken rxjs reflect-metadata
34
+ ```
35
+
36
+ ## ๐Ÿš€ Quick Start
37
+
38
+ ### 1. Basic Setup
39
+
40
+ ```typescript
41
+ // app.module.ts
42
+ import { Module } from '@nestjs/common';
43
+ import { PermissionsContractXModule } from 'permissions-contractx';
44
+
45
+ @Module({
46
+ imports: [
47
+ PermissionsContractXModule.register({
48
+ jwt: {
49
+ secret: 'your-secret-key',
50
+ issuer: 'your-api',
51
+ audience: 'your-users',
52
+ expiresIn: '15m',
53
+ },
54
+ guards: {
55
+ enableGlobalAuth: true, // Apply authentication globally
56
+ },
57
+ }),
58
+ ],
59
+ })
60
+ export class AppModule {}
61
+ ```
62
+
63
+ ### 2. Using Decorators in Controllers
64
+
65
+ ```typescript
66
+ import { Controller, Get, Post, UseGuards } from '@nestjs/common';
67
+ import {
68
+ CurrentUser,
69
+ Roles,
70
+ RequirePermissions,
71
+ Public,
72
+ JwtAuthGuard,
73
+ RolesGuard,
74
+ PermissionsGuard,
75
+ JwtPayload,
76
+ } from 'permissions-contractx';
77
+
78
+ @Controller('users')
79
+ @UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
80
+ export class UsersController {
81
+
82
+ // Public endpoint (no authentication)
83
+ @Public()
84
+ @Get('public')
85
+ getPublicInfo() {
86
+ return { message: 'This is public' };
87
+ }
88
+
89
+ // Authenticated endpoint
90
+ @Get('profile')
91
+ getProfile(@CurrentUser() user: JwtPayload) {
92
+ return {
93
+ id: user.sub,
94
+ name: user.fullName,
95
+ roles: user.role,
96
+ permissions: user.permissions,
97
+ };
98
+ }
99
+
100
+ // Role-based access
101
+ @Roles('superadmin', 'client_contract_admin')
102
+ @Get('admin-data')
103
+ getAdminData() {
104
+ return { message: 'Admin only data' };
105
+ }
106
+
107
+ // Permission-based access
108
+ @RequirePermissions('users.create')
109
+ @Post()
110
+ createUser(@CurrentUser() user: JwtPayload) {
111
+ return { message: 'User created', createdBy: user.fullName };
112
+ }
113
+
114
+ // Combined role and permission
115
+ @Roles('client_contract_admin')
116
+ @RequirePermissions('users.delete')
117
+ @Delete(':id')
118
+ deleteUser(@Param('id') id: string) {
119
+ return { message: `User ${id} deleted` };
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### 3. Environment Variables Setup
125
+
126
+ Create a `.env` file:
127
+
128
+ ```env
129
+ JWT_SECRET=your-super-secret-jwt-key-change-in-production
130
+ JWT_ISSUER=contractx-api
131
+ JWT_AUDIENCE=contractx-users
132
+ JWT_EXPIRES_IN=15m
133
+
134
+ # Optional: Enable global guards
135
+ ENABLE_GLOBAL_AUTH=true
136
+ ENABLE_AUTH_LOGGING=true
137
+
138
+ # Development only
139
+ DISABLE_AUTH=false # Set to true to disable auth in development
140
+ ```
141
+
142
+ ### 4. Auto-Configuration with Environment Variables
143
+
144
+ ```typescript
145
+ // app.module.ts - Easiest setup
146
+ @Module({
147
+ imports: [
148
+ PermissionsContractXModule.forRoot(), // Auto-configures from environment variables
149
+ ],
150
+ })
151
+ export class AppModule {}
152
+ ```
153
+
154
+ ## ๐Ÿ—๏ธ Advanced Configuration
155
+
156
+ ### Async Configuration
157
+
158
+ ```typescript
159
+ import { ConfigModule, ConfigService } from '@nestjs/config';
160
+
161
+ @Module({
162
+ imports: [
163
+ PermissionsContractXModule.registerAsync({
164
+ imports: [ConfigModule],
165
+ useFactory: async (configService: ConfigService) => ({
166
+ jwt: {
167
+ secret: configService.get('JWT_SECRET'),
168
+ issuer: configService.get('JWT_ISSUER'),
169
+ audience: configService.get('JWT_AUDIENCE'),
170
+ expiresIn: configService.get('JWT_EXPIRES_IN', '15m'),
171
+ clockTolerance: 30, // seconds
172
+ },
173
+ guards: {
174
+ enableGlobalAuth: true,
175
+ enableGlobalRoles: false,
176
+ enableGlobalPermissions: false,
177
+ },
178
+ security: {
179
+ enableLogging: process.env.NODE_ENV === 'production',
180
+ },
181
+ development: {
182
+ disableAuth: process.env.NODE_ENV === 'development',
183
+ mockUser: {
184
+ sub: 'dev-user-123',
185
+ role: ['superadmin'],
186
+ permissions: ['*'],
187
+ fullName: 'Development User',
188
+ email: 'dev@example.com',
189
+ },
190
+ },
191
+ }),
192
+ inject: [ConfigService],
193
+ }),
194
+ ],
195
+ })
196
+ export class AppModule {}
197
+ ```
198
+
199
+ ## ๐Ÿ“‹ JWT Token Structure
200
+
201
+ The JWT token must include the following payload structure:
202
+
203
+ ```json
204
+ {
205
+ "sub": "user_123456789", // User ID (required)
206
+ "fullName": "John Doe", // User's full name (required)
207
+ "email": "john@example.com", // User's email
208
+ "clientId": "client_001", // Organization/Client ID
209
+ "sessionId": "session_abc", // Session tracking
210
+
211
+ "role": [ // User roles array (required)
212
+ "admin",
213
+ "manager",
214
+ "user"
215
+ ],
216
+
217
+ "permissions": [ // User permissions array (required)
218
+ "users:read",
219
+ "users:create",
220
+ "users:update",
221
+ "users:delete",
222
+ "settings:manage"
223
+ ],
224
+
225
+ // Standard JWT fields
226
+ "iat": 1609459200, // Issued at
227
+ "exp": 1609545600, // Expires at
228
+ "iss": "contractx-api", // Issuer
229
+ "aud": "contractx-users" // Audience
230
+ }
231
+ ```
232
+
233
+ ## ๐Ÿ›ก๏ธ Guards
234
+
235
+ ### 1. JwtAuthGuard
236
+
237
+ Validates JWT tokens and extracts user information.
238
+
239
+ ```typescript
240
+ import { Controller, UseGuards } from '@nestjs/common';
241
+ import { JwtAuthGuard } from 'permissions-contractx';
242
+
243
+ @Controller('protected')
244
+ @UseGuards(JwtAuthGuard)
245
+ export class ProtectedController {
246
+ // All routes require valid JWT token
247
+ }
248
+ ```
249
+
250
+ ### 2. RolesGuard
251
+
252
+ Checks if user has required roles.
253
+
254
+ ```typescript
255
+ import { Controller, UseGuards } from '@nestjs/common';
256
+ import { JwtAuthGuard, RolesGuard, RequireRoles } from 'permissions-contractx';
257
+
258
+ @Controller('admin')
259
+ @UseGuards(JwtAuthGuard, RolesGuard)
260
+ export class AdminController {
261
+
262
+ @Get('dashboard')
263
+ @RequireRoles('admin', 'manager') // User must have admin OR manager role
264
+ getDashboard() {
265
+ return { message: 'Admin dashboard' };
266
+ }
267
+ }
268
+ ```
269
+
270
+ ### 3. PermissionsGuard
271
+
272
+ Checks if user has required permissions.
273
+
274
+ ```typescript
275
+ import { Controller, UseGuards } from '@nestjs/common';
276
+ import { JwtAuthGuard, PermissionsGuard, RequirePermissions } from 'permissions-contractx';
277
+
278
+ @Controller('users')
279
+ @UseGuards(JwtAuthGuard, PermissionsGuard)
280
+ export class UsersController {
281
+
282
+ @Post()
283
+ @RequirePermissions('users:create') // User must have this exact permission
284
+ createUser() {
285
+ return { message: 'User created' };
286
+ }
287
+
288
+ @Delete(':id')
289
+ @RequirePermissions('users:delete', 'admin:all') // User must have one of these
290
+ deleteUser() {
291
+ return { message: 'User deleted' };
292
+ }
293
+ }
294
+ ```
295
+
296
+ ## ๐ŸŽฏ Decorators
297
+
298
+ The permissions-contractx package provides a comprehensive set of decorators for authentication and authorization in your NestJS applications.
299
+
300
+ ### ๐Ÿ” Authentication Decorators
301
+
302
+ #### `@Public()`
303
+ Marks routes as public (no authentication required). Essential for login endpoints, health checks, and public APIs.
304
+
305
+ ```typescript
306
+ @Controller('auth')
307
+ export class AuthController {
308
+ @Public()
309
+ @Post('login')
310
+ login(@Body() credentials: LoginDto) {
311
+ return this.authService.login(credentials);
312
+ }
313
+
314
+ @Public()
315
+ @Get('health')
316
+ getHealth() {
317
+ return { status: 'OK', timestamp: new Date() };
318
+ }
319
+ }
320
+ ```
321
+
322
+ #### `@CurrentUser(property?)`
323
+ Injects the current authenticated user or specific user properties into route handlers.
324
+
325
+ ```typescript
326
+ @Controller('users')
327
+ export class UsersController {
328
+ // Inject full user object
329
+ @Get('profile')
330
+ getProfile(@CurrentUser() user: JwtPayload) {
331
+ return {
332
+ id: user.sub,
333
+ name: user.fullName,
334
+ email: user.email,
335
+ roles: user.role,
336
+ permissions: user.permissions
337
+ };
338
+ }
339
+
340
+ // Inject specific user property
341
+ @Post('actions')
342
+ performAction(
343
+ @CurrentUser('sub') userId: string,
344
+ @CurrentUser('fullName') userName: string,
345
+ @Body() actionData: any
346
+ ) {
347
+ return {
348
+ action: 'completed',
349
+ performedBy: userName,
350
+ userId: userId,
351
+ data: actionData
352
+ };
353
+ }
354
+ }
355
+ ```
356
+
357
+ #### `@UserId()`
358
+ Convenience decorator to get the current user's ID directly.
359
+
360
+ ```typescript
361
+ @Controller('resources')
362
+ export class ResourcesController {
363
+ @Post()
364
+ createResource(
365
+ @UserId() userId: string,
366
+ @Body() resourceData: CreateResourceDto
367
+ ) {
368
+ return this.resourcesService.create({
369
+ ...resourceData,
370
+ createdBy: userId,
371
+ createdAt: new Date()
372
+ });
373
+ }
374
+
375
+ @Get('my-resources')
376
+ getMyResources(@UserId() userId: string) {
377
+ return this.resourcesService.findByUser(userId);
378
+ }
379
+ }
380
+ ```
381
+
382
+ #### `@UserRoles()`
383
+ Injects the current user's roles array into the route handler.
384
+
385
+ ```typescript
386
+ @Controller('dashboard')
387
+ export class DashboardController {
388
+ @Get('capabilities')
389
+ getUserCapabilities(@UserRoles() roles: string[]) {
390
+ const capabilities = {
391
+ canManageUsers: roles.includes('superadmin') || roles.includes('client_contract_admin'),
392
+ canViewReports: roles.some(role => role.includes('reports')),
393
+ canManageContracts: roles.some(role => role.includes('contract_admin')),
394
+ isClientSide: roles.some(role => role.startsWith('client_')),
395
+ isProviderSide: roles.some(role => role.startsWith('provider_'))
396
+ };
397
+
398
+ return { roles, capabilities };
399
+ }
400
+ }
401
+ ```
402
+
403
+ #### `@UserPermissions()`
404
+ Injects the current user's permissions array into the route handler.
405
+
406
+ ```typescript
407
+ @Controller('admin')
408
+ export class AdminController {
409
+ @Get('available-actions')
410
+ getAvailableActions(@UserPermissions() permissions: string[]) {
411
+ const modulePermissions = permissions.reduce((acc, permission) => {
412
+ const [module, action] = permission.split(':');
413
+ if (!acc[module]) acc[module] = [];
414
+ acc[module].push(action);
415
+ return acc;
416
+ }, {});
417
+
418
+ return {
419
+ totalPermissions: permissions.length,
420
+ moduleBreakdown: modulePermissions,
421
+ rawPermissions: permissions
422
+ };
423
+ }
424
+ }
425
+ ```
426
+
427
+ #### `@UserClientId()`
428
+ Injects the current user's client ID for multi-tenant applications.
429
+
430
+ ```typescript
431
+ @Controller('tenant')
432
+ export class TenantController {
433
+ @Get('data')
434
+ getTenantData(@UserClientId() clientId: string) {
435
+ return this.dataService.findByClient(clientId);
436
+ }
437
+
438
+ @Post('settings')
439
+ updateTenantSettings(
440
+ @UserClientId() clientId: string,
441
+ @Body() settings: TenantSettingsDto
442
+ ) {
443
+ return this.settingsService.update(clientId, settings);
444
+ }
445
+ }
446
+ ```
447
+
448
+ ### ๐Ÿ‘ฅ Role-Based Authorization Decorators
449
+
450
+ #### `@Roles(...roles)`
451
+ Requires user to have **at least one** of the specified roles (OR logic).
452
+
453
+ ```typescript
454
+ @Controller('admin')
455
+ export class AdminController {
456
+ // User needs superadmin OR any contract admin role
457
+ @Roles('superadmin', 'client_contract_admin', 'provider_contract_admin')
458
+ @Get('dashboard')
459
+ getAdminDashboard() {
460
+ return { message: 'Admin dashboard data' };
461
+ }
462
+
463
+ // Multiple specific roles
464
+ @Roles('client_finance_manager', 'provider_finance_manager')
465
+ @Get('financial-reports')
466
+ getFinancialReports() {
467
+ return this.reportsService.getFinancialData();
468
+ }
469
+ }
470
+ ```
471
+
472
+ #### `@AdminOnly()`
473
+ Shortcut for admin-level access (superadmin, client_contract_admin, provider_contract_admin).
474
+
475
+ ```typescript
476
+ @Controller('system')
477
+ export class SystemController {
478
+ @AdminOnly()
479
+ @Delete('cache')
480
+ clearCache() {
481
+ return this.cacheService.clear();
482
+ }
483
+
484
+ @AdminOnly()
485
+ @Post('maintenance-mode')
486
+ enableMaintenanceMode(@Body() config: MaintenanceConfigDto) {
487
+ return this.systemService.enableMaintenance(config);
488
+ }
489
+ }
490
+ ```
491
+
492
+ #### `@ClientOnly()`
493
+ Restricts access to client-side roles only.
494
+
495
+ ```typescript
496
+ @Controller('client')
497
+ export class ClientController {
498
+ @ClientOnly()
499
+ @Get('performance-metrics')
500
+ getClientPerformanceMetrics(@UserClientId() clientId: string) {
501
+ return this.metricsService.getClientMetrics(clientId);
502
+ }
503
+
504
+ @ClientOnly()
505
+ @Post('escalation')
506
+ createEscalation(@Body() escalationData: CreateEscalationDto) {
507
+ return this.escalationService.create(escalationData);
508
+ }
509
+ }
510
+ ```
511
+
512
+ #### `@ProviderOnly()`
513
+ Restricts access to provider-side roles only.
514
+
515
+ ```typescript
516
+ @Controller('provider')
517
+ export class ProviderController {
518
+ @ProviderOnly()
519
+ @Get('delivery-schedule')
520
+ getDeliverySchedule() {
521
+ return this.deliveryService.getSchedule();
522
+ }
523
+
524
+ @ProviderOnly()
525
+ @Put('deliverable/:id/status')
526
+ updateDeliverableStatus(
527
+ @Param('id') id: string,
528
+ @Body() statusUpdate: DeliverableStatusDto
529
+ ) {
530
+ return this.deliverableService.updateStatus(id, statusUpdate);
531
+ }
532
+ }
533
+ ```
534
+
535
+ #### `@SuperAdminOnly()`
536
+ Restricts access to superadmin role only.
537
+
538
+ ```typescript
539
+ @Controller('system-admin')
540
+ export class SystemAdminController {
541
+ @SuperAdminOnly()
542
+ @Post('create-tenant')
543
+ createTenant(@Body() tenantData: CreateTenantDto) {
544
+ return this.tenantService.create(tenantData);
545
+ }
546
+
547
+ @SuperAdminOnly()
548
+ @Delete('user/:id')
549
+ deleteUser(@Param('id') userId: string) {
550
+ return this.userService.delete(userId);
551
+ }
552
+ }
553
+ ```
554
+
555
+ ### ๐Ÿ” Permission-Based Authorization Decorators
556
+
557
+ #### `@RequirePermissions(...permissions)`
558
+ Requires user to have **all** specified permissions (AND logic).
559
+
560
+ ```typescript
561
+ @Controller('contracts')
562
+ export class ContractsController {
563
+ // User must have ALL specified permissions
564
+ @RequirePermissions('contracts.create', 'contracts.validate')
565
+ @Post()
566
+ createContract(@Body() contractData: CreateContractDto) {
567
+ return this.contractService.create(contractData);
568
+ }
569
+
570
+ // Single permission requirement
571
+ @RequirePermissions('contracts.delete')
572
+ @Delete(':id')
573
+ deleteContract(@Param('id') id: string) {
574
+ return this.contractService.delete(id);
575
+ }
576
+ }
577
+ ```
578
+
579
+ #### `@RequireAnyPermission(...permissions)`
580
+ Requires user to have **at least one** of the specified permissions (OR logic).
581
+
582
+ ```typescript
583
+ @Controller('documents')
584
+ export class DocumentsController {
585
+ // User needs ANY of these permissions
586
+ @RequireAnyPermission('documents.read', 'documents.show', 'documents.filter')
587
+ @Get()
588
+ getDocuments(@Query() filters: DocumentFiltersDto) {
589
+ return this.documentService.findAll(filters);
590
+ }
591
+
592
+ // Administrative permissions
593
+ @RequireAnyPermission('documents.admin', 'superadmin.all')
594
+ @Post('batch-process')
595
+ batchProcessDocuments(@Body() batchData: BatchProcessDto) {
596
+ return this.documentService.batchProcess(batchData);
597
+ }
598
+ }
599
+ ```
600
+
601
+ ### ๐ŸŽฏ Module-Level Permission Decorators
602
+
603
+ These decorators provide convenient access patterns based on common CRUD operations:
604
+
605
+ #### `@ReadAccess(module)`
606
+ Grants read access to a module (read, show, or filter permissions).
607
+
608
+ ```typescript
609
+ @Controller('reports')
610
+ export class ReportsController {
611
+ @ReadAccess('reports')
612
+ @Get('financial')
613
+ getFinancialReports() {
614
+ // User needs reports.read, reports.show, OR reports.filter
615
+ return this.reportsService.getFinancialReports();
616
+ }
617
+
618
+ @ReadAccess('contracts')
619
+ @Get('contract-summary')
620
+ getContractSummary() {
621
+ // User needs contracts.read, contracts.show, OR contracts.filter
622
+ return this.contractService.getSummary();
623
+ }
624
+ }
625
+ ```
626
+
627
+ #### `@WriteAccess(module)`
628
+ Grants write access to a module (create or update permissions).
629
+
630
+ ```typescript
631
+ @Controller('users')
632
+ export class UsersController {
633
+ @WriteAccess('users')
634
+ @Post()
635
+ createUser(@Body() userData: CreateUserDto) {
636
+ // User needs users.create OR users.update
637
+ return this.userService.create(userData);
638
+ }
639
+
640
+ @WriteAccess('users')
641
+ @Put(':id')
642
+ updateUser(
643
+ @Param('id') id: string,
644
+ @Body() userData: UpdateUserDto
645
+ ) {
646
+ // User needs users.create OR users.update
647
+ return this.userService.update(id, userData);
648
+ }
649
+ }
650
+ ```
651
+
652
+ #### `@DeleteAccess(module)`
653
+ Grants delete access to a module.
654
+
655
+ ```typescript
656
+ @Controller('deliverables')
657
+ export class DeliverablesController {
658
+ @DeleteAccess('deliverables')
659
+ @Delete(':id')
660
+ deleteDeliverable(@Param('id') id: string) {
661
+ // User needs deliverables.delete
662
+ return this.deliverableService.delete(id);
663
+ }
664
+ }
665
+ ```
666
+
667
+ #### `@FullAccess(module)`
668
+ Grants full CRUD access to a module (any module permission).
669
+
670
+ ```typescript
671
+ @Controller('admin/modules')
672
+ export class ModuleAdminController {
673
+ @FullAccess('users')
674
+ @Post('users/bulk-operation')
675
+ bulkUserOperation(@Body() operation: BulkOperationDto) {
676
+ // User needs ANY users module permission
677
+ return this.userService.bulkOperation(operation);
678
+ }
679
+ }
680
+ ```
681
+
682
+ ### ๐Ÿ”„ Combining Decorators
683
+
684
+ Decorators can be combined for complex authorization logic:
685
+
686
+ ```typescript
687
+ @Controller('advanced')
688
+ export class AdvancedController {
689
+ // Combine role and permission requirements
690
+ @Roles('client_contract_admin', 'provider_contract_admin')
691
+ @RequirePermissions('contracts.approve')
692
+ @Put('contracts/:id/approve')
693
+ approveContract(
694
+ @Param('id') contractId: string,
695
+ @CurrentUser() user: JwtPayload
696
+ ) {
697
+ return this.contractService.approve(contractId, user.sub);
698
+ }
699
+
700
+ // Complex permission logic
701
+ @ClientOnly()
702
+ @RequireAnyPermission('reports.generate', 'reports.admin')
703
+ @Post('custom-report')
704
+ generateCustomReport(
705
+ @Body() reportSpec: CustomReportDto,
706
+ @UserClientId() clientId: string
707
+ ) {
708
+ return this.reportsService.generateCustom(reportSpec, clientId);
709
+ }
710
+
711
+ // Multiple permission sets
712
+ @RequirePermissions('documents.create')
713
+ @RequireAnyPermission('contracts.update', 'deliverables.update')
714
+ @Post('document-with-linking')
715
+ createLinkedDocument(
716
+ @Body() documentData: LinkedDocumentDto,
717
+ @UserId() userId: string
718
+ ) {
719
+ // User must have documents.create AND (contracts.update OR deliverables.update)
720
+ return this.documentService.createWithLinking(documentData, userId);
721
+ }
722
+ }
723
+ ```
724
+
725
+ ### ๐Ÿท๏ธ Method vs Class Level Decorators
726
+
727
+ Decorators can be applied at both class and method levels:
728
+
729
+ ```typescript
730
+ // Class-level decorators apply to all methods
731
+ @Controller('secure')
732
+ @UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
733
+ @ClientOnly() // All methods require client roles
734
+ export class SecureController {
735
+ @Get('data')
736
+ getData() {
737
+ // Inherits @ClientOnly from class
738
+ return this.dataService.getClientData();
739
+ }
740
+
741
+ @RequirePermissions('admin.override')
742
+ @Get('admin-data')
743
+ getAdminData() {
744
+ // Combines @ClientOnly + @RequirePermissions
745
+ return this.dataService.getAdminData();
746
+ }
747
+
748
+ @Public() // Overrides class-level @ClientOnly
749
+ @Get('public-info')
750
+ getPublicInfo() {
751
+ return { message: 'Public information' };
752
+ }
753
+ }
754
+ ```
755
+
756
+ ## ๐Ÿ› ๏ธ Services
757
+
758
+ ### UserContextService
759
+
760
+ Access user information and check permissions programmatically:
761
+
762
+ ```typescript
763
+ import { Injectable } from '@nestjs/common';
764
+ import { UserContextService } from 'permissions-contractx';
765
+
766
+ @Injectable()
767
+ export class MyService {
768
+ constructor(private userContext: UserContextService) {}
769
+
770
+ async doSomething() {
771
+ // Get user information
772
+ const user = this.userContext.getUser();
773
+ const userId = this.userContext.getUserId();
774
+ const roles = this.userContext.getUserRoles();
775
+
776
+ // Check permissions
777
+ if (this.userContext.hasRole('admin')) {
778
+ // Do admin stuff
779
+ }
780
+
781
+ if (this.userContext.hasPermission('users.create')) {
782
+ // Can create users
783
+ }
784
+
785
+ if (this.userContext.isClientUser()) {
786
+ // Client-side user logic
787
+ }
788
+
789
+ // Get user summary for logging
790
+ const summary = this.userContext.getUserSummary();
791
+ console.log('User accessing service:', summary);
792
+ }
793
+ }
794
+ ```
795
+
796
+ ## ๐Ÿšซ Error Handling
797
+
798
+ The package provides specific error messages for different authentication and authorization failures:
799
+
800
+ ### Common Error Responses
801
+
802
+ ```json
803
+ // 401 - Missing token
804
+ {
805
+ "statusCode": 401,
806
+ "message": "Access token is required",
807
+ "error": "Unauthorized"
808
+ }
809
+
810
+ // 401 - Invalid token
811
+ {
812
+ "statusCode": 401,
813
+ "message": "Invalid access token",
814
+ "error": "Unauthorized"
815
+ }
816
+
817
+ // 401 - Expired token
818
+ {
819
+ "statusCode": 401,
820
+ "message": "Access token has expired",
821
+ "error": "Unauthorized"
822
+ }
823
+
824
+ // 403 - Insufficient permissions
825
+ {
826
+ "statusCode": 403,
827
+ "message": "Insufficient permissions. Required: users:create",
828
+ "error": "Forbidden"
829
+ }
830
+
831
+ // 403 - Missing roles
832
+ {
833
+ "statusCode": 403,
834
+ "message": "Insufficient roles. Required: admin",
835
+ "error": "Forbidden"
836
+ }
837
+ ```
838
+
839
+ ### Custom Error Handling
840
+
841
+ ```typescript
842
+ import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
843
+ import { UnauthorizedException, ForbiddenException } from '@nestjs/common';
844
+
845
+ @Catch(UnauthorizedException, ForbiddenException)
846
+ export class AuthExceptionFilter implements ExceptionFilter {
847
+ catch(exception: UnauthorizedException | ForbiddenException, host: ArgumentsHost) {
848
+ const ctx = host.switchToHttp();
849
+ const response = ctx.getResponse();
850
+
851
+ // Custom error handling logic
852
+ response.status(exception.getStatus()).json({
853
+ statusCode: exception.getStatus(),
854
+ message: exception.message,
855
+ timestamp: new Date().toISOString(),
856
+ });
857
+ }
858
+ }
859
+ ```
860
+
861
+ ## ๐Ÿ’พ Database Integration & ODS Seeder
862
+
863
+ ### ODS Roles and Permissions Seeder
864
+
865
+ The package includes a complete seeder for the ODS (Operational Data Store) roles and permissions matrix with **16 predefined roles** and **23 modules**:
866
+
867
+ ```typescript
868
+ import { ContractXRolePermissionSeeder } from '@your-org/permissions-contractx';
869
+
870
+ @Injectable()
871
+ export class DatabaseSeederService {
872
+ constructor(
873
+ private readonly seeder: ContractXRolePermissionSeeder,
874
+ // Your repository dependencies
875
+ @InjectRepository(Role) private roleRepo: Repository<Role>,
876
+ @InjectRepository(Permission) private permissionRepo: Repository<Permission>,
877
+ @InjectRepository(RolePermission) private rolePermissionRepo: Repository<RolePermission>
878
+ ) {}
879
+
880
+ async seedRolesAndPermissions() {
881
+ const { roles, permissions, rolePermissions } = await this.seeder.seed();
882
+
883
+ // Save to database
884
+ const savedRoles = await this.roleRepo.save(roles);
885
+ const savedPermissions = await this.permissionRepo.save(permissions);
886
+
887
+ // Update IDs for role-permission mappings
888
+ const mappingsWithIds = rolePermissions.map(rp => ({
889
+ ...rp,
890
+ roleId: savedRoles.find(r => r.name === roles.find(role => role.id === rp.roleId)?.name)?.id,
891
+ permissionId: savedPermissions.find(p => p.name === permissions.find(perm => perm.id === rp.permissionId)?.name)?.id
892
+ }));
893
+
894
+ await this.rolePermissionRepo.save(mappingsWithIds);
895
+
896
+ // Validate seeded data
897
+ const isValid = await this.seeder.validateSeed(savedRoles, savedPermissions, mappingsWithIds);
898
+ if (!isValid) {
899
+ throw new Error('Seeder validation failed');
900
+ }
901
+
902
+ // Get statistics
903
+ const stats = this.seeder.getSeederStats();
904
+ console.log('Seeding completed:', stats);
905
+ /*
906
+ Output:
907
+ {
908
+ totalRoles: 16,
909
+ totalPermissions: 161, // 23 modules ร— 7 actions each
910
+ totalModules: 23,
911
+ rolesByType: {
912
+ system: 4,
913
+ client: 6,
914
+ provider: 6
915
+ },
916
+ permissionsByCategory: {
917
+ contract_management: 98,
918
+ financial: 21,
919
+ system_admin: 21,
920
+ user_management: 7,
921
+ client_management: 7,
922
+ provider_management: 7
923
+ }
924
+ }
925
+ */
926
+ }
927
+ }
928
+ ```
929
+
930
+ ### ODS Roles Matrix (16 Roles)
931
+
932
+ The seeder creates the following roles based on the complete ODS specification:
933
+
934
+ #### ๐Ÿ”ง System Roles
935
+ - **superadmin**: Full system access to all modules
936
+ - **support**: Broad access excluding client management
937
+ - **auditor**: Read-only audit and compliance access
938
+ - **guest**: Limited read-only access
939
+
940
+ #### ๐Ÿ‘ฅ Client-Side Roles
941
+ - **client_contract_admin**: Full contract management for client
942
+ - **client_performance_manager**: SLA and performance management
943
+ - **client_finance_manager**: Financial operations and invoicing
944
+ - **client_reports_manager**: Reporting and analytics
945
+ - **client_relationship_manager**: Relationship and meeting management
946
+ - **client_risk_manager**: Risk and security management
947
+
948
+ #### ๐Ÿข Provider-Side Roles
949
+ - **provider_contract_admin**: Provider contract administration
950
+ - **provider_performance_manager**: Provider performance management
951
+ - **provider_finance_manager**: Provider financial operations
952
+ - **provider_relationship_manager**: Provider relationship management
953
+ - **provider_risk_manager**: Provider risk management
954
+ - **provider_operator**: Operational support and deliverable management
955
+
956
+ ### ๐Ÿ“Š ODS Modules (23 Modules)
957
+
958
+ The seeder covers all ContractX modules with comprehensive CRUD permissions:
959
+
960
+ - **Core Management**: clients, contracts, users, providers, documents, clauses
961
+ - **Deliverables**: deliverables, subdeliverables, deliverable_history
962
+ - **SLA Management**: sla_services, measurement_windows, credit_service_levels
963
+ - **Collaboration**: meetings, meeting_participants, action_items
964
+ - **Notifications**: notification_escalations
965
+ - **Financial**: invoice_services, invoice_lines
966
+ - **System**: security_control, configuration, workflows
967
+
968
+ ### Database Entity Examples
969
+
970
+ For database integration with TypeORM, implement the seeder interfaces:
971
+
972
+ ```typescript
973
+ // Role Entity
974
+ @Entity('roles')
975
+ export class Role implements RoleEntity {
976
+ @PrimaryGeneratedColumn('uuid')
977
+ id: string;
978
+
979
+ @Column({ unique: true })
980
+ name: string;
981
+
982
+ @Column()
983
+ displayName: string;
984
+
985
+ @Column()
986
+ description: string;
987
+
988
+ @Column()
989
+ type: string;
990
+
991
+ @Column()
992
+ scope: string;
993
+
994
+ @Column()
995
+ level: number;
996
+
997
+ @Column({ default: true })
998
+ isActive: boolean;
999
+
1000
+ @Column()
1001
+ tenantAssociation: string;
1002
+
1003
+ @Column('jsonb')
1004
+ metadata: Record<string, any>;
1005
+
1006
+ @CreateDateColumn()
1007
+ createdAt: Date;
1008
+
1009
+ @UpdateDateColumn()
1010
+ updatedAt: Date;
1011
+ }
1012
+
1013
+ // Permission Entity
1014
+ @Entity('permissions')
1015
+ export class Permission implements PermissionEntity {
1016
+ @PrimaryGeneratedColumn('uuid')
1017
+ id: string;
1018
+
1019
+ @Column({ unique: true })
1020
+ name: string;
1021
+
1022
+ @Column()
1023
+ displayName: string;
1024
+
1025
+ @Column()
1026
+ description: string;
1027
+
1028
+ @Column()
1029
+ module: string;
1030
+
1031
+ @Column()
1032
+ action: string;
1033
+
1034
+ @Column()
1035
+ category: string;
1036
+
1037
+ @Column()
1038
+ scope: string;
1039
+
1040
+ @Column({ default: true })
1041
+ isActive: boolean;
1042
+
1043
+ @Column('jsonb')
1044
+ metadata: Record<string, any>;
1045
+
1046
+ @CreateDateColumn()
1047
+ createdAt: Date;
1048
+
1049
+ @UpdateDateColumn()
1050
+ updatedAt: Date;
1051
+ }
1052
+
1053
+ // Role-Permission Junction
1054
+ @Entity('role_permissions')
1055
+ export class RolePermission implements RolePermissionEntity {
1056
+ @PrimaryGeneratedColumn('uuid')
1057
+ id: string;
1058
+
1059
+ @Column()
1060
+ roleId: string;
1061
+
1062
+ @Column()
1063
+ permissionId: string;
1064
+
1065
+ @Column({ default: true })
1066
+ isActive: boolean;
1067
+
1068
+ @Column('jsonb', { nullable: true })
1069
+ metadata: Record<string, any>;
1070
+
1071
+ @CreateDateColumn()
1072
+ createdAt: Date;
1073
+
1074
+ @UpdateDateColumn()
1075
+ updatedAt: Date;
1076
+ }
1077
+
1078
+ // User entity example with JWT payload
1079
+ @Entity('users')
1080
+ export class User implements JwtPayload {
1081
+ @PrimaryGeneratedColumn('uuid')
1082
+ id: string;
1083
+
1084
+ @Column()
1085
+ email: string;
1086
+
1087
+ @Column('simple-array')
1088
+ roles: string[];
1089
+
1090
+ @Column('simple-array')
1091
+ permissions: string[];
1092
+
1093
+ @Column({ nullable: true })
1094
+ clientId?: string;
1095
+
1096
+ @Column({ nullable: true })
1097
+ providerId?: string;
1098
+
1099
+ @Column()
1100
+ firstName: string;
1101
+
1102
+ @Column()
1103
+ lastName: string;
1104
+
1105
+ @Column({ default: true })
1106
+ isActive: boolean;
1107
+
1108
+ @CreateDateColumn()
1109
+ createdAt: Date;
1110
+
1111
+ @UpdateDateColumn()
1112
+ updatedAt: Date;
1113
+ }
1114
+ ```
1115
+
1116
+ ### Integration with Auth Service
1117
+
1118
+ ```typescript
1119
+ // In your auth-service-contract
1120
+ @Injectable()
1121
+ export class AuthService {
1122
+ constructor(
1123
+ private readonly seeder: ContractXRolePermissionSeeder,
1124
+ private readonly authorizationService: ContractXAuthorizationService,
1125
+ private readonly validationService: ContractXValidationService,
1126
+ ) {}
1127
+
1128
+ async initializeSystem() {
1129
+ // Seed ODS roles and permissions
1130
+ await this.seeder.seed();
1131
+ }
1132
+
1133
+ async validateUserAccess(user: JwtPayload, requiredPermission: string) {
1134
+ return this.authorizationService.checkPermission(user, requiredPermission);
1135
+ }
1136
+
1137
+ async getUserAccessMatrix(user: JwtPayload) {
1138
+ return this.authorizationService.generateAccessMatrix(user);
1139
+ }
1140
+ }
1141
+ ```
1142
+
1143
+ ## ๐ŸŒ Environment Variables
1144
+
1145
+ | Variable | Description | Default | Required |
1146
+ |----------|-------------|---------|----------|
1147
+ | `JWT_SECRET` | JWT signing secret | - | โœ… Yes |
1148
+ | `JWT_ISSUER` | Token issuer | `contractx-api` | No |
1149
+ | `JWT_AUDIENCE` | Token audience | `contractx-users` | No |
1150
+ | `JWT_EXPIRES_IN` | Token expiration | `15m` | No |
1151
+ | `JWT_CLOCK_TOLERANCE` | Clock tolerance (seconds) | `0` | No |
1152
+ | `ENABLE_GLOBAL_AUTH` | Apply auth guard globally | `false` | No |
1153
+ | `ENABLE_GLOBAL_ROLES` | Apply roles guard globally | `false` | No |
1154
+ | `ENABLE_GLOBAL_PERMISSIONS` | Apply permissions guard globally | `false` | No |
1155
+ | `ENABLE_AUTH_LOGGING` | Enable security logging | `false` | No |
1156
+ | `DISABLE_AUTH` | Disable authentication | `false` | No |
1157
+
1158
+ ## ๐Ÿ”’ Security Best Practices
1159
+
1160
+ ### 1. JWT Token Structure
1161
+
1162
+ The package expects JWT tokens with this payload structure:
1163
+
1164
+ ```typescript
1165
+ interface JwtPayload {
1166
+ sub: string; // User ID
1167
+ role: string[]; // User roles
1168
+ permissions: string[]; // User permissions
1169
+ fullName: string; // User's full name
1170
+ email?: string; // User's email
1171
+ clientId?: string; // Organization/client ID
1172
+ sessionId?: string; // Session tracking
1173
+ iat?: number; // Issued at
1174
+ exp?: number; // Expires at
1175
+ }
1176
+ ```
1177
+
1178
+ ### 2. Environment Variables
1179
+
1180
+ ```env
1181
+ # Required
1182
+ JWT_SECRET=your-256-bit-secret-key-here
1183
+ JWT_ISSUER=your-api-name
1184
+ JWT_AUDIENCE=your-api-users
1185
+
1186
+ # Optional but recommended
1187
+ JWT_EXPIRES_IN=15m
1188
+ JWT_CLOCK_TOLERANCE=30
1189
+
1190
+ # Security
1191
+ ENABLE_AUTH_LOGGING=true
1192
+ ```
1193
+
1194
+ ### 3. Global Guards
1195
+
1196
+ ```typescript
1197
+ // For maximum security, enable global authentication
1198
+ PermissionsContractXModule.register({
1199
+ guards: {
1200
+ enableGlobalAuth: true, // All routes require auth by default
1201
+ enableGlobalRoles: false, // Only specific routes check roles
1202
+ enableGlobalPermissions: false, // Only specific routes check permissions
1203
+ },
1204
+ })
1205
+ ```
1206
+
1207
+ ## ๐Ÿงช Testing
1208
+
1209
+ ### Unit Testing
1210
+
1211
+ ```typescript
1212
+ import { Test } from '@nestjs/testing';
1213
+ import { JwtService } from '@nestjs/jwt';
1214
+ import { JwtAuthGuard } from 'permissions-contractx';
1215
+
1216
+ describe('Authentication', () => {
1217
+ let guard: JwtAuthGuard;
1218
+
1219
+ beforeEach(async () => {
1220
+ const module = await Test.createTestingModule({
1221
+ providers: [
1222
+ JwtAuthGuard,
1223
+ {
1224
+ provide: JwtService,
1225
+ useValue: { verifyAsync: jest.fn() },
1226
+ },
1227
+ // ... other providers
1228
+ ],
1229
+ }).compile();
1230
+
1231
+ guard = module.get(JwtAuthGuard);
1232
+ });
1233
+
1234
+ it('should authenticate valid token', async () => {
1235
+ // Test implementation
1236
+ });
1237
+ });
1238
+ ```
1239
+
1240
+ ### Integration Testing
1241
+
1242
+ ```typescript
1243
+ import * as request from 'supertest';
1244
+
1245
+ describe('Protected Routes', () => {
1246
+ it('should reject unauthenticated requests', () => {
1247
+ return request(app.getHttpServer())
1248
+ .get('/protected-route')
1249
+ .expect(401);
1250
+ });
1251
+
1252
+ it('should allow authenticated requests', () => {
1253
+ return request(app.getHttpServer())
1254
+ .get('/protected-route')
1255
+ .set('Authorization', `Bearer ${validToken}`)
1256
+ .expect(200);
1257
+ });
1258
+ });
1259
+ ```
1260
+
1261
+ ## ๐Ÿš€ Production Deployment
1262
+
1263
+ ### Docker Support
1264
+
1265
+ ```dockerfile
1266
+ FROM node:18-alpine
1267
+ WORKDIR /app
1268
+ COPY package*.json ./
1269
+ RUN npm ci --only=production
1270
+ COPY . .
1271
+ RUN npm run build
1272
+
1273
+ ENV NODE_ENV=production
1274
+ ENV JWT_SECRET=${JWT_SECRET}
1275
+ ENV JWT_ISSUER=contractx-production
1276
+
1277
+ EXPOSE 3000
1278
+ CMD ["npm", "run", "start:prod"]
1279
+ ```
1280
+
1281
+ ### Environment Configuration
1282
+
1283
+ ```yaml
1284
+ # docker-compose.yml
1285
+ version: '3.8'
1286
+ services:
1287
+ app:
1288
+ build: .
1289
+ environment:
1290
+ - NODE_ENV=production
1291
+ - JWT_SECRET=${JWT_SECRET}
1292
+ - JWT_ISSUER=contractx-api
1293
+ - JWT_AUDIENCE=contractx-users
1294
+ - ENABLE_AUTH_LOGGING=true
1295
+ ```
1296
+
1297
+ ## ๐Ÿ“– Examples
1298
+
1299
+ ### Complete Controller Example
1300
+
1301
+ ```typescript
1302
+ import {
1303
+ Controller,
1304
+ Get,
1305
+ Post,
1306
+ Put,
1307
+ Delete,
1308
+ Body,
1309
+ Param,
1310
+ UseGuards,
1311
+ } from '@nestjs/common';
1312
+ import {
1313
+ JwtAuthGuard,
1314
+ RolesGuard,
1315
+ PermissionsGuard,
1316
+ CurrentUser,
1317
+ Roles,
1318
+ RequirePermissions,
1319
+ Public,
1320
+ ClientOnly,
1321
+ AdminOnly,
1322
+ JwtPayload,
1323
+ } from 'permissions-contractx';
1324
+
1325
+ @Controller('contracts')
1326
+ @UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
1327
+ export class ContractsController {
1328
+
1329
+ @Public()
1330
+ @Get('health')
1331
+ getHealth() {
1332
+ return { status: 'OK' };
1333
+ }
1334
+
1335
+ @Get()
1336
+ @RequirePermissions('contracts.read', 'contracts.filter')
1337
+ async getContracts(@CurrentUser() user: JwtPayload) {
1338
+ // User must have both read AND filter permissions
1339
+ return { contracts: [], requestedBy: user.fullName };
1340
+ }
1341
+
1342
+ @Post()
1343
+ @ClientOnly()
1344
+ @RequirePermissions('contracts.create')
1345
+ async createContract(
1346
+ @Body() contractData: any,
1347
+ @CurrentUser() user: JwtPayload,
1348
+ ) {
1349
+ // Only client-side users with create permission
1350
+ return { id: '123', createdBy: user.sub };
1351
+ }
1352
+
1353
+ @Put(':id/approve')
1354
+ @AdminOnly()
1355
+ @RequirePermissions('contracts.approve')
1356
+ async approveContract(
1357
+ @Param('id') id: string,
1358
+ @CurrentUser() user: JwtPayload,
1359
+ ) {
1360
+ // Only admins with approval permission
1361
+ return { id, approvedBy: user.fullName, approvedAt: new Date() };
1362
+ }
1363
+
1364
+ @Delete(':id')
1365
+ @Roles('superadmin')
1366
+ async deleteContract(@Param('id') id: string) {
1367
+ // Only superadmin can delete
1368
+ return { message: `Contract ${id} deleted` };
1369
+ }
1370
+ }
1371
+ ```
1372
+
1373
+ ## ๐Ÿค Contributing
1374
+
1375
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
1376
+
1377
+ ## ๐Ÿ“„ License
1378
+
1379
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1380
+
1381
+ ## ๐Ÿ†˜ Support
1382
+
1383
+ - ๐Ÿ“ง Email: support@contractx.dev
1384
+ - ๐Ÿ› Issues: [GitHub Issues](https://github.com/your-org/permissions-contractx/issues)
1385
+ - ๐Ÿ“š Documentation: [Full Documentation](https://permissions-contractx.dev)
1386
+
1387
+ ## ๐Ÿ“Š Package Stats
1388
+
1389
+ - โœ… **Zero Dependencies** (only peer dependencies)
1390
+ - ๐Ÿš€ **TypeScript First** - Built with TypeScript for TypeScript
1391
+ - ๐Ÿ“ฆ **Tree Shakeable** - Only import what you need
1392
+ - ๐Ÿ”’ **Security Focused** - Built with security best practices
1393
+ - ๐Ÿงช **Well Tested** - Comprehensive test coverage
1394
+
1395
+ ---
1396
+
1397
+ Made with โค๏ธ by the ContractX Team