@venizia/ignis-docs 0.0.3 → 0.0.4-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 (131) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -2
  3. package/wiki/best-practices/api-usage-examples.md +591 -0
  4. package/wiki/best-practices/architectural-patterns.md +415 -0
  5. package/wiki/best-practices/architecture-decisions.md +488 -0
  6. package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
  7. package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
  8. package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
  9. package/wiki/best-practices/data-modeling.md +376 -0
  10. package/wiki/best-practices/deployment-strategies.md +698 -0
  11. package/wiki/best-practices/index.md +27 -0
  12. package/wiki/best-practices/performance-optimization.md +196 -0
  13. package/wiki/best-practices/security-guidelines.md +218 -0
  14. package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
  15. package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
  16. package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
  17. package/wiki/changelogs/2025-12-17-refactor.md +1 -1
  18. package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
  19. package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
  20. package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
  21. package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
  22. package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
  23. package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
  24. package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
  25. package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
  26. package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
  27. package/wiki/changelogs/index.md +6 -0
  28. package/wiki/changelogs/planned-schema-migrator.md +0 -8
  29. package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
  30. package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
  31. package/wiki/guides/core-concepts/components-guide.md +509 -0
  32. package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
  33. package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
  34. package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
  35. package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
  36. package/wiki/guides/core-concepts/persistent/index.md +119 -0
  37. package/wiki/guides/core-concepts/persistent/models.md +241 -0
  38. package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
  39. package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
  40. package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
  41. package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
  42. package/wiki/guides/get-started/philosophy.md +682 -0
  43. package/wiki/guides/get-started/setup.md +157 -0
  44. package/wiki/guides/index.md +89 -0
  45. package/wiki/guides/reference/glossary.md +243 -0
  46. package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
  47. package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
  48. package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
  49. package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
  50. package/wiki/guides/tutorials/realtime-chat.md +1261 -0
  51. package/wiki/guides/tutorials/testing.md +723 -0
  52. package/wiki/index.md +176 -37
  53. package/wiki/references/base/application.md +27 -0
  54. package/wiki/references/base/bootstrapping.md +30 -26
  55. package/wiki/references/base/components.md +24 -7
  56. package/wiki/references/base/controllers.md +51 -20
  57. package/wiki/references/base/datasources.md +30 -0
  58. package/wiki/references/base/dependency-injection.md +39 -3
  59. package/wiki/references/base/filter-system/application-usage.md +224 -0
  60. package/wiki/references/base/filter-system/array-operators.md +132 -0
  61. package/wiki/references/base/filter-system/comparison-operators.md +109 -0
  62. package/wiki/references/base/filter-system/default-filter.md +428 -0
  63. package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
  64. package/wiki/references/base/filter-system/index.md +127 -0
  65. package/wiki/references/base/filter-system/json-filtering.md +197 -0
  66. package/wiki/references/base/filter-system/list-operators.md +71 -0
  67. package/wiki/references/base/filter-system/logical-operators.md +156 -0
  68. package/wiki/references/base/filter-system/null-operators.md +58 -0
  69. package/wiki/references/base/filter-system/pattern-matching.md +108 -0
  70. package/wiki/references/base/filter-system/quick-reference.md +431 -0
  71. package/wiki/references/base/filter-system/range-operators.md +63 -0
  72. package/wiki/references/base/filter-system/tips.md +190 -0
  73. package/wiki/references/base/filter-system/use-cases.md +452 -0
  74. package/wiki/references/base/index.md +90 -0
  75. package/wiki/references/base/middlewares.md +602 -0
  76. package/wiki/references/base/models.md +215 -23
  77. package/wiki/references/base/providers.md +732 -0
  78. package/wiki/references/base/repositories/advanced.md +555 -0
  79. package/wiki/references/base/repositories/index.md +228 -0
  80. package/wiki/references/base/repositories/mixins.md +331 -0
  81. package/wiki/references/base/repositories/relations.md +486 -0
  82. package/wiki/references/base/repositories.md +40 -635
  83. package/wiki/references/base/services.md +28 -4
  84. package/wiki/references/components/authentication.md +22 -2
  85. package/wiki/references/components/health-check.md +12 -0
  86. package/wiki/references/components/index.md +23 -0
  87. package/wiki/references/components/mail.md +687 -0
  88. package/wiki/references/components/request-tracker.md +16 -0
  89. package/wiki/references/components/socket-io.md +18 -0
  90. package/wiki/references/components/static-asset.md +14 -26
  91. package/wiki/references/components/swagger.md +17 -0
  92. package/wiki/references/configuration/environment-variables.md +427 -0
  93. package/wiki/references/configuration/index.md +73 -0
  94. package/wiki/references/helpers/cron.md +14 -0
  95. package/wiki/references/helpers/crypto.md +15 -0
  96. package/wiki/references/helpers/env.md +16 -0
  97. package/wiki/references/helpers/error.md +17 -0
  98. package/wiki/references/helpers/index.md +14 -0
  99. package/wiki/references/helpers/inversion.md +24 -4
  100. package/wiki/references/helpers/logger.md +19 -0
  101. package/wiki/references/helpers/network.md +11 -0
  102. package/wiki/references/helpers/queue.md +19 -0
  103. package/wiki/references/helpers/redis.md +21 -0
  104. package/wiki/references/helpers/socket-io.md +24 -5
  105. package/wiki/references/helpers/storage.md +18 -10
  106. package/wiki/references/helpers/testing.md +18 -0
  107. package/wiki/references/helpers/types.md +16 -0
  108. package/wiki/references/helpers/uid.md +167 -0
  109. package/wiki/references/helpers/worker-thread.md +16 -0
  110. package/wiki/references/index.md +177 -0
  111. package/wiki/references/quick-reference.md +634 -0
  112. package/wiki/references/src-details/boot.md +3 -3
  113. package/wiki/references/src-details/dev-configs.md +0 -4
  114. package/wiki/references/src-details/docs.md +2 -2
  115. package/wiki/references/src-details/index.md +86 -0
  116. package/wiki/references/src-details/inversion.md +1 -6
  117. package/wiki/references/src-details/mcp-server.md +3 -15
  118. package/wiki/references/utilities/index.md +86 -10
  119. package/wiki/references/utilities/jsx.md +577 -0
  120. package/wiki/references/utilities/request.md +0 -2
  121. package/wiki/references/utilities/statuses.md +740 -0
  122. package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
  123. package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
  124. package/wiki/get-started/best-practices/data-modeling.md +0 -177
  125. package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
  126. package/wiki/get-started/best-practices/performance-optimization.md +0 -97
  127. package/wiki/get-started/best-practices/security-guidelines.md +0 -99
  128. package/wiki/get-started/core-concepts/persistent.md +0 -539
  129. package/wiki/get-started/index.md +0 -65
  130. package/wiki/get-started/philosophy.md +0 -296
  131. package/wiki/get-started/prerequisites.md +0 -113
@@ -0,0 +1,687 @@
1
+ # Mail Component
2
+
3
+ Flexible email sending system with support for multiple transports, templating, and queue-based processing.
4
+
5
+ ## Quick Reference
6
+
7
+ | Component | Purpose |
8
+ | ----------------------------------- | ------------------------------------------------------------------------ |
9
+ | **MailComponent** | Main component registering mail services, transporters, and executors |
10
+ | **MailService** | Core service for sending emails, batch emails, and template-based emails |
11
+ | **TemplateEngineService** | Simple template engine with `{{variable}}` syntax |
12
+ | **NodemailerTransportHelper** | Nodemailer-based email transport implementation |
13
+ | **MailgunTransportHelper** | Mailgun API-based email transport implementation |
14
+ | **DirectMailExecutorHelper** | Execute email sending immediately without queue |
15
+ | **InternalQueueMailExecutorHelper** | Queue emails using in-memory queue |
16
+ | **BullMQMailExecutorHelper** | Queue emails using BullMQ for distributed processing |
17
+
18
+ ### Key Binding Keys
19
+
20
+ | Key | Purpose |
21
+ | --------------------------------------- | ---------------------------------------------- |
22
+ | `MailKeys.MAIL_OPTIONS` | Mail transport configuration (required) |
23
+ | `MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` | Queue executor configuration (required) |
24
+ | `MailKeys.MAIL_SERVICE` | Main mail service instance |
25
+ | `MailKeys.MAIL_TEMPLATE_ENGINE` | Template engine service |
26
+ | `MailKeys.MAIL_TRANSPORT_INSTANCE` | Transport instance (created by component) |
27
+ | `MailKeys.MAIL_QUEUE_EXECUTOR_INSTANCE` | Queue executor instance (created by component) |
28
+
29
+ ### Transport Providers
30
+
31
+ | Provider | Value | When to Use |
32
+ | -------------- | -------------------------- | ------------------------------------------------ |
33
+ | **Nodemailer** | `MailProviders.NODEMAILER` | SMTP-based email sending (Gmail, SendGrid, etc.) |
34
+ | **Mailgun** | `MailProviders.MAILGUN` | Mailgun API for transactional emails |
35
+ | **Custom** | `MailProviders.CUSTOM` | Custom transport implementation |
36
+
37
+ ### Queue Executor Types
38
+
39
+ | Type | Value | When to Use |
40
+ | ------------------ | ------------------ | ------------------------------------------ |
41
+ | **Direct** | `'direct'` | No queue, send immediately |
42
+ | **Internal Queue** | `'internal-queue'` | In-memory queue for simple use cases |
43
+ | **BullMQ** | `'bullmq'` | Redis-backed queue for distributed systems |
44
+
45
+ ## Architecture Components
46
+
47
+ - **`MailComponent`**: Initializes and registers all mail services, transporters, and queue executors
48
+ - **`MailService`**: Provides methods to send single emails, batch emails, and template-based emails
49
+ - **`TemplateEngineService`**: Manages email templates with simple `{{variable}}` substitution
50
+ - **Verification Generators**: Generate verification codes, tokens, and data for email verification flows
51
+ - **Transport Providers**: Factory functions that create transport instances based on configuration
52
+ - **Queue Executor Providers**: Factory functions that create queue executor instances based on configuration
53
+
54
+ ## Implementation Details
55
+
56
+ ### Tech Stack
57
+
58
+ - **Nodemailer**: SMTP-based email sending
59
+ - **Mailgun**: Mailgun API client
60
+ - **BullMQ** (optional): Redis-backed queue for distributed processing
61
+ - **Handlebars-style Templates**: Simple `{{variable}}` syntax for email templates
62
+
63
+ ### Configuration
64
+
65
+ The Mail component requires two main configurations to be bound before registering the component:
66
+
67
+ 1. **`MailKeys.MAIL_OPTIONS`**: Transport configuration
68
+ 2. **`MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG`**: Queue executor configuration
69
+
70
+ **Environment Variables (for Nodemailer with OAuth2):**
71
+
72
+ ```
73
+ APP_ENV_MAIL_HOST=smtp.gmail.com
74
+ APP_ENV_MAIL_PORT=465
75
+ APP_ENV_MAIL_SECURE=true
76
+ APP_ENV_MAIL_USER=your-email@gmail.com
77
+ APP_ENV_MAIL_CLIENT_ID=your-oauth2-client-id
78
+ APP_ENV_MAIL_CLIENT_SECRET=your-oauth2-client-secret
79
+ APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
80
+ ```
81
+
82
+ ::: tip
83
+ For Gmail OAuth2 setup, you need to create credentials in Google Cloud Console and generate a refresh token. See [Nodemailer OAuth2 documentation](https://nodemailer.com/smtp/oauth2/) for details.
84
+ :::
85
+
86
+ ### Code Samples
87
+
88
+ #### 1. Basic Setup with Nodemailer
89
+
90
+ The simplest way to set up the Mail component is by creating a custom component that wraps `MailComponent` with the necessary bindings.
91
+
92
+ ```typescript
93
+ // src/components/mail/component.ts
94
+ import {
95
+ BaseApplication,
96
+ BaseComponent,
97
+ Binding,
98
+ CoreBindings,
99
+ inject,
100
+ MailComponent,
101
+ MailKeys,
102
+ MailProviders,
103
+ applicationEnvironment,
104
+ toBoolean,
105
+ } from '@venizia/ignis';
106
+
107
+ export class NodemailerComponent extends BaseComponent {
108
+ constructor(
109
+ @inject({ key: CoreBindings.APPLICATION_INSTANCE })
110
+ protected application: BaseApplication,
111
+ ) {
112
+ super({
113
+ scope: NodemailerComponent.name,
114
+ initDefault: { enable: true, container: application },
115
+ bindings: {
116
+ // Configure mail transport options
117
+ [MailKeys.MAIL_OPTIONS]: Binding.bind({
118
+ key: MailKeys.MAIL_OPTIONS,
119
+ }).toValue({
120
+ provider: MailProviders.NODEMAILER,
121
+ from: 'noreply@example.com',
122
+ fromName: 'Example App',
123
+ config: {
124
+ host: applicationEnvironment.get<string>('APP_ENV_MAIL_HOST') ?? 'smtp.gmail.com',
125
+ port: +(applicationEnvironment.get<number>('APP_ENV_MAIL_PORT') ?? 465),
126
+ secure: toBoolean(applicationEnvironment.get<boolean>('APP_ENV_MAIL_SECURE') ?? true),
127
+ auth: {
128
+ type: 'oauth2',
129
+ user: applicationEnvironment.get<string>('APP_ENV_MAIL_USER'),
130
+ clientId: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_ID'),
131
+ clientSecret: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_SECRET'),
132
+ refreshToken: applicationEnvironment.get<string>('APP_ENV_MAIL_REFRESH_TOKEN'),
133
+ },
134
+ },
135
+ }),
136
+ // Configure queue executor
137
+ [MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG]: Binding.bind({
138
+ key: MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG,
139
+ }).toValue({
140
+ type: 'internal-queue',
141
+ internalQueue: {
142
+ identifier: 'mail-internal-queue',
143
+ },
144
+ }),
145
+ },
146
+ });
147
+ }
148
+
149
+ override async binding(): Promise<void> {
150
+ this.logger.info('[binding] Binding mail component...');
151
+
152
+ // Register the core MailComponent
153
+ this.application.component(MailComponent);
154
+
155
+ this.logger.info('[binding] Mail component initialized successfully');
156
+ }
157
+ }
158
+ ```
159
+
160
+ Then register it in your application:
161
+
162
+ ```typescript
163
+ // src/application.ts
164
+ import { BaseApplication, ValueOrPromise } from '@venizia/ignis';
165
+ import { NodemailerComponent } from './components/mail/component';
166
+
167
+ export class Application extends BaseApplication {
168
+ preConfigure(): ValueOrPromise<void> {
169
+ // Register the mail component
170
+ this.component(NodemailerComponent);
171
+
172
+ // ... other components
173
+ }
174
+ }
175
+ ```
176
+
177
+ #### 2. Nodemailer with Simple SMTP Auth
178
+
179
+ For basic SMTP authentication (username/password):
180
+
181
+ ```typescript
182
+ {
183
+ provider: MailProviders.NODEMAILER,
184
+ from: 'noreply@example.com',
185
+ fromName: 'My App',
186
+ config: {
187
+ host: 'smtp.example.com',
188
+ port: 587,
189
+ secure: false, // true for 465, false for other ports
190
+ auth: {
191
+ user: 'smtp-username',
192
+ pass: 'smtp-password',
193
+ },
194
+ },
195
+ }
196
+ ```
197
+
198
+ #### 3. Mailgun Configuration
199
+
200
+ ```typescript
201
+ {
202
+ provider: MailProviders.MAILGUN,
203
+ from: 'noreply@example.com',
204
+ fromName: 'My App',
205
+ config: {
206
+ domain: 'mg.example.com',
207
+ apiKey: process.env.MAILGUN_API_KEY,
208
+ url: 'https://api.mailgun.net', // Optional, defaults to US region
209
+ },
210
+ }
211
+ ```
212
+
213
+ #### 4. Queue Executor Configurations
214
+
215
+ **Direct Executor (No Queue):**
216
+
217
+ ```typescript
218
+ {
219
+ type: 'direct',
220
+ }
221
+ ```
222
+
223
+ **Internal Queue Executor:**
224
+
225
+ ```typescript
226
+ {
227
+ type: 'internal-queue',
228
+ internalQueue: {
229
+ identifier: 'mail-verification-queue',
230
+ },
231
+ }
232
+ ```
233
+
234
+ **BullMQ Executor:**
235
+
236
+ ```typescript
237
+ {
238
+ type: 'bullmq',
239
+ bullmq: {
240
+ redis: {
241
+ name: 'mail-redis',
242
+ host: process.env.REDIS_HOST ?? 'localhost',
243
+ port: process.env.REDIS_PORT ?? 6379,
244
+ password: process.env.REDIS_PASSWORD ?? '',
245
+ database: 0,
246
+ autoConnect: true,
247
+ },
248
+ queue: {
249
+ identifier: 'mail-queue-executor',
250
+ name: 'mail-verification-queue',
251
+ },
252
+ mode: 'both', // 'queue-only' | 'worker-only' | 'both'
253
+ },
254
+ }
255
+ ```
256
+
257
+ **BullMQ Executor Mode Options:**
258
+
259
+ - **`queue-only`**: Only enqueue jobs, no workers (useful for API servers that just add jobs)
260
+ - **`worker-only`**: Only process jobs, cannot enqueue (useful for dedicated worker servers)
261
+ - **`both`**: Can both enqueue and process jobs (useful for single-server deployments)
262
+
263
+ #### 5. Sending Emails
264
+
265
+ Inject the `MailService` to send emails:
266
+
267
+ ```typescript
268
+ import { BaseService, inject, MailKeys, IMailService } from '@venizia/ignis';
269
+
270
+ export class UserService extends BaseService {
271
+ constructor(
272
+ @inject({ key: MailKeys.MAIL_SERVICE })
273
+ private _mailService: IMailService,
274
+ ) {
275
+ super({ scope: UserService.name });
276
+ }
277
+
278
+ async sendWelcomeEmail(opts: { userEmail: string; userName: string }) {
279
+ const result = await this._mailService.send({
280
+ to: opts.userEmail,
281
+ subject: 'Welcome to Our App!',
282
+ html: `<h1>Welcome ${opts.userName}!</h1><p>Thanks for joining us.</p>`,
283
+ text: `Welcome ${opts.userName}! Thanks for joining us.`,
284
+ });
285
+
286
+ if (result.success) {
287
+ this.logger.info('[sendWelcomeEmail] Email sent: %s', result.messageId);
288
+ } else {
289
+ this.logger.error('[sendWelcomeEmail] Failed to send email: %s', result.error);
290
+ }
291
+
292
+ return result;
293
+ }
294
+ }
295
+ ```
296
+
297
+ #### 6. Using Templates
298
+
299
+ Register and use email templates:
300
+
301
+ ```typescript
302
+ import { BaseService, inject, MailKeys, IMailTemplateEngine, IMailService } from '@venizia/ignis';
303
+
304
+ export class NotificationService extends BaseService {
305
+ constructor(
306
+ @inject({ key: MailKeys.MAIL_TEMPLATE_ENGINE })
307
+ private templateEngine: IMailTemplateEngine,
308
+ @inject({ key: MailKeys.MAIL_SERVICE })
309
+ private mailService: IMailService,
310
+ ) {
311
+ super({ scope: NotificationService.name });
312
+ this.registerTemplates();
313
+ }
314
+
315
+ registerTemplates() {
316
+ // Register a welcome email template
317
+ this.templateEngine.registerTemplate({
318
+ name: 'welcome-email',
319
+ content: `
320
+ <html>
321
+ <body>
322
+ <h1>Welcome {{userName}}!</h1>
323
+ <p>Your account has been created successfully.</p>
324
+ <p>Your verification code is: <strong>{{verificationCode}}</strong></p>
325
+ </body>
326
+ </html>
327
+ `,
328
+ options: {
329
+ subject: 'Welcome to {{appName}}',
330
+ description: 'Welcome email for new users',
331
+ },
332
+ });
333
+ }
334
+
335
+ async sendWelcomeEmail(userEmail: string, userName: string, verificationCode: string) {
336
+ const result = await this.mailService.sendTemplate({
337
+ templateName: 'welcome-email',
338
+ data: {
339
+ userName,
340
+ verificationCode,
341
+ appName: 'My Application',
342
+ },
343
+ recipients: userEmail,
344
+ options: {
345
+ // Optional: override template subject or add attachments
346
+ attachments: [
347
+ {
348
+ filename: 'logo.png',
349
+ path: '/path/to/logo.png',
350
+ cid: 'logo',
351
+ },
352
+ ],
353
+ },
354
+ });
355
+
356
+ return result;
357
+ }
358
+ }
359
+ ```
360
+
361
+ #### 7. Batch Email Sending
362
+
363
+ Send multiple emails with controlled concurrency:
364
+
365
+ ```typescript
366
+ async sendBulkNotifications(users: Array<{ email: string; name: string }>) {
367
+ const messages = users.map(user => ({
368
+ to: user.email,
369
+ subject: 'Important Update',
370
+ html: `<p>Hello ${user.name}, we have an important update for you.</p>`,
371
+ }));
372
+
373
+ const results = await this.mailService.sendBatch(messages, {
374
+ concurrency: 5, // Send 5 emails at a time
375
+ });
376
+
377
+ const successCount = results.filter(r => r.success).length;
378
+ this.logger.info(
379
+ '[sendBulkNotifications] Sent %d/%d emails successfully',
380
+ successCount,
381
+ results.length,
382
+ );
383
+
384
+ return results;
385
+ }
386
+ ```
387
+
388
+ #### 8. Email Verification Flow
389
+
390
+ Using the verification data generators:
391
+
392
+ ```typescript
393
+ import {
394
+ BaseService,
395
+ inject,
396
+ MailKeys,
397
+ IMailService,
398
+ IVerificationDataGenerator,
399
+ } from '@venizia/ignis';
400
+
401
+ export class AuthService extends BaseService {
402
+ constructor(
403
+ @inject({ key: MailKeys.MAIL_SERVICE })
404
+ private mailService: IMailService,
405
+ @inject({ key: MailKeys.MAIL_VERIFICATION_DATA_GENERATOR })
406
+ private verificationGenerator: IVerificationDataGenerator,
407
+ ) {
408
+ super({ scope: AuthService.name });
409
+ }
410
+
411
+ async sendVerificationEmail(userEmail: string) {
412
+ // Generate verification code and token
413
+ const verificationData = this.verificationGenerator.generateVerificationData({
414
+ codeLength: 6, // 6-digit code
415
+ tokenBytes: 32, // 32-byte token
416
+ codeExpiryMinutes: 10, // Code expires in 10 minutes
417
+ tokenExpiryHours: 24, // Token expires in 24 hours
418
+ });
419
+
420
+ // Save verification data to database
421
+ // await this.saveVerificationData(userEmail, verificationData);
422
+
423
+ // Send verification email
424
+ const result = await this.mailService.send({
425
+ to: userEmail,
426
+ subject: 'Email Verification',
427
+ html: `
428
+ <h2>Verify Your Email</h2>
429
+ <p>Your verification code is: <strong>${verificationData.verificationCode}</strong></p>
430
+ <p>This code expires at: ${verificationData.codeExpiresAt}</p>
431
+ <p>Or click this link: https://example.com/verify?token=${verificationData.verificationToken}</p>
432
+ `,
433
+ });
434
+
435
+ return { result, verificationData };
436
+ }
437
+ }
438
+ ```
439
+
440
+ #### 9. Template Validation
441
+
442
+ Ensure all required template variables are provided:
443
+
444
+ ```typescript
445
+ const template = '<h1>Hello {{userName}}, your code is {{code}}</h1>';
446
+ const data = { userName: 'John' }; // Missing 'code'
447
+
448
+ const validation = this.templateEngine.validateTemplateData({ template, data });
449
+
450
+ if (!validation.isValid) {
451
+ console.error('Missing template variables:', validation.missingKeys);
452
+ // Output: ['code']
453
+ }
454
+
455
+ // Render with validation
456
+ try {
457
+ const html = this.templateEngine.render({
458
+ templateData: template,
459
+ data,
460
+ requireValidate: true, // Throws error if validation fails
461
+ });
462
+ } catch (error) {
463
+ console.error('Template rendering failed:', error.message);
464
+ }
465
+ ```
466
+
467
+ #### 10. Syncing Templates from Database
468
+
469
+ For applications that store templates in a database:
470
+
471
+ ```typescript
472
+ async syncTemplatesFromDatabase() {
473
+ const templateEngine = this.application.get<IMailTemplateEngine>({
474
+ key: MailKeys.MAIL_TEMPLATE_ENGINE,
475
+ });
476
+
477
+ const configRepository = this.application.get<ConfigurationRepository>({
478
+ key: 'repositories.ConfigurationRepository',
479
+ });
480
+
481
+ const templateConfigs = await configRepository.find({
482
+ filter: {
483
+ where: {
484
+ code: { inq: ['MAIL_TEMPLATE_WELCOME', 'MAIL_TEMPLATE_VERIFICATION'] },
485
+ },
486
+ },
487
+ });
488
+
489
+ templateConfigs.forEach(config => {
490
+ templateEngine.registerTemplate({
491
+ name: config.code,
492
+ content: config.jValue.content,
493
+ options: {
494
+ subject: config.jValue.subject,
495
+ description: config.jValue.description,
496
+ },
497
+ });
498
+ this.logger.info('[syncTemplates] Registered template: %s', config.code);
499
+ });
500
+ }
501
+ ```
502
+
503
+ ## API Specifications
504
+
505
+ ### Mail Options Configuration
506
+
507
+ ```typescript
508
+ // Nodemailer Options
509
+ interface INodemailerMailOptions {
510
+ provider: 'nodemailer';
511
+ from?: string;
512
+ fromName?: string;
513
+ config: {
514
+ host: string;
515
+ port: number;
516
+ secure: boolean;
517
+ auth: {
518
+ type?: 'oauth2' | 'login';
519
+ user: string;
520
+ pass?: string; // For simple auth
521
+ // OAuth2 specific
522
+ clientId?: string;
523
+ clientSecret?: string;
524
+ refreshToken?: string;
525
+ };
526
+ };
527
+ }
528
+
529
+ // Mailgun Options
530
+ interface IMailgunMailOptions {
531
+ provider: 'mailgun';
532
+ from?: string;
533
+ fromName?: string;
534
+ config: {
535
+ domain: string;
536
+ apiKey: string;
537
+ url?: string; // Optional, defaults to US region
538
+ };
539
+ }
540
+
541
+ // Queue Executor Configuration
542
+ interface IMailQueueExecutorConfig {
543
+ type: 'direct' | 'internal-queue' | 'bullmq';
544
+
545
+ // For internal-queue type
546
+ internalQueue?: {
547
+ identifier: string;
548
+ };
549
+
550
+ // For bullmq type
551
+ bullmq?: {
552
+ redis: {
553
+ name: string;
554
+ host: string;
555
+ port: string | number;
556
+ password: string;
557
+ user?: string;
558
+ database?: number;
559
+ autoConnect?: boolean;
560
+ maxRetry?: number;
561
+ };
562
+ queue: {
563
+ identifier: string;
564
+ name: string;
565
+ };
566
+ mode: 'queue-only' | 'worker-only' | 'both';
567
+ };
568
+ }
569
+ ```
570
+
571
+ ### IMailService Interface
572
+
573
+ ```typescript
574
+ interface IMailService {
575
+ // Send a single email
576
+ send(message: IMailMessage): Promise<IMailSendResult>;
577
+
578
+ // Send multiple emails with controlled concurrency
579
+ sendBatch(
580
+ messages: IMailMessage[],
581
+ options?: { concurrency?: number },
582
+ ): Promise<IMailSendResult[]>;
583
+
584
+ // Send email using a registered template
585
+ sendTemplate(opts: {
586
+ templateName: string;
587
+ data: Record<string, any>;
588
+ recipients: string | string[];
589
+ options?: Partial<IMailMessage>;
590
+ }): Promise<IMailSendResult>;
591
+
592
+ // Verify transport connection
593
+ verify(): Promise<boolean>;
594
+ }
595
+ ```
596
+
597
+ ### IMailMessage Interface
598
+
599
+ ```typescript
600
+ interface IMailMessage {
601
+ from?: string; // Sender email (uses default if not provided)
602
+ to: string | string[]; // Recipient(s)
603
+ cc?: string | string[]; // CC recipient(s)
604
+ bcc?: string | string[]; // BCC recipient(s)
605
+ replyTo?: string; // Reply-to address
606
+ subject: string; // Email subject
607
+ text?: string; // Plain text content
608
+ html?: string; // HTML content
609
+ attachments?: IMailAttachment[]; // File attachments
610
+ headers?: Record<string, string>; // Custom headers
611
+ requireValidate?: boolean; // Validate template data
612
+ }
613
+ ```
614
+
615
+ ### IMailTemplateEngine Interface
616
+
617
+ ```typescript
618
+ interface IMailTemplateEngine {
619
+ // Render a template with data
620
+ render(opts: {
621
+ templateData?: string;
622
+ templateName?: string;
623
+ data: Record<string, any>;
624
+ requireValidate?: boolean;
625
+ }): string;
626
+
627
+ // Register a new template
628
+ registerTemplate(opts: { name: string; content: string; options?: Partial<ITemplate> }): void;
629
+
630
+ // Validate template data
631
+ validateTemplateData(opts: { template: string; data: Record<string, any> }): {
632
+ isValid: boolean;
633
+ missingKeys: string[];
634
+ allKeys: string[];
635
+ };
636
+
637
+ // Get a registered template
638
+ getTemplate(name: string): ITemplate | undefined;
639
+
640
+ // List all registered templates
641
+ listTemplates(): ITemplate[];
642
+
643
+ // Check if template exists
644
+ hasTemplate(name: string): boolean;
645
+
646
+ // Remove a template
647
+ removeTemplate(name: string): boolean;
648
+ }
649
+ ```
650
+
651
+ ## Best Practices
652
+
653
+ 1. **Always bind configuration before registering MailComponent**: The component will throw an error if `MailKeys.MAIL_OPTIONS` is not bound.
654
+
655
+ 2. **Use environment variables for sensitive data**: Never hardcode SMTP credentials or API keys in your code.
656
+
657
+ 3. **Choose the right queue executor**:
658
+ - Use `direct` for development or low-volume applications
659
+ - Use `internal-queue` for single-instance applications with moderate volume
660
+ - Use `bullmq` for distributed systems or high-volume applications
661
+
662
+ 4. **Validate templates in development**: Use `requireValidate: true` during development to catch missing template variables early.
663
+
664
+ 5. **Handle send failures gracefully**: Always check the `success` field in `IMailSendResult` and implement proper error handling.
665
+
666
+ 6. **Use batch sending for bulk operations**: The `sendBatch` method with controlled concurrency prevents overwhelming your mail server.
667
+
668
+ 7. **Verify transport on startup**: Call `mailService.verify()` during application startup to ensure mail configuration is correct.
669
+
670
+ ## See Also
671
+
672
+ - **Related Concepts:**
673
+ - [Components Overview](/guides/core-concepts/components) - Component system basics
674
+ - [Services](/guides/core-concepts/services) - Using mail service in business logic
675
+
676
+ - **Other Components:**
677
+ - [Components Index](./index) - All built-in components
678
+
679
+ - **References:**
680
+ - [Queue Helper](/references/helpers/queue) - Background job processing
681
+
682
+ - **External Resources:**
683
+ - [Nodemailer Documentation](https://nodemailer.com/) - Email library
684
+ - [Handlebars Documentation](https://handlebarsjs.com/) - Template engine
685
+
686
+ - **Best Practices:**
687
+ - [Security Guidelines](/best-practices/security-guidelines) - Email security
@@ -33,3 +33,19 @@ When the component is active, it adds the `requestId` and `RequestSpyMiddleware`
33
33
  ```
34
34
 
35
35
  This feature is essential for building production-ready applications with proper logging and traceability.
36
+
37
+ ## See Also
38
+
39
+ - **Related Concepts:**
40
+ - [Components Overview](/guides/core-concepts/components) - Component system basics
41
+ - [Middlewares](/references/base/middlewares) - Request middleware system
42
+
43
+ - **Other Components:**
44
+ - [Components Index](./index) - All built-in components
45
+
46
+ - **References:**
47
+ - [Logger Helper](/references/helpers/logger) - Logging utilities
48
+
49
+ - **Best Practices:**
50
+ - [Troubleshooting Tips](/best-practices/troubleshooting-tips) - Debugging with request IDs
51
+ - [Deployment Strategies](/best-practices/deployment-strategies) - Production logging