@flusys/nestjs-event-manager 3.0.1

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 (89) hide show
  1. package/README.md +1328 -0
  2. package/adapters/event-manager.adapter.d.ts +12 -0
  3. package/adapters/index.d.ts +1 -0
  4. package/cjs/adapters/event-manager.adapter.js +71 -0
  5. package/cjs/adapters/index.js +18 -0
  6. package/cjs/config/event-manager.constants.js +13 -0
  7. package/cjs/config/index.js +18 -0
  8. package/cjs/controllers/event-participant.controller.js +271 -0
  9. package/cjs/controllers/event.controller.js +229 -0
  10. package/cjs/controllers/index.js +19 -0
  11. package/cjs/docs/event-manager-swagger.config.js +135 -0
  12. package/cjs/docs/index.js +24 -0
  13. package/cjs/dtos/calendar-query.dto.js +186 -0
  14. package/cjs/dtos/event-participant.dto.js +226 -0
  15. package/cjs/dtos/event.dto.js +291 -0
  16. package/cjs/dtos/index.js +20 -0
  17. package/cjs/entities/event-participant.entity.js +96 -0
  18. package/cjs/entities/event-with-company.entity.js +56 -0
  19. package/cjs/entities/event.entity.js +143 -0
  20. package/cjs/entities/index.js +55 -0
  21. package/cjs/index.js +27 -0
  22. package/cjs/interfaces/event-manager-module.interface.js +4 -0
  23. package/cjs/interfaces/event.interface.js +4 -0
  24. package/cjs/interfaces/index.js +19 -0
  25. package/cjs/modules/event-manager.module.js +133 -0
  26. package/cjs/modules/index.js +18 -0
  27. package/cjs/services/event-manager-config.service.js +76 -0
  28. package/cjs/services/event-manager-datasource.provider.js +181 -0
  29. package/cjs/services/event-manager-helper.service.js +253 -0
  30. package/cjs/services/event-participant.service.js +164 -0
  31. package/cjs/services/event.service.js +421 -0
  32. package/cjs/services/index.js +22 -0
  33. package/config/event-manager.constants.d.ts +1 -0
  34. package/config/index.d.ts +1 -0
  35. package/controllers/event-participant.controller.d.ts +31 -0
  36. package/controllers/event.controller.d.ts +24 -0
  37. package/controllers/index.d.ts +2 -0
  38. package/docs/event-manager-swagger.config.d.ts +3 -0
  39. package/docs/index.d.ts +2 -0
  40. package/dtos/calendar-query.dto.d.ts +23 -0
  41. package/dtos/event-participant.dto.d.ts +31 -0
  42. package/dtos/event.dto.d.ts +37 -0
  43. package/dtos/index.d.ts +3 -0
  44. package/entities/event-participant.entity.d.ts +8 -0
  45. package/entities/event-with-company.entity.d.ts +4 -0
  46. package/entities/event.entity.d.ts +14 -0
  47. package/entities/index.d.ts +11 -0
  48. package/fesm/adapters/event-manager.adapter.js +61 -0
  49. package/fesm/adapters/index.js +1 -0
  50. package/fesm/config/event-manager.constants.js +3 -0
  51. package/fesm/config/index.js +1 -0
  52. package/fesm/controllers/event-participant.controller.js +261 -0
  53. package/fesm/controllers/event.controller.js +219 -0
  54. package/fesm/controllers/index.js +2 -0
  55. package/fesm/docs/event-manager-swagger.config.js +128 -0
  56. package/fesm/docs/index.js +4 -0
  57. package/fesm/dtos/calendar-query.dto.js +168 -0
  58. package/fesm/dtos/event-participant.dto.js +199 -0
  59. package/fesm/dtos/event.dto.js +270 -0
  60. package/fesm/dtos/index.js +3 -0
  61. package/fesm/entities/event-participant.entity.js +86 -0
  62. package/fesm/entities/event-with-company.entity.js +46 -0
  63. package/fesm/entities/event.entity.js +133 -0
  64. package/fesm/entities/index.js +24 -0
  65. package/fesm/index.js +10 -0
  66. package/fesm/interfaces/event-manager-module.interface.js +3 -0
  67. package/fesm/interfaces/event.interface.js +1 -0
  68. package/fesm/interfaces/index.js +2 -0
  69. package/fesm/modules/event-manager.module.js +123 -0
  70. package/fesm/modules/index.js +1 -0
  71. package/fesm/services/event-manager-config.service.js +66 -0
  72. package/fesm/services/event-manager-datasource.provider.js +130 -0
  73. package/fesm/services/event-manager-helper.service.js +243 -0
  74. package/fesm/services/event-participant.service.js +154 -0
  75. package/fesm/services/event.service.js +411 -0
  76. package/fesm/services/index.js +5 -0
  77. package/index.d.ts +9 -0
  78. package/interfaces/event-manager-module.interface.d.ts +20 -0
  79. package/interfaces/event.interface.d.ts +28 -0
  80. package/interfaces/index.d.ts +2 -0
  81. package/modules/event-manager.module.d.ts +8 -0
  82. package/modules/index.d.ts +1 -0
  83. package/package.json +89 -0
  84. package/services/event-manager-config.service.d.ts +13 -0
  85. package/services/event-manager-datasource.provider.d.ts +23 -0
  86. package/services/event-manager-helper.service.d.ts +27 -0
  87. package/services/event-participant.service.d.ts +27 -0
  88. package/services/event.service.d.ts +49 -0
  89. package/services/index.d.ts +5 -0
package/README.md ADDED
@@ -0,0 +1,1328 @@
1
+ # Event Manager Package Guide
2
+
3
+ > **Package:** `@flusys/nestjs-event-manager`
4
+ > **Version:** 3.0.1
5
+ > **Type:** Calendar event management with recurrence support and multi-tenant capabilities
6
+
7
+ This comprehensive guide covers the event manager package - calendar-based event scheduling with participants and recurrence patterns.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Overview](#overview)
12
+ - [Installation](#installation)
13
+ - [Constants](#constants)
14
+ - [Package Architecture](#package-architecture)
15
+ - [Module Setup](#module-setup)
16
+ - [Entities](#entities)
17
+ - [Services](#services)
18
+ - [Controllers](#controllers)
19
+ - [DTOs](#dtos)
20
+ - [Recurrence Handling](#recurrence-handling)
21
+ - [REST API Endpoints](#rest-api-endpoints)
22
+ - [DataSource Provider Pattern](#datasource-provider-pattern)
23
+ - [Multi-Tenant Support](#multi-tenant-support)
24
+ - [Swagger Configuration](#swagger-configuration)
25
+ - [Event Manager Adapter](#event-manager-adapter)
26
+ - [Best Practices](#best-practices)
27
+ - [API Reference](#api-reference)
28
+
29
+ ---
30
+
31
+ ## Overview
32
+
33
+ `@flusys/nestjs-event-manager` provides a comprehensive event management system:
34
+
35
+ - **Event CRUD** - Create, read, update, delete events with rich metadata
36
+ - **Recurrence Support** - Daily, weekly, biweekly, and monthly patterns
37
+ - **Participant Management** - Track event participants with status
38
+ - **Calendar Queries** - Date range queries with recurrence expansion
39
+ - **Adapter Pattern** - Cross-module event creation without direct dependencies
40
+ - **Company Scoping** - Per-company event isolation
41
+ - **Multi-Tenant Support** - Separate databases per tenant
42
+
43
+ ### Package Hierarchy
44
+
45
+ ```
46
+ @flusys/nestjs-core <- Foundation
47
+ |
48
+ @flusys/nestjs-shared <- Shared utilities
49
+ |
50
+ @flusys/nestjs-event-manager <- Event management (THIS PACKAGE)
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ npm install @flusys/nestjs-event-manager @flusys/nestjs-shared @flusys/nestjs-core
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Constants
64
+
65
+ ```typescript
66
+ // Injection Tokens
67
+ export const EVENT_MANAGER_MODULE_OPTIONS = 'EVENT_MANAGER_MODULE_OPTIONS';
68
+
69
+ // Adapter Token (from @flusys/nestjs-shared)
70
+ export const EVENT_MANAGER_ADAPTER = 'EVENT_MANAGER_ADAPTER';
71
+
72
+ // Permissions (from @flusys/nestjs-shared)
73
+ export const EVENT_PERMISSIONS = {
74
+ CREATE: 'event.create',
75
+ READ: 'event.read',
76
+ UPDATE: 'event.update',
77
+ DELETE: 'event.delete',
78
+ };
79
+
80
+ export const EVENT_PARTICIPANT_PERMISSIONS = {
81
+ CREATE: 'event_participant.create',
82
+ READ: 'event_participant.read',
83
+ UPDATE: 'event_participant.update',
84
+ DELETE: 'event_participant.delete',
85
+ };
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Package Architecture
91
+
92
+ ```
93
+ nestjs-event-manager/
94
+ ├── src/
95
+ │ ├── modules/
96
+ │ │ └── event-manager.module.ts # Main module with provider registration
97
+ │ │
98
+ │ ├── adapters/
99
+ │ │ ├── event-manager.adapter.ts # Adapter for cross-module usage
100
+ │ │ └── index.ts
101
+ │ │
102
+ │ ├── config/
103
+ │ │ ├── event-manager.constants.ts # Module constants
104
+ │ │ └── index.ts
105
+ │ │
106
+ │ ├── services/
107
+ │ │ ├── event.service.ts # Event CRUD + calendar queries
108
+ │ │ ├── event-participant.service.ts # Participant CRUD
109
+ │ │ ├── event-manager-config.service.ts # Module configuration
110
+ │ │ ├── event-manager-datasource.provider.ts # Dynamic entity loading
111
+ │ │ ├── event-manager-helper.service.ts # Helper for adapter (singleton)
112
+ │ │ └── index.ts
113
+ │ │
114
+ │ ├── controllers/
115
+ │ │ ├── event.controller.ts # /event-manager/event/*
116
+ │ │ ├── event-participant.controller.ts # /event-manager/participant/*
117
+ │ │ └── index.ts
118
+ │ │
119
+ │ ├── entities/
120
+ │ │ ├── event.entity.ts # Event base
121
+ │ │ ├── event-with-company.entity.ts # Event with company
122
+ │ │ ├── event-participant.entity.ts # Participant entity
123
+ │ │ └── index.ts
124
+ │ │
125
+ │ ├── dtos/
126
+ │ │ ├── event.dto.ts # Event DTOs
127
+ │ │ ├── event-participant.dto.ts # Participant DTOs
128
+ │ │ ├── calendar-query.dto.ts # Calendar query DTO
129
+ │ │ └── index.ts
130
+ │ │
131
+ │ ├── interfaces/
132
+ │ │ ├── event.interface.ts # IEvent, IEventParticipant, ICalendarEvent
133
+ │ │ ├── event-manager-module.interface.ts # Module options
134
+ │ │ └── index.ts
135
+ │ │
136
+ │ ├── enums/
137
+ │ │ └── index.ts # Re-exports from @flusys/nestjs-shared
138
+ │ │
139
+ │ ├── docs/
140
+ │ │ └── index.ts # Swagger config, permissions
141
+ │ │
142
+ │ └── index.ts # Main export file
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Module Setup
148
+
149
+ ### Basic Setup
150
+
151
+ ```typescript
152
+ import { Module } from '@nestjs/common';
153
+ import { EventManagerModule } from '@flusys/nestjs-event-manager';
154
+
155
+ @Module({
156
+ imports: [
157
+ EventManagerModule.forRoot({
158
+ global: true,
159
+ includeController: true,
160
+ bootstrapAppConfig: {
161
+ databaseMode: 'single',
162
+ enableCompanyFeature: false,
163
+ permissionMode: 'RBAC',
164
+ },
165
+ config: {
166
+ defaultDatabaseConfig: {
167
+ type: 'postgres',
168
+ host: 'localhost',
169
+ port: 5432,
170
+ username: 'postgres',
171
+ password: 'password',
172
+ database: 'myapp',
173
+ },
174
+ defaultColor: '#3B82F6',
175
+ maxRecurrenceOccurrences: 365,
176
+ },
177
+ }),
178
+ ],
179
+ })
180
+ export class AppModule {}
181
+ ```
182
+
183
+ ### With Company Feature
184
+
185
+ ```typescript
186
+ EventManagerModule.forRoot({
187
+ global: true,
188
+ includeController: true,
189
+ bootstrapAppConfig: {
190
+ databaseMode: 'single',
191
+ enableCompanyFeature: true,
192
+ permissionMode: 'FULL',
193
+ },
194
+ config: {
195
+ defaultDatabaseConfig: { /* ... */ },
196
+ defaultColor: '#3B82F6',
197
+ maxRecurrenceOccurrences: 365,
198
+ },
199
+ });
200
+ ```
201
+
202
+ ### Async Configuration
203
+
204
+ ```typescript
205
+ EventManagerModule.forRootAsync({
206
+ global: true,
207
+ includeController: true,
208
+ bootstrapAppConfig: {
209
+ databaseMode: 'single',
210
+ enableCompanyFeature: true,
211
+ permissionMode: 'FULL',
212
+ },
213
+ imports: [ConfigModule],
214
+ useFactory: async (configService: ConfigService) => ({
215
+ defaultDatabaseConfig: configService.getDatabaseConfig(),
216
+ defaultColor: configService.get('EVENT_DEFAULT_COLOR', '#3B82F6'),
217
+ maxRecurrenceOccurrences: configService.get('MAX_RECURRENCE', 365),
218
+ }),
219
+ inject: [ConfigService],
220
+ });
221
+ ```
222
+
223
+ ### Configuration Options
224
+
225
+ ```typescript
226
+ interface IEventManagerModuleConfig extends IDataSourceServiceOptions {
227
+ /** Default event color (default: '#3B82F6') */
228
+ defaultColor?: string;
229
+ /** Maximum recurrence occurrences to generate (default: 365) */
230
+ maxRecurrenceOccurrences?: number;
231
+ }
232
+
233
+ interface EventManagerModuleOptions extends IDynamicModuleConfig {
234
+ bootstrapAppConfig?: IBootstrapAppConfig;
235
+ config?: IEventManagerModuleConfig;
236
+ }
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Entities
242
+
243
+ ### Enums (from @flusys/nestjs-shared)
244
+
245
+ The enums are defined in `@flusys/nestjs-shared/enums` and re-exported from this package for convenience:
246
+
247
+ ```typescript
248
+ // Import from shared (canonical source)
249
+ import { RecurrenceType, ParticipantStatus } from '@flusys/nestjs-shared/enums';
250
+
251
+ // Or import from event-manager (re-export)
252
+ import { RecurrenceType, ParticipantStatus } from '@flusys/nestjs-event-manager/enums';
253
+ ```
254
+
255
+ **RecurrenceType:**
256
+
257
+ ```typescript
258
+ export enum RecurrenceType {
259
+ NONE = 'none',
260
+ DAILY = 'daily',
261
+ WEEKLY = 'weekly',
262
+ BIWEEKLY = 'biweekly',
263
+ MONTHLY = 'monthly',
264
+ }
265
+ ```
266
+
267
+ **ParticipantStatus:**
268
+
269
+ ```typescript
270
+ export enum ParticipantStatus {
271
+ PENDING = 'pending',
272
+ ACCEPTED = 'accepted',
273
+ DECLINED = 'declined',
274
+ TENTATIVE = 'tentative',
275
+ }
276
+ ```
277
+
278
+ ### Entity Groups
279
+
280
+ ```typescript
281
+ // Core entities (no company feature)
282
+ export const EventManagerCoreEntities = [Event, EventParticipant];
283
+
284
+ // Company-specific entities
285
+ export const EventManagerCompanyEntities = [EventWithCompany, EventParticipant];
286
+
287
+ // Helper function
288
+ export function getEventManagerEntitiesByConfig(enableCompanyFeature: boolean): any[] {
289
+ return enableCompanyFeature ? EventManagerCompanyEntities : EventManagerCoreEntities;
290
+ }
291
+
292
+ // Base type aliases
293
+ export { Event as EventBase } from './event.entity';
294
+ export { EventParticipant as EventParticipantBase } from './event-participant.entity';
295
+ ```
296
+
297
+ ### Event Entity
298
+
299
+ ```typescript
300
+ @Entity({ name: 'event' })
301
+ @Index(['startDateTime', 'endDateTime'])
302
+ @Index(['isActive'])
303
+ export class Event extends Identity {
304
+ @Column({ type: 'varchar', length: 255 })
305
+ title!: string;
306
+
307
+ @Column({ type: 'text', nullable: true })
308
+ description!: string | null;
309
+
310
+ @Column({ type: 'varchar', length: 500, nullable: true })
311
+ meetingLink!: string | null;
312
+
313
+ @Column({ type: 'timestamp' })
314
+ @Index()
315
+ startDateTime!: Date;
316
+
317
+ @Column({ type: 'timestamp' })
318
+ endDateTime!: Date;
319
+
320
+ @Column({ type: 'boolean', default: false })
321
+ isAllDay!: boolean;
322
+
323
+ @Column({ type: 'varchar', length: 20, default: 'none' })
324
+ @Index()
325
+ recurrenceType!: string;
326
+
327
+ @Column({ type: 'timestamp', nullable: true })
328
+ recurrenceEndDate!: Date | null;
329
+
330
+ @Column({ type: 'varchar', length: 7, default: '#3B82F6' })
331
+ color!: string;
332
+
333
+ @Column({ type: 'boolean', default: true })
334
+ isActive!: boolean;
335
+
336
+ @Column({ type: 'simple-json', nullable: true })
337
+ metadata!: Record<string, unknown> | null;
338
+ }
339
+
340
+ // With company feature
341
+ @Entity({ name: 'event' })
342
+ @Index(['companyId', 'isActive'])
343
+ export class EventWithCompany extends Event {
344
+ @Column({ type: 'uuid', nullable: true })
345
+ companyId!: string | null;
346
+ }
347
+ ```
348
+
349
+ ### EventParticipant Entity
350
+
351
+ ```typescript
352
+ @Entity({ name: 'event_participant' })
353
+ @Index(['eventId'])
354
+ @Index(['userId'])
355
+ @Index(['eventId', 'userId'], { unique: true })
356
+ export class EventParticipant extends Identity {
357
+ @Column({ type: 'uuid' })
358
+ eventId!: string;
359
+
360
+ @Column({ type: 'uuid' })
361
+ userId!: string;
362
+
363
+ @Column({ type: 'varchar', length: 50, default: 'pending' })
364
+ status!: string;
365
+
366
+ @Column({ type: 'boolean', default: false })
367
+ isOrganizer!: boolean;
368
+
369
+ @Column({ type: 'simple-json', nullable: true })
370
+ metadata!: Record<string, unknown> | null;
371
+ }
372
+ ```
373
+
374
+ **Note:** EventParticipant does NOT have a company variant - company context is inherited through the Event relationship.
375
+
376
+ ---
377
+
378
+ ## Services
379
+
380
+ ### EventService
381
+
382
+ Handles event CRUD and calendar queries.
383
+
384
+ ```typescript
385
+ @Injectable({ scope: Scope.REQUEST })
386
+ export class EventService extends RequestScopedApiService<
387
+ CreateEventDto,
388
+ UpdateEventDto,
389
+ IEvent,
390
+ EventBase,
391
+ Repository<EventBase>
392
+ > {
393
+ // Standard CRUD methods inherited
394
+
395
+ /** Get events for calendar date range with recurrence expansion */
396
+ async getEventsForCalendarRange(
397
+ dto: CalendarQueryDto,
398
+ user?: ILoggedUserInfo
399
+ ): Promise<ICalendarEvent[]>;
400
+
401
+ /** Get event with participant list */
402
+ async getEventWithParticipants(
403
+ eventId: string,
404
+ user?: ILoggedUserInfo
405
+ ): Promise<EventBase | null>;
406
+
407
+ /** Add participants to event */
408
+ async addParticipants(
409
+ dto: BulkAddParticipantsDto,
410
+ user?: ILoggedUserInfo
411
+ ): Promise<EventParticipantBase[]>;
412
+ }
413
+ ```
414
+
415
+ **Key Features:**
416
+ - Dynamic entity resolution (Event vs EventWithCompany)
417
+ - Automatic participant creation on event insert
418
+ - Recurrence expansion for calendar queries
419
+ - Company filtering when enabled
420
+
421
+ ### EventParticipantService
422
+
423
+ Handles participant CRUD.
424
+
425
+ ```typescript
426
+ @Injectable({ scope: Scope.REQUEST })
427
+ export class EventParticipantService extends RequestScopedApiService<
428
+ CreateEventParticipantDto,
429
+ UpdateEventParticipantDto,
430
+ IEventParticipant,
431
+ EventParticipantBase,
432
+ Repository<EventParticipantBase>
433
+ > {
434
+ // Standard CRUD methods inherited
435
+
436
+ /** Update participant status */
437
+ async updateStatus(
438
+ dto: UpdateParticipantStatusDto,
439
+ user?: ILoggedUserInfo
440
+ ): Promise<EventParticipantBase>;
441
+
442
+ /** Get participants for event */
443
+ async getParticipantsByEvent(eventId: string): Promise<EventParticipantBase[]>;
444
+
445
+ /** Get user's participations */
446
+ async getParticipantsByUser(userId: string): Promise<EventParticipantBase[]>;
447
+
448
+ /** Remove participant from event */
449
+ async removeParticipant(
450
+ eventId: string,
451
+ userId: string,
452
+ user?: ILoggedUserInfo
453
+ ): Promise<void>;
454
+ }
455
+ ```
456
+
457
+ ### EventManagerConfigService
458
+
459
+ Module configuration service.
460
+
461
+ ```typescript
462
+ @Injectable()
463
+ export class EventManagerConfigService implements IModuleConfigService {
464
+ /** Check if company feature is enabled */
465
+ isCompanyFeatureEnabled(): boolean;
466
+
467
+ /** Get database mode */
468
+ getDatabaseMode(): 'single' | 'multi-tenant';
469
+
470
+ /** Check if multi-tenant mode */
471
+ isMultiTenant(): boolean;
472
+
473
+ /** Get default event color */
474
+ getDefaultColor(): string;
475
+
476
+ /** Get max recurrence occurrences */
477
+ getMaxRecurrenceOccurrences(): number;
478
+ }
479
+ ```
480
+
481
+ ### EventManagerDataSourceProvider
482
+
483
+ Dynamic entity loading with isolated cache.
484
+
485
+ ```typescript
486
+ @Injectable({ scope: Scope.REQUEST })
487
+ export class EventManagerDataSourceProvider extends MultiTenantDataSourceService {
488
+ // Static cache isolated from other modules
489
+ protected static override readonly tenantConnections = new Map<string, DataSource>();
490
+ protected static override singleDataSource: DataSource | null = null;
491
+
492
+ /** Get entities based on company feature */
493
+ async getEventManagerEntities(enableCompanyFeature?: boolean): Promise<any[]>;
494
+
495
+ /** Get company feature for current tenant */
496
+ getEnableCompanyFeatureForCurrentTenant(): boolean;
497
+ }
498
+ ```
499
+
500
+ ---
501
+
502
+ ## Controllers
503
+
504
+ ### EventController
505
+
506
+ Base path: `/event-manager/event`
507
+
508
+ ```typescript
509
+ @Controller('event-manager/event')
510
+ @ApiTags('Event Manager - Events')
511
+ @ApiBearerAuth()
512
+ export class EventController extends createApiController<
513
+ CreateEventDto,
514
+ UpdateEventDto,
515
+ EventResponseDto,
516
+ IEvent,
517
+ EventService
518
+ >() {
519
+ // Inherited CRUD endpoints with permissions
520
+
521
+ @Post('calendar')
522
+ @UseGuards(JwtAuthGuard)
523
+ @RequirePermission(EVENT_PERMISSIONS.READ)
524
+ async getCalendarEvents(@Body() dto: CalendarQueryDto, @CurrentUser() user): Promise<ListResponseDto>;
525
+
526
+ @Post('get-with-participants')
527
+ @UseGuards(JwtAuthGuard)
528
+ @RequirePermission(EVENT_PERMISSIONS.READ)
529
+ async getWithParticipants(@Body() dto: { id: string }, @CurrentUser() user): Promise<SingleResponseDto>;
530
+
531
+ @Post('add-participants')
532
+ @UseGuards(JwtAuthGuard)
533
+ @RequirePermission(EVENT_PERMISSIONS.UPDATE)
534
+ async addParticipants(@Body() dto: BulkAddParticipantsDto, @CurrentUser() user): Promise<SingleResponseDto>;
535
+ }
536
+ ```
537
+
538
+ ### EventParticipantController
539
+
540
+ Base path: `/event-manager/participant`
541
+
542
+ ```typescript
543
+ @Controller('event-manager/participant')
544
+ @ApiTags('Event Manager - Participants')
545
+ @ApiBearerAuth()
546
+ export class EventParticipantController extends createApiController<...>() {
547
+ // Inherited CRUD endpoints with permissions
548
+
549
+ @Post('update-status')
550
+ @UseGuards(JwtAuthGuard)
551
+ @RequirePermission(EVENT_PARTICIPANT_PERMISSIONS.UPDATE)
552
+ async updateStatus(@Body() dto: UpdateParticipantStatusDto, @CurrentUser() user): Promise<SingleResponseDto>;
553
+
554
+ @Post('get-by-event')
555
+ @UseGuards(JwtAuthGuard)
556
+ @RequirePermission(EVENT_PARTICIPANT_PERMISSIONS.READ)
557
+ async getByEvent(@Body() dto: { eventId: string }): Promise<ListResponseDto>;
558
+
559
+ @Post('get-by-user')
560
+ @UseGuards(JwtAuthGuard)
561
+ @RequirePermission(EVENT_PARTICIPANT_PERMISSIONS.READ)
562
+ async getByUser(@Body() dto: { userId: string }): Promise<ListResponseDto>;
563
+
564
+ @Post('remove')
565
+ @UseGuards(JwtAuthGuard)
566
+ @RequirePermission(EVENT_PARTICIPANT_PERMISSIONS.DELETE)
567
+ async remove(@Body() dto: { eventId: string; userId: string }, @CurrentUser() user): Promise<MessageResponseDto>;
568
+ }
569
+ ```
570
+
571
+ ---
572
+
573
+ ## DTOs
574
+
575
+ ### CreateEventDto
576
+
577
+ ```typescript
578
+ export class CreateEventDto {
579
+ @IsNotEmpty()
580
+ @IsString()
581
+ @MaxLength(255)
582
+ title!: string;
583
+
584
+ @IsOptional()
585
+ @IsString()
586
+ description?: string;
587
+
588
+ @IsOptional()
589
+ @IsString()
590
+ @MaxLength(500)
591
+ meetingLink?: string;
592
+
593
+ @IsNotEmpty()
594
+ @IsDateString()
595
+ startDateTime!: Date;
596
+
597
+ @IsNotEmpty()
598
+ @IsDateString()
599
+ endDateTime!: Date;
600
+
601
+ @IsOptional()
602
+ @IsBoolean()
603
+ isAllDay?: boolean;
604
+
605
+ @IsOptional()
606
+ @IsEnum(RecurrenceType)
607
+ recurrenceType?: RecurrenceType;
608
+
609
+ @IsOptional()
610
+ @IsDateString()
611
+ recurrenceEndDate?: Date;
612
+
613
+ @IsOptional()
614
+ @IsString()
615
+ @MaxLength(7)
616
+ color?: string;
617
+
618
+ @IsOptional()
619
+ @IsBoolean()
620
+ isActive?: boolean;
621
+
622
+ @IsOptional()
623
+ metadata?: Record<string, unknown>;
624
+
625
+ @IsOptional()
626
+ @IsUUID('4', { each: true })
627
+ participantIds?: string[];
628
+ }
629
+ ```
630
+
631
+ ### UpdateEventDto
632
+
633
+ ```typescript
634
+ export class UpdateEventDto extends PartialType(CreateEventDto) {
635
+ @IsUUID()
636
+ @IsNotEmpty()
637
+ id!: string;
638
+ }
639
+ ```
640
+
641
+ ### CalendarQueryDto
642
+
643
+ ```typescript
644
+ export class CalendarQueryDto {
645
+ @IsNotEmpty()
646
+ @IsDateString()
647
+ startDate!: Date;
648
+
649
+ @IsNotEmpty()
650
+ @IsDateString()
651
+ endDate!: Date;
652
+
653
+ @IsOptional()
654
+ @IsBoolean()
655
+ includeParticipants?: boolean;
656
+
657
+ @IsOptional()
658
+ @IsUUID()
659
+ userId?: string;
660
+
661
+ @IsOptional()
662
+ @IsBoolean()
663
+ activeOnly?: boolean;
664
+ }
665
+ ```
666
+
667
+ ### CreateEventParticipantDto
668
+
669
+ ```typescript
670
+ export class CreateEventParticipantDto {
671
+ @IsNotEmpty()
672
+ @IsUUID()
673
+ eventId!: string;
674
+
675
+ @IsNotEmpty()
676
+ @IsUUID()
677
+ userId!: string;
678
+
679
+ @IsOptional()
680
+ @IsEnum(ParticipantStatus)
681
+ status?: ParticipantStatus;
682
+
683
+ @IsOptional()
684
+ @IsBoolean()
685
+ isOrganizer?: boolean;
686
+
687
+ @IsOptional()
688
+ metadata?: Record<string, unknown>;
689
+ }
690
+ ```
691
+
692
+ ### UpdateParticipantStatusDto
693
+
694
+ ```typescript
695
+ export class UpdateParticipantStatusDto {
696
+ @IsUUID()
697
+ @IsNotEmpty()
698
+ id!: string;
699
+
700
+ @IsNotEmpty()
701
+ @IsEnum(ParticipantStatus)
702
+ status!: ParticipantStatus;
703
+ }
704
+ ```
705
+
706
+ ### BulkAddParticipantsDto
707
+
708
+ ```typescript
709
+ export class BulkAddParticipantsDto {
710
+ @IsNotEmpty()
711
+ @IsUUID()
712
+ eventId!: string;
713
+
714
+ @IsNotEmpty()
715
+ @IsUUID('4', { each: true })
716
+ userIds!: string[];
717
+ }
718
+ ```
719
+
720
+ ---
721
+
722
+ ## Recurrence Handling
723
+
724
+ ### How Recurrence Works
725
+
726
+ 1. **Storage:** Events store recurrence pattern in `recurrenceType` and optional `recurrenceEndDate`
727
+ 2. **Metadata:** Weekly recurrence uses `metadata.recurrenceDays` array (0=Sunday, 6=Saturday)
728
+ 3. **Expansion:** Calendar queries expand recurring events into individual instances
729
+ 4. **Instance Markers:** Expanded instances have `isRecurrenceInstance: true` and `originalEventId`
730
+
731
+ ### Recurrence Expansion Logic
732
+
733
+ ```typescript
734
+ private generateOccurrences(
735
+ event: EventBase,
736
+ rangeStart: Date,
737
+ rangeEnd: Date
738
+ ): ICalendarEvent[] {
739
+ const occurrences: ICalendarEvent[] = [];
740
+ const recurrenceEnd = event.recurrenceEndDate || rangeEnd;
741
+ const maxOccurrences = this.eventConfig.getMaxRecurrenceOccurrences();
742
+
743
+ let currentDate = new Date(event.startDateTime);
744
+
745
+ while (currentDate <= recurrenceEnd && occurrences.length < maxOccurrences) {
746
+ if (currentDate >= rangeStart && currentDate <= rangeEnd) {
747
+ occurrences.push(this.createOccurrence(event, currentDate));
748
+ }
749
+
750
+ // Advance based on recurrence type
751
+ switch (event.recurrenceType) {
752
+ case RecurrenceType.DAILY:
753
+ currentDate.setDate(currentDate.getDate() + 1);
754
+ break;
755
+ case RecurrenceType.WEEKLY:
756
+ currentDate = this.getNextWeeklyOccurrence(event, currentDate);
757
+ break;
758
+ case RecurrenceType.BIWEEKLY:
759
+ currentDate.setDate(currentDate.getDate() + 14);
760
+ break;
761
+ case RecurrenceType.MONTHLY:
762
+ currentDate.setMonth(currentDate.getMonth() + 1);
763
+ break;
764
+ }
765
+ }
766
+
767
+ return occurrences;
768
+ }
769
+ ```
770
+
771
+ ### Weekly Recurrence with Specific Days
772
+
773
+ ```typescript
774
+ // Event with recurrence on Mon, Wed, Fri
775
+ const event = await eventService.insert({
776
+ title: 'Team Standup',
777
+ startDateTime: new Date('2026-03-02T09:00:00'),
778
+ endDateTime: new Date('2026-03-02T09:30:00'),
779
+ recurrenceType: RecurrenceType.WEEKLY,
780
+ recurrenceEndDate: new Date('2026-06-30'),
781
+ metadata: {
782
+ recurrenceDays: [1, 3, 5], // Monday, Wednesday, Friday
783
+ },
784
+ }, user);
785
+ ```
786
+
787
+ ---
788
+
789
+ ## REST API Endpoints
790
+
791
+ All event manager endpoints are prefixed with `/event-manager`.
792
+
793
+ ### Event Endpoints
794
+
795
+ | Endpoint | Method | Description | Permission |
796
+ |----------|--------|-------------|------------|
797
+ | `/event-manager/event/insert` | POST | Create event | `event.create` |
798
+ | `/event-manager/event/insert-many` | POST | Bulk create | `event.create` |
799
+ | `/event-manager/event/get/:id` | POST | Get by ID | `event.read` |
800
+ | `/event-manager/event/get-all` | POST | List with pagination | `event.read` |
801
+ | `/event-manager/event/update` | POST | Update event | `event.update` |
802
+ | `/event-manager/event/update-many` | POST | Bulk update | `event.update` |
803
+ | `/event-manager/event/delete` | POST | Soft delete | `event.delete` |
804
+ | `/event-manager/event/calendar` | POST | Calendar query with expansion | `event.read` |
805
+ | `/event-manager/event/get-with-participants` | POST | Get with participant list | `event.read` |
806
+ | `/event-manager/event/add-participants` | POST | Add participants | `event.update` |
807
+
808
+ ### Participant Endpoints
809
+
810
+ | Endpoint | Method | Description | Permission |
811
+ |----------|--------|-------------|------------|
812
+ | `/event-manager/participant/insert` | POST | Create participant | `event_participant.create` |
813
+ | `/event-manager/participant/insert-many` | POST | Bulk create | `event_participant.create` |
814
+ | `/event-manager/participant/get/:id` | POST | Get by ID | `event_participant.read` |
815
+ | `/event-manager/participant/get-all` | POST | List with pagination | `event_participant.read` |
816
+ | `/event-manager/participant/update` | POST | Update participant | `event_participant.update` |
817
+ | `/event-manager/participant/update-many` | POST | Bulk update | `event_participant.update` |
818
+ | `/event-manager/participant/delete` | POST | Soft delete | `event_participant.delete` |
819
+ | `/event-manager/participant/update-status` | POST | Update status | `event_participant.update` |
820
+ | `/event-manager/participant/get-by-event` | POST | Get by event | `event_participant.read` |
821
+ | `/event-manager/participant/get-by-user` | POST | Get by user | `event_participant.read` |
822
+ | `/event-manager/participant/remove` | POST | Remove from event | `event_participant.delete` |
823
+
824
+ ### Request/Response Examples
825
+
826
+ **Create Event:**
827
+
828
+ ```bash
829
+ curl -X POST http://localhost:2002/event-manager/event/insert \
830
+ -H "Authorization: Bearer <token>" \
831
+ -H "Content-Type: application/json" \
832
+ -d '{
833
+ "title": "Team Meeting",
834
+ "description": "Weekly sync",
835
+ "startDateTime": "2026-03-01T10:00:00Z",
836
+ "endDateTime": "2026-03-01T11:00:00Z",
837
+ "recurrenceType": "weekly",
838
+ "recurrenceEndDate": "2026-06-01T00:00:00Z",
839
+ "metadata": { "recurrenceDays": [1, 3, 5] },
840
+ "participantIds": ["user-id-1", "user-id-2"],
841
+ "color": "#3B82F6"
842
+ }'
843
+
844
+ # Response:
845
+ {
846
+ "success": true,
847
+ "message": "Event created successfully",
848
+ "data": {
849
+ "id": "event-uuid",
850
+ "title": "Team Meeting",
851
+ "startDateTime": "2026-03-01T10:00:00.000Z",
852
+ "recurrenceType": "weekly",
853
+ ...
854
+ }
855
+ }
856
+ ```
857
+
858
+ **Calendar Query:**
859
+
860
+ ```bash
861
+ curl -X POST http://localhost:2002/event-manager/event/calendar \
862
+ -H "Authorization: Bearer <token>" \
863
+ -H "Content-Type: application/json" \
864
+ -d '{
865
+ "startDate": "2026-03-01",
866
+ "endDate": "2026-03-31",
867
+ "includeParticipants": true,
868
+ "activeOnly": true
869
+ }'
870
+
871
+ # Response includes expanded recurring events
872
+ {
873
+ "success": true,
874
+ "data": [
875
+ {
876
+ "id": "event-uuid",
877
+ "title": "Team Meeting",
878
+ "startDateTime": "2026-03-03T10:00:00.000Z",
879
+ "isRecurrenceInstance": true,
880
+ "originalEventId": "event-uuid",
881
+ "participants": [...]
882
+ },
883
+ {
884
+ "id": "event-uuid",
885
+ "title": "Team Meeting",
886
+ "startDateTime": "2026-03-05T10:00:00.000Z",
887
+ "isRecurrenceInstance": true,
888
+ "originalEventId": "event-uuid",
889
+ "participants": [...]
890
+ },
891
+ ...
892
+ ],
893
+ "meta": { "total": 15, "page": 1, "pageSize": 100, "count": 15 }
894
+ }
895
+ ```
896
+
897
+ ---
898
+
899
+ ## DataSource Provider Pattern
900
+
901
+ ### EventManagerDataSourceProvider
902
+
903
+ The EventManagerDataSourceProvider follows the isolated cache pattern:
904
+
905
+ ```typescript
906
+ @Injectable({ scope: Scope.REQUEST })
907
+ export class EventManagerDataSourceProvider extends MultiTenantDataSourceService {
908
+ // Isolated static cache per module
909
+ protected static override readonly tenantConnections = new Map<string, DataSource>();
910
+ protected static override singleDataSource: DataSource | null = null;
911
+ protected static override tenantsRegistry: ITenant[] = [];
912
+ protected static override initialized = false;
913
+ protected static override connectionLocks = new Map<string, Promise<DataSource>>();
914
+ protected static override singleConnectionLock: Promise<DataSource> | null = null;
915
+
916
+ constructor(
917
+ @Inject(EventManagerConfigService) private readonly configService: EventManagerConfigService,
918
+ @Optional() @Inject(REQUEST) protected override readonly request?: Request,
919
+ ) {
920
+ super(configService, request);
921
+ }
922
+
923
+ async getEventManagerEntities(enableCompanyFeature?: boolean): Promise<any[]> {
924
+ const featureEnabled = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
925
+ return getEventManagerEntitiesByConfig(featureEnabled);
926
+ }
927
+
928
+ // Override methods to use EventManagerDataSourceProvider's static cache
929
+ protected override async getSingleDataSource(): Promise<DataSource> {
930
+ // Uses EventManagerDataSourceProvider.singleDataSource
931
+ }
932
+
933
+ protected override async getOrCreateTenantConnection(tenant: ITenant): Promise<DataSource> {
934
+ // Uses EventManagerDataSourceProvider.tenantConnections
935
+ }
936
+ }
937
+ ```
938
+
939
+ ---
940
+
941
+ ## Multi-Tenant Support
942
+
943
+ ### Company Filtering
944
+
945
+ When company feature is enabled:
946
+
947
+ ```typescript
948
+ protected override async getExtraManipulateQuery(query, filterDto, user) {
949
+ const result = await super.getExtraManipulateQuery(query, filterDto, user);
950
+
951
+ applyCompanyFilter(query, {
952
+ isCompanyFeatureEnabled: this.eventConfig.isCompanyFeatureEnabled(),
953
+ entityAlias: 'event',
954
+ }, user);
955
+
956
+ return result;
957
+ }
958
+ ```
959
+
960
+ ### DTO to Entity Conversion
961
+
962
+ ```typescript
963
+ protected override async convertSingleDtoToEntity(dto, user): Promise<Partial<EventBase>> {
964
+ const entity = await super.convertSingleDtoToEntity(dto, user);
965
+
966
+ if (this.eventConfig.isCompanyFeatureEnabled() && user?.companyId) {
967
+ (entity as Partial<EventWithCompany>).companyId = user.companyId;
968
+ }
969
+
970
+ return entity;
971
+ }
972
+ ```
973
+
974
+ ---
975
+
976
+ ## Swagger Configuration
977
+
978
+ ### Using eventManagerSwaggerConfig
979
+
980
+ ```typescript
981
+ import { eventManagerSwaggerConfig } from '@flusys/nestjs-event-manager/docs';
982
+
983
+ // In your main.ts or app module
984
+ const swaggerOptions = eventManagerSwaggerConfig({
985
+ enableCompanyFeature: true,
986
+ databaseMode: 'single',
987
+ });
988
+
989
+ // Returns:
990
+ // {
991
+ // title: 'Event Manager API',
992
+ // description: '... dynamic description based on config ...',
993
+ // version: '1.0',
994
+ // path: 'api/docs/event-manager',
995
+ // bearerAuth: true,
996
+ // }
997
+ ```
998
+
999
+ ---
1000
+
1001
+ ## Event Manager Adapter
1002
+
1003
+ The Event Manager Adapter allows other modules to create events and manage participants without direct dependencies on the event manager module.
1004
+
1005
+ ### Interface (from @flusys/nestjs-shared)
1006
+
1007
+ ```typescript
1008
+ import { ParticipantStatus, RecurrenceType } from '@flusys/nestjs-shared/enums';
1009
+
1010
+ export interface IEventManagerAdapter {
1011
+ createEvent(options: CreateEventOptions): Promise<EventResult>;
1012
+ addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
1013
+ removeParticipant(eventId: string, userId: string): Promise<void>;
1014
+ updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
1015
+ getEventsForUser?(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
1016
+ getEventById?(eventId: string): Promise<EventResult | null>;
1017
+ }
1018
+
1019
+ export interface CreateEventOptions {
1020
+ title: string;
1021
+ description?: string;
1022
+ meetingLink?: string;
1023
+ startDateTime: Date;
1024
+ endDateTime: Date;
1025
+ isAllDay?: boolean;
1026
+ recurrenceType?: RecurrenceType;
1027
+ recurrenceEndDate?: Date;
1028
+ color?: string;
1029
+ metadata?: Record<string, unknown>;
1030
+ participantIds?: string[];
1031
+ organizerId?: string;
1032
+ companyId?: string;
1033
+ }
1034
+
1035
+ export interface EventResult {
1036
+ id: string;
1037
+ title: string;
1038
+ description?: string | null;
1039
+ meetingLink?: string | null;
1040
+ startDateTime: Date;
1041
+ endDateTime: Date;
1042
+ isAllDay: boolean;
1043
+ recurrenceType: string;
1044
+ recurrenceEndDate?: Date | null;
1045
+ color: string;
1046
+ isActive: boolean;
1047
+ metadata?: Record<string, unknown> | null;
1048
+ companyId?: string | null;
1049
+ createdAt: Date;
1050
+ updatedAt: Date;
1051
+ }
1052
+
1053
+ export const EVENT_MANAGER_ADAPTER = 'EVENT_MANAGER_ADAPTER';
1054
+ ```
1055
+
1056
+ ### Using the Adapter in Other Modules
1057
+
1058
+ ```typescript
1059
+ import { Injectable, Inject, Optional } from '@nestjs/common';
1060
+ import {
1061
+ EVENT_MANAGER_ADAPTER,
1062
+ IEventManagerAdapter,
1063
+ RecurrenceType,
1064
+ } from '@flusys/nestjs-shared';
1065
+
1066
+ @Injectable()
1067
+ export class MyService {
1068
+ constructor(
1069
+ @Optional() @Inject(EVENT_MANAGER_ADAPTER)
1070
+ private readonly eventAdapter?: IEventManagerAdapter,
1071
+ ) {}
1072
+
1073
+ async createMeetingEvent(userId: string, companyId?: string) {
1074
+ if (!this.eventAdapter) {
1075
+ console.warn('Event manager not available');
1076
+ return;
1077
+ }
1078
+
1079
+ const event = await this.eventAdapter.createEvent({
1080
+ title: 'Team Meeting',
1081
+ description: 'Weekly sync meeting',
1082
+ startDateTime: new Date(),
1083
+ endDateTime: new Date(Date.now() + 3600000), // 1 hour later
1084
+ recurrenceType: RecurrenceType.WEEKLY,
1085
+ participantIds: [userId],
1086
+ organizerId: userId,
1087
+ companyId,
1088
+ });
1089
+
1090
+ return event;
1091
+ }
1092
+
1093
+ async inviteToEvent(eventId: string, userIds: string[]) {
1094
+ if (this.eventAdapter) {
1095
+ await this.eventAdapter.addParticipants(eventId, userIds);
1096
+ }
1097
+ }
1098
+ }
1099
+ ```
1100
+
1101
+ ### Module Registration Order
1102
+
1103
+ **Important:** The `EventManagerModule` must be imported BEFORE any module that injects the adapter:
1104
+
1105
+ ```typescript
1106
+ @Module({
1107
+ imports: [
1108
+ // EventManagerModule FIRST
1109
+ EventManagerModule.forRoot({
1110
+ global: true,
1111
+ // ...config
1112
+ }),
1113
+
1114
+ // Modules that use the adapter AFTER
1115
+ MyFeatureModule,
1116
+ ],
1117
+ })
1118
+ export class AppModule {}
1119
+ ```
1120
+
1121
+ ### Adapter Methods
1122
+
1123
+ | Method | Description |
1124
+ |--------|-------------|
1125
+ | `createEvent(options)` | Create a new event with optional participants |
1126
+ | `addParticipants(eventId, userIds)` | Add users as participants to an event |
1127
+ | `removeParticipant(eventId, userId)` | Remove a user from an event |
1128
+ | `updateParticipantStatus(participantId, status)` | Update RSVP status |
1129
+ | `getEventsForUser(userId, startDate, endDate)` | Get user's events in date range |
1130
+ | `getEventById(eventId)` | Get a single event by ID |
1131
+
1132
+ ### Helper Service
1133
+
1134
+ The adapter delegates to `EventManagerHelperService`, a singleton service that handles the actual business logic:
1135
+
1136
+ ```typescript
1137
+ @Injectable()
1138
+ export class EventManagerHelperService {
1139
+ async createEvent(options: CreateEventOptions): Promise<EventResult>;
1140
+ async addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
1141
+ async removeParticipant(eventId: string, userId: string): Promise<void>;
1142
+ async updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
1143
+ async getEventsForUser(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
1144
+ async getEventById(eventId: string): Promise<EventResult | null>;
1145
+ }
1146
+ ```
1147
+
1148
+ ---
1149
+
1150
+ ## Best Practices
1151
+
1152
+ ### 1. Use Proper Recurrence Patterns
1153
+
1154
+ ```typescript
1155
+ // Daily standup
1156
+ await eventService.insert({
1157
+ title: 'Daily Standup',
1158
+ recurrenceType: RecurrenceType.DAILY,
1159
+ recurrenceEndDate: new Date('2026-12-31'),
1160
+ }, user);
1161
+
1162
+ // Weekly on specific days
1163
+ await eventService.insert({
1164
+ title: 'Team Sync',
1165
+ recurrenceType: RecurrenceType.WEEKLY,
1166
+ metadata: { recurrenceDays: [1, 4] }, // Monday, Thursday
1167
+ }, user);
1168
+
1169
+ // Monthly meeting
1170
+ await eventService.insert({
1171
+ title: 'Monthly Review',
1172
+ recurrenceType: RecurrenceType.MONTHLY,
1173
+ }, user);
1174
+ ```
1175
+
1176
+ ### 2. Query Calendar Efficiently
1177
+
1178
+ ```typescript
1179
+ // Only fetch what you need
1180
+ const events = await eventService.getEventsForCalendarRange({
1181
+ startDate: monthStart,
1182
+ endDate: monthEnd,
1183
+ includeParticipants: false, // Only include if needed
1184
+ activeOnly: true,
1185
+ }, user);
1186
+ ```
1187
+
1188
+ ### 3. Handle Participant Status
1189
+
1190
+ ```typescript
1191
+ // Update participant response
1192
+ await participantService.updateStatus({
1193
+ id: participantId,
1194
+ status: ParticipantStatus.ACCEPTED,
1195
+ }, user);
1196
+ ```
1197
+
1198
+ ### 4. Use Consistent Colors
1199
+
1200
+ ```typescript
1201
+ // Use the default color from config
1202
+ const defaultColor = eventConfig.getDefaultColor();
1203
+
1204
+ // Or use predefined colors
1205
+ const EVENT_COLORS = [
1206
+ '#3B82F6', // Blue
1207
+ '#EF4444', // Red
1208
+ '#10B981', // Green
1209
+ '#F59E0B', // Amber
1210
+ '#8B5CF6', // Purple
1211
+ ];
1212
+ ```
1213
+
1214
+ ---
1215
+
1216
+ ## API Reference
1217
+
1218
+ ### Main Exports
1219
+
1220
+ ```typescript
1221
+ // Module
1222
+ import { EventManagerModule } from '@flusys/nestjs-event-manager';
1223
+
1224
+ // Adapter (for cross-module usage)
1225
+ import { EventManagerAdapter } from '@flusys/nestjs-event-manager/adapters';
1226
+
1227
+ // Adapter Interface & Token (from shared)
1228
+ import {
1229
+ EVENT_MANAGER_ADAPTER,
1230
+ IEventManagerAdapter,
1231
+ CreateEventOptions,
1232
+ EventResult,
1233
+ } from '@flusys/nestjs-shared/interfaces';
1234
+
1235
+ // Services
1236
+ import {
1237
+ EventService,
1238
+ EventParticipantService,
1239
+ EventManagerConfigService,
1240
+ EventManagerDataSourceProvider,
1241
+ EventManagerHelperService,
1242
+ } from '@flusys/nestjs-event-manager/services';
1243
+
1244
+ // Entities
1245
+ import {
1246
+ Event,
1247
+ EventBase,
1248
+ EventWithCompany,
1249
+ EventParticipant,
1250
+ EventParticipantBase,
1251
+ EventManagerCoreEntities,
1252
+ EventManagerCompanyEntities,
1253
+ getEventManagerEntitiesByConfig,
1254
+ } from '@flusys/nestjs-event-manager/entities';
1255
+
1256
+ // DTOs
1257
+ import {
1258
+ CreateEventDto,
1259
+ UpdateEventDto,
1260
+ EventResponseDto,
1261
+ CalendarEventResponseDto,
1262
+ CalendarQueryDto,
1263
+ CreateEventParticipantDto,
1264
+ UpdateEventParticipantDto,
1265
+ EventParticipantResponseDto,
1266
+ UpdateParticipantStatusDto,
1267
+ BulkAddParticipantsDto,
1268
+ } from '@flusys/nestjs-event-manager/dtos';
1269
+
1270
+ // Interfaces
1271
+ import {
1272
+ IEvent,
1273
+ IEventParticipant,
1274
+ ICalendarEvent,
1275
+ IEventManagerModuleConfig,
1276
+ EventManagerModuleOptions,
1277
+ EventManagerModuleAsyncOptions,
1278
+ EventManagerOptionsFactory,
1279
+ } from '@flusys/nestjs-event-manager/interfaces';
1280
+
1281
+ // Enums (canonical source)
1282
+ import {
1283
+ RecurrenceType,
1284
+ ParticipantStatus,
1285
+ } from '@flusys/nestjs-shared/enums';
1286
+
1287
+ // Or re-export from event-manager
1288
+ import {
1289
+ RecurrenceType,
1290
+ ParticipantStatus,
1291
+ } from '@flusys/nestjs-event-manager/enums';
1292
+
1293
+ // Controllers
1294
+ import {
1295
+ EventController,
1296
+ EventParticipantController,
1297
+ } from '@flusys/nestjs-event-manager/controllers';
1298
+
1299
+ // Config & Docs
1300
+ import { EVENT_MANAGER_MODULE_OPTIONS } from '@flusys/nestjs-event-manager/config';
1301
+ import {
1302
+ EVENT_PERMISSIONS,
1303
+ EVENT_PARTICIPANT_PERMISSIONS,
1304
+ eventManagerSwaggerConfig,
1305
+ } from '@flusys/nestjs-event-manager/docs';
1306
+ ```
1307
+
1308
+ ---
1309
+
1310
+ ## Summary
1311
+
1312
+ The `@flusys/nestjs-event-manager` package provides:
1313
+
1314
+ - **Event CRUD** - Full create, read, update, delete for events
1315
+ - **Recurrence Support** - Daily, weekly, biweekly, monthly patterns
1316
+ - **Calendar Queries** - Date range queries with automatic recurrence expansion
1317
+ - **Participant Management** - Track participants with status (pending, accepted, declined, tentative)
1318
+ - **Adapter Pattern** - Cross-module event creation via `IEventManagerAdapter`
1319
+ - **Company Scoping** - Per-company event isolation
1320
+ - **Multi-Tenant** - Separate databases per tenant
1321
+ - **POST-only RPC** - All endpoints use POST method
1322
+ - **Permission Guards** - All endpoints protected by permissions
1323
+
1324
+ ---
1325
+
1326
+ **Last Updated:** 2026-02-26
1327
+ **Version:** 3.0.0
1328
+ **NestJS Version:** 11