@breadstone/archipel-mcp 0.0.45 → 0.0.47

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 (44) hide show
  1. package/data/guides/ai-text-generation.md +2 -2
  2. package/data/guides/authentication-and-authorization.md +2 -2
  3. package/data/guides/blob-storage.md +3 -3
  4. package/data/guides/caching.md +2 -2
  5. package/data/guides/composition-context.md +462 -0
  6. package/data/guides/database-setup.md +4 -4
  7. package/data/guides/email-delivery.md +6 -6
  8. package/data/guides/index.md +1 -0
  9. package/data/guides/openapi-and-feature-discovery.md +1 -1
  10. package/data/guides/queue-infrastructure.md +4 -4
  11. package/data/guides/telemetry-and-observability.md +1 -1
  12. package/data/packages/platform-blob-storage/api/Class.BlobStorageStrategyBase.md +1 -0
  13. package/data/packages/platform-blob-storage/api/Class.EmptyBlobStorageStrategy.md +183 -0
  14. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_ACCESS_KEY_ID.md +1 -1
  15. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_BUCKET.md +1 -1
  16. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_CONFIG_ENTRIES.md +1 -1
  17. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_ENDPOINT.md +1 -1
  18. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_REGION.md +1 -1
  19. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_SECRET_ACCESS_KEY.md +1 -1
  20. package/data/packages/platform-blob-storage/api/Variable.LOCAL_BLOB_BASE_PATH.md +1 -1
  21. package/data/packages/platform-blob-storage/api/Variable.LOCAL_BLOB_BUCKET.md +1 -1
  22. package/data/packages/platform-blob-storage/api/Variable.LOCAL_CONFIG_ENTRIES.md +1 -1
  23. package/data/packages/platform-blob-storage/api/Variable.PLATFORM_BLOB_STORAGE_CONFIG_ENTRIES.md +1 -1
  24. package/data/packages/platform-blob-storage/api/index.md +1 -0
  25. package/data/packages/platform-blob-storage/index.md +21 -1
  26. package/data/packages/platform-bootstrap/api/Class.CompositionContext.md +226 -0
  27. package/data/packages/platform-bootstrap/api/Class.CompositionModule.md +56 -0
  28. package/data/packages/platform-bootstrap/api/Class.CompositionResolver.md +206 -0
  29. package/data/packages/platform-bootstrap/api/Class.PlatformApplicationBuilder.md +75 -8
  30. package/data/packages/platform-bootstrap/api/Function.createCompositionContext.md +56 -0
  31. package/data/packages/platform-bootstrap/api/Interface.ICompositionContext.md +179 -0
  32. package/data/packages/platform-bootstrap/api/Interface.ICreateCompositionContextOptions.md +54 -0
  33. package/data/packages/platform-bootstrap/api/Interface.ICreateWithCompositionOptions.md +128 -0
  34. package/data/packages/platform-bootstrap/api/Interface.IProviderDecision.md +36 -0
  35. package/data/packages/platform-bootstrap/api/TypeAlias.CompositionImport.md +20 -0
  36. package/data/packages/platform-bootstrap/api/TypeAlias.ProviderComposer.md +53 -0
  37. package/data/packages/platform-bootstrap/api/index.md +10 -0
  38. package/data/packages/platform-cryptography/api/Class.OtpService.md +6 -6
  39. package/data/packages/platform-cryptography/api/Variable.TOTP_EPOCH_TOLERANCE.md +1 -1
  40. package/data/packages/platform-feature-flags/index.md +103 -0
  41. package/data/packages/platform-mailing/api/Class.DeliveryStrategyBase.md +0 -1
  42. package/data/packages/platform-mailing/api/index.md +0 -1
  43. package/package.json +1 -1
  44. package/data/packages/platform-mailing/api/Class.LogDeliveryStrategy.md +0 -71
@@ -64,7 +64,7 @@ Register only the provider loaders you install. The root entry does not import p
64
64
 
65
65
  All intelligence settings are read from environment variables via `ConfigService`. No direct `process.env` access is needed.
66
66
 
67
- ```env
67
+ ```dotenv
68
68
  INTELLIGENCE_PROVIDER=openai
69
69
  INTELLIGENCE_MODEL=gpt-4o-mini
70
70
  INTELLIGENCE_API_KEY=sk-...
@@ -85,7 +85,7 @@ INTELLIGENCE_BASE_URL= # optional — override for custom endpoints
85
85
 
86
86
  Each provider resolves its API key and base URL from dedicated environment variables when the generic `INTELLIGENCE_API_KEY` is not set:
87
87
 
88
- ```env
88
+ ```dotenv
89
89
  # Provider-specific keys (optional — fallback from INTELLIGENCE_API_KEY)
90
90
  OPENAI_API_KEY=sk-...
91
91
  ANTHROPIC_API_KEY=sk-ant-...
@@ -475,7 +475,7 @@ If `mfaRequired` is `true`, the client receives a `challengeId` instead of an `a
475
475
 
476
476
  ### MFA Configuration
477
477
 
478
- ```env
478
+ ```dotenv
479
479
  AUTH_MFA_ENCRYPTION_KEY=<32-byte-hex-key>
480
480
  AUTH_MFA_CHALLENGE_EXPIRES_IN=5m
481
481
  AUTH_MFA_MAX_ATTEMPTS=5
@@ -584,7 +584,7 @@ AuthModule.register({
584
584
 
585
585
  ### Step 4: Set Environment Variables
586
586
 
587
- ```env
587
+ ```dotenv
588
588
  # Google
589
589
  AUTH_GOOGLE_CLIENT_ID=your-client-id
590
590
  AUTH_GOOGLE_CLIENT_SECRET=your-client-secret
@@ -54,7 +54,7 @@ Each provider reads its credentials from environment variables via the `ConfigMo
54
54
 
55
55
  ### AWS S3
56
56
 
57
- ```env
57
+ ```dotenv
58
58
  BLOB_AWS_REGION=eu-central-1
59
59
  BLOB_AWS_BUCKET=my-app-uploads
60
60
  BLOB_AWS_ACCESS_KEY_ID=AKIA...
@@ -67,7 +67,7 @@ BLOB_AWS_SECRET_ACCESS_KEY=secret...
67
67
 
68
68
  You can authenticate with either a **connection string** or **DefaultAzureCredential** (via managed identity):
69
69
 
70
- ```env
70
+ ```dotenv
71
71
  # Option 1: Connection string
72
72
  BLOB_AZURE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
73
73
  BLOB_AZURE_CONTAINER=uploads
@@ -83,7 +83,7 @@ When using `accountName` without a `connectionString`, the provider authenticate
83
83
 
84
84
  ### Vercel Blob
85
85
 
86
- ```env
86
+ ```dotenv
87
87
  BLOB_VERCEL_TOKEN=your-vercel-blob-token
88
88
  ```
89
89
 
@@ -28,7 +28,7 @@ yarn add ioredis
28
28
 
29
29
  ### Core Variables
30
30
 
31
- ```env
31
+ ```dotenv
32
32
  CACHE_DEFAULT_TTL_MS=60000
33
33
  CACHE_MAX_ENTRIES=1000
34
34
  CACHE_STALE_WHILE_REVALIDATE=false
@@ -38,7 +38,7 @@ All core variables are optional. When omitted, each cache instance uses the valu
38
38
 
39
39
  ### Redis Variables
40
40
 
41
- ```env
41
+ ```dotenv
42
42
  REDIS_URL=redis://localhost:6379
43
43
  REDIS_KEY_PREFIX=app:
44
44
  REDIS_TTL_SECONDS=300
@@ -0,0 +1,462 @@
1
+ ---
2
+ title: Composition Context
3
+ description: Stage-aware, configuration-driven module composition for NestJS applications without direct process.env access.
4
+ order: 4
5
+ ---
6
+
7
+ # Composition Context
8
+
9
+ The composition context pattern enables **stage-aware infrastructure module selection** at application startup. Rather than hard-coding provider imports or scattering `process.env` checks throughout your codebase, composition provides a clean abstraction that reads configuration once and determines which modules to import.
10
+
11
+ This is particularly valuable for:
12
+
13
+ - **Multi-stage deployments** — Use mock mail in development, real SMTP in production
14
+ - **Feature flags** — Toggle entire modules based on configuration
15
+ - **Provider switching** — Swap payment providers or blob storage backends per environment
16
+ - **Clean architecture** — Keep `main.ts` free of conditional logic
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ The composition subpath is part of `platform-bootstrap`:
23
+
24
+ ```bash
25
+ yarn add @breadstone/archipel-platform-bootstrap @breadstone/archipel-platform-configuration
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Core Concepts
31
+
32
+ ### Composition Context
33
+
34
+ The `ICompositionContext` provides typed access to configuration during module assembly:
35
+
36
+ ```typescript
37
+ interface ICompositionContext {
38
+ readonly context: INestApplicationContext;
39
+ readonly config: ConfigService;
40
+
41
+ getConfigValue<T>(key: IConfigKey<T>): T;
42
+ tryGetConfigValue<T>(key: IConfigKey<T>, fallback: T): T;
43
+ getService<T>(token: Type<T>): T;
44
+ close(): Promise<void>;
45
+ }
46
+ ```
47
+
48
+ ### Composition Resolver
49
+
50
+ Abstract base class for encapsulating composition decisions:
51
+
52
+ ```typescript
53
+ abstract class CompositionResolver {
54
+ abstract shouldImportProvider(providerKey: string): boolean;
55
+
56
+ protected getConfigValue<T>(key: IConfigKey<T>): T;
57
+ protected tryGetConfigValue<T>(key: IConfigKey<T>, fallback: T): T;
58
+ protected compareConfigValue<T>(key: IConfigKey<T>, expected: T): boolean;
59
+ }
60
+ ```
61
+
62
+ ### Composition Import
63
+
64
+ Type alias for valid NestJS module imports:
65
+
66
+ ```typescript
67
+ type CompositionImport = Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference<unknown>;
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Basic Usage
73
+
74
+ ### Direct Factory Approach
75
+
76
+ For simple cases, use `createCompositionContext()` directly:
77
+
78
+ ```typescript
79
+ import { NestFactory } from '@nestjs/core';
80
+ import { createCompositionContext } from '@breadstone/archipel-platform-bootstrap/composition';
81
+ import { AppModule } from './AppModule';
82
+
83
+ async function main(): Promise<void> {
84
+ const context = await createCompositionContext();
85
+
86
+ try {
87
+ const driver = context.tryGetConfigValue({ key: 'MAIL_DRIVER' }, 'log');
88
+
89
+ if (driver === 'smtp') {
90
+ // Dynamic import only when needed
91
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
92
+ const { SmtpDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/smtp');
93
+
94
+ console.log('Using SMTP mail delivery');
95
+ }
96
+ } finally {
97
+ await context.close();
98
+ }
99
+
100
+ // Continue with normal NestJS bootstrap
101
+ const app = await NestFactory.create(AppModule);
102
+ await app.listen(3000);
103
+ }
104
+ ```
105
+
106
+ ### Builder Integration
107
+
108
+ For full integration with `PlatformApplicationBuilder`:
109
+
110
+ ```typescript
111
+ import { PlatformApplicationBuilder, useApi, CompositionImport } from '@breadstone/archipel-platform-bootstrap';
112
+ import { ExpressAdapter, NestExpressApplication } from '@nestjs/platform-express';
113
+ import { NestFactory } from '@nestjs/core';
114
+ import { AppModule } from './AppModule';
115
+
116
+ async function main(): Promise<void> {
117
+ const builder = await PlatformApplicationBuilder.createWithComposition<NestExpressApplication>(
118
+ async (context) => {
119
+ const imports: CompositionImport[] = [AppModule];
120
+
121
+ // Stage-aware mail provider selection
122
+ const driver = context.tryGetConfigValue({ key: 'MAIL_DRIVER' }, 'log');
123
+ const stage = context.tryGetConfigValue({ key: 'NODE_ENV' }, 'development');
124
+
125
+ if (driver === 'smtp' || stage === 'production') {
126
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
127
+ const { SmtpDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/smtp');
128
+ imports.push(MailModule.register({ deliveryStrategy: SmtpDeliveryStrategy }));
129
+ } else {
130
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
131
+ const { LogDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/log');
132
+ imports.push(MailModule.register({ deliveryStrategy: LogDeliveryStrategy }));
133
+ }
134
+
135
+ return imports;
136
+ },
137
+ {
138
+ appFactory: (module) => NestFactory.create<NestExpressApplication>(module, new ExpressAdapter()),
139
+ }
140
+ );
141
+
142
+ await builder
143
+ .use(useApi({ prefix: 'api' }))
144
+ .listenFromConfig({ fallbackPort: 3000 });
145
+ }
146
+
147
+ void main();
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Custom Composition Resolver
153
+
154
+ For complex applications, encapsulate composition logic in a dedicated resolver class:
155
+
156
+ ### 1. Define the Resolver
157
+
158
+ ```typescript
159
+ // src/composition/AppCompositionResolver.ts
160
+ import { Injectable } from '@nestjs/common';
161
+ import { ConfigService, createConfigKey } from '@breadstone/archipel-platform-configuration';
162
+ import { CompositionResolver } from '@breadstone/archipel-platform-bootstrap/composition';
163
+
164
+ const MAIL_DRIVER = createConfigKey<string>('MAIL_DRIVER');
165
+ const NODE_ENV = createConfigKey<string>('NODE_ENV');
166
+ const FEATURE_NEW_PAYMENTS = createConfigKey<string>('FEATURE_NEW_PAYMENTS');
167
+
168
+ @Injectable()
169
+ export class AppCompositionResolver extends CompositionResolver {
170
+ public constructor(configService: ConfigService) {
171
+ super(configService);
172
+ }
173
+
174
+ public shouldImportProvider(providerKey: string): boolean {
175
+ switch (providerKey) {
176
+ case 'smtp-mail':
177
+ return this.shouldUseSmtpMail();
178
+ case 'log-mail':
179
+ return !this.shouldUseSmtpMail();
180
+ case 'stripe-payments':
181
+ return this.shouldUseStripePayments();
182
+ case 'paddle-payments':
183
+ return !this.shouldUseStripePayments();
184
+ default:
185
+ return false;
186
+ }
187
+ }
188
+
189
+ public shouldUseSmtpMail(): boolean {
190
+ const driver = this.tryGetConfigValue(MAIL_DRIVER, 'log');
191
+ return driver === 'smtp' || this.isProductionLike();
192
+ }
193
+
194
+ public shouldUseStripePayments(): boolean {
195
+ const feature = this.tryGetConfigValue(FEATURE_NEW_PAYMENTS, 'disabled');
196
+ return feature !== 'paddle';
197
+ }
198
+
199
+ public isProductionLike(): boolean {
200
+ const stage = this.tryGetConfigValue(NODE_ENV, 'development');
201
+ return stage === 'production' || stage === 'staging';
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### 2. Create a Composition Module
207
+
208
+ ```typescript
209
+ // src/composition/AppCompositionModule.ts
210
+ import { Module } from '@nestjs/common';
211
+ import { ConfigModule, EnvironmentConfigStrategy } from '@breadstone/archipel-platform-configuration';
212
+ import { AppCompositionResolver } from './AppCompositionResolver';
213
+
214
+ @Module({
215
+ imports: [
216
+ ConfigModule.forRoot({
217
+ strategyFactory: () => new EnvironmentConfigStrategy(),
218
+ }),
219
+ ],
220
+ providers: [AppCompositionResolver],
221
+ exports: [ConfigModule, AppCompositionResolver],
222
+ })
223
+ export class AppCompositionModule {}
224
+ ```
225
+
226
+ ### 3. Use in Bootstrap
227
+
228
+ ```typescript
229
+ // src/main.ts
230
+ import { PlatformApplicationBuilder, CompositionImport } from '@breadstone/archipel-platform-bootstrap';
231
+ import { AppCompositionModule, AppCompositionResolver } from './composition';
232
+ import { AppModule } from './AppModule';
233
+
234
+ async function main(): Promise<void> {
235
+ const builder = await PlatformApplicationBuilder.createWithComposition(
236
+ async (context) => {
237
+ const resolver = context.getService(AppCompositionResolver);
238
+ const imports: CompositionImport[] = [AppModule];
239
+
240
+ // Mail provider
241
+ if (resolver.shouldImportProvider('smtp-mail')) {
242
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
243
+ const { SmtpDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/smtp');
244
+ imports.push(MailModule.register({ deliveryStrategy: SmtpDeliveryStrategy }));
245
+ } else {
246
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
247
+ const { LogDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/log');
248
+ imports.push(MailModule.register({ deliveryStrategy: LogDeliveryStrategy }));
249
+ }
250
+
251
+ // Payment provider
252
+ if (resolver.shouldImportProvider('stripe-payments')) {
253
+ const { PaymentModule } = await import('@breadstone/archipel-platform-payments');
254
+ const { StripeClient } = await import('@breadstone/archipel-platform-payments/stripe');
255
+ imports.push(PaymentModule.register({ paymentClient: StripeClient }));
256
+ } else if (resolver.shouldImportProvider('paddle-payments')) {
257
+ const { PaymentModule } = await import('@breadstone/archipel-platform-payments');
258
+ const { PaddleClient } = await import('@breadstone/archipel-platform-payments/paddle');
259
+ imports.push(PaymentModule.register({ paymentClient: PaddleClient }));
260
+ }
261
+
262
+ return imports;
263
+ },
264
+ {
265
+ compositionModule: AppCompositionModule,
266
+ }
267
+ );
268
+
269
+ await builder.listenFromConfig({ fallbackPort: 3000 });
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Provider Composer Pattern
276
+
277
+ For reusable provider composition, define composer functions:
278
+
279
+ ```typescript
280
+ // src/composition/composers/composeMailProvider.ts
281
+ import type { ICompositionContext } from '@breadstone/archipel-platform-bootstrap/composition';
282
+ import type { CompositionImport } from '@breadstone/archipel-platform-bootstrap';
283
+ import { AppCompositionResolver } from '../AppCompositionResolver';
284
+
285
+ export async function composeMailProvider(context: ICompositionContext): Promise<CompositionImport | null> {
286
+ const resolver = context.getService(AppCompositionResolver);
287
+
288
+ if (resolver.shouldImportProvider('smtp-mail')) {
289
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
290
+ const { SmtpDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/smtp');
291
+ return MailModule.register({ deliveryStrategy: SmtpDeliveryStrategy });
292
+ }
293
+
294
+ if (resolver.shouldImportProvider('log-mail')) {
295
+ const { MailModule } = await import('@breadstone/archipel-platform-mailing');
296
+ const { LogDeliveryStrategy } = await import('@breadstone/archipel-platform-mailing/delivering/log');
297
+ return MailModule.register({ deliveryStrategy: LogDeliveryStrategy });
298
+ }
299
+
300
+ return null;
301
+ }
302
+ ```
303
+
304
+ Then compose cleanly in main:
305
+
306
+ ```typescript
307
+ const builder = await PlatformApplicationBuilder.createWithComposition(
308
+ async (context) => {
309
+ const imports: CompositionImport[] = [AppModule];
310
+
311
+ const mailModule = await composeMailProvider(context);
312
+ if (mailModule) imports.push(mailModule);
313
+
314
+ const paymentModule = await composePaymentProvider(context);
315
+ if (paymentModule) imports.push(paymentModule);
316
+
317
+ return imports;
318
+ },
319
+ { compositionModule: AppCompositionModule }
320
+ );
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Testing Composition
326
+
327
+ ### Unit Testing a Resolver
328
+
329
+ ```typescript
330
+ import { describe, it, expect, vi, afterEach } from 'vitest';
331
+ import { ConfigService } from '@breadstone/archipel-platform-configuration';
332
+ import { AppCompositionResolver } from './AppCompositionResolver';
333
+
334
+ describe('AppCompositionResolver', () => {
335
+ afterEach(() => {
336
+ vi.restoreAllMocks();
337
+ });
338
+
339
+ it('uses SMTP in production regardless of driver setting', () => {
340
+ const configService = {
341
+ get: vi.fn((key: string) => {
342
+ if (key === 'MAIL_DRIVER') return 'log';
343
+ if (key === 'NODE_ENV') return 'production';
344
+ return undefined;
345
+ }),
346
+ tryGet: vi.fn((key: string, fallback: string) => {
347
+ if (key === 'MAIL_DRIVER') return 'log';
348
+ if (key === 'NODE_ENV') return 'production';
349
+ return fallback;
350
+ }),
351
+ } as unknown as ConfigService;
352
+
353
+ const resolver = new AppCompositionResolver(configService);
354
+
355
+ expect(resolver.shouldImportProvider('smtp-mail')).toBe(true);
356
+ expect(resolver.shouldImportProvider('log-mail')).toBe(false);
357
+ });
358
+ });
359
+ ```
360
+
361
+ ### Integration Testing with Real Context
362
+
363
+ ```typescript
364
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
365
+ import { createCompositionContext } from '@breadstone/archipel-platform-bootstrap/composition';
366
+ import { AppCompositionModule, AppCompositionResolver } from './composition';
367
+
368
+ describe('Composition Integration', () => {
369
+ let originalEnv: Record<string, string | undefined>;
370
+
371
+ beforeEach(() => {
372
+ originalEnv = {
373
+ MAIL_DRIVER: process.env['MAIL_DRIVER'],
374
+ NODE_ENV: process.env['NODE_ENV'],
375
+ };
376
+ });
377
+
378
+ afterEach(() => {
379
+ for (const [key, value] of Object.entries(originalEnv)) {
380
+ if (value === undefined) {
381
+ delete process.env[key];
382
+ } else {
383
+ process.env[key] = value;
384
+ }
385
+ }
386
+ });
387
+
388
+ it('resolves correct mail provider for production', async () => {
389
+ process.env['NODE_ENV'] = 'production';
390
+ process.env['MAIL_DRIVER'] = 'log';
391
+
392
+ const context = await createCompositionContext({
393
+ module: AppCompositionModule,
394
+ });
395
+
396
+ try {
397
+ const resolver = context.getService(AppCompositionResolver);
398
+ expect(resolver.shouldImportProvider('smtp-mail')).toBe(true);
399
+ } finally {
400
+ await context.close();
401
+ }
402
+ });
403
+ });
404
+ ```
405
+
406
+ ---
407
+
408
+ ## API Reference
409
+
410
+ ### createCompositionContext
411
+
412
+ ```typescript
413
+ function createCompositionContext(
414
+ options?: ICreateCompositionContextOptions
415
+ ): Promise<ICompositionContext>;
416
+ ```
417
+
418
+ | Option | Type | Default | Description |
419
+ | ------ | ---- | ------- | ----------- |
420
+ | `module` | `Type<unknown>` | `CompositionModule` | Custom composition module |
421
+ | `enableLogging` | `boolean` | `false` | Enable NestJS logger output |
422
+
423
+ ### PlatformApplicationBuilder.createWithComposition
424
+
425
+ ```typescript
426
+ static async createWithComposition<TApp extends INestApplication>(
427
+ composer: (context: ICompositionContext) => Promise<CompositionImport[]> | CompositionImport[],
428
+ options?: ICreateWithCompositionOptions<TApp>
429
+ ): Promise<PlatformApplicationBuilder<TApp>>;
430
+ ```
431
+
432
+ | Option | Type | Default | Description |
433
+ | ------ | ---- | ------- | ----------- |
434
+ | `compositionModule` | `Type<unknown>` | `CompositionModule` | Custom composition module |
435
+ | `enableCompositionLogging` | `boolean` | `false` | Enable logging during composition |
436
+ | `nestOptions` | `NestApplicationOptions` | `undefined` | Options for `NestFactory.create()` |
437
+ | `platformOptions` | `IPlatformApplicationOptions` | `undefined` | Options for the builder |
438
+ | `appFactory` | `(module: DynamicModule) => Promise<TApp>` | `undefined` | Custom app factory |
439
+
440
+ ---
441
+
442
+ ## Best Practices
443
+
444
+ 1. **Keep composition modules minimal** — Only configuration and resolver services. No database, queues, or heavy infrastructure.
445
+
446
+ 2. **Use dynamic imports** — Import provider modules only when needed to reduce bundle size and startup time.
447
+
448
+ 3. **Encapsulate decisions in resolvers** — Don't scatter `process.env` checks. Centralize in a `CompositionResolver`.
449
+
450
+ 4. **Test resolvers in isolation** — Unit test the decision logic separately from NestJS bootstrap.
451
+
452
+ 5. **Close the context** — Always call `context.close()` when using `createCompositionContext()` directly.
453
+
454
+ 6. **Prefer `tryGetConfigValue` over `getConfigValue`** — Provide sensible defaults for optional configuration.
455
+
456
+ ---
457
+
458
+ ## See Also
459
+
460
+ - [Application Bootstrap](./application-bootstrap) — Standard bootstrap pipeline without composition
461
+ - [Configuration Management](./configuration) — Typed configuration keys and strategies
462
+ - [Implementing Ports](./implementing-ports) — Port/adapter pattern for swappable implementations
@@ -48,19 +48,19 @@ npx prisma init
48
48
 
49
49
  `platform-database` ships its own config keys and a ready-made entries array. Set the relevant variables in your environment:
50
50
 
51
- ```env
51
+ ```dotenv
52
52
  DATABASE_URL=postgresql://user:password@localhost:5432/mydb
53
53
  ```
54
54
 
55
55
  For Prisma Accelerate (managed connection pooling), add the Accelerate URL from the Prisma Console:
56
56
 
57
- ```env
57
+ ```dotenv
58
58
  DB_ACCELERATE_URL=prisma://accelerate.prisma-data.net/?api_key=your-accelerate-api-key
59
59
  ```
60
60
 
61
61
  Optional environment variables for Prisma Optimize (query analysis dashboard):
62
62
 
63
- ```env
63
+ ```dotenv
64
64
  DB_OPTIMIZE=true
65
65
  DB_OPTIMIZE_API_KEY=your-optimize-api-key
66
66
  ```
@@ -120,7 +120,7 @@ Accelerate provides connection pooling, global caching, and query optimization
120
120
 
121
121
  Set `DB_ACCELERATE_URL` in your environment. The module reads it automatically via `ConfigService` — no code changes needed:
122
122
 
123
- ```env
123
+ ```dotenv
124
124
  DB_ACCELERATE_URL=prisma://accelerate.prisma-data.net/?api_key=your-accelerate-api-key
125
125
  ```
126
126
 
@@ -96,7 +96,7 @@ This ensures that importing the core package does **not** pull in provider-speci
96
96
 
97
97
  ### Core Variables
98
98
 
99
- ```env
99
+ ```dotenv
100
100
  MAIL_TEMPLATE_ENGINE_FORMAT=html
101
101
  MAIL_SENDER_EMAIL=noreply@yourapp.com
102
102
  ```
@@ -109,7 +109,7 @@ The delivery strategy and template-fetch strategy are no longer configured via e
109
109
 
110
110
  #### SMTP
111
111
 
112
- ```env
112
+ ```dotenv
113
113
  MAIL_SMTP_HOST=smtp.example.com
114
114
  MAIL_SMTP_PORT=587
115
115
  MAIL_SMTP_USER=user@example.com
@@ -119,25 +119,25 @@ MAIL_SMTP_SECURE=true
119
119
 
120
120
  #### Resend
121
121
 
122
- ```env
122
+ ```dotenv
123
123
  MAIL_RESEND_API_KEY=re_...
124
124
  ```
125
125
 
126
126
  #### Postmark
127
127
 
128
- ```env
128
+ ```dotenv
129
129
  MAIL_POSTMARK_API_KEY=...
130
130
  ```
131
131
 
132
132
  #### SendGrid
133
133
 
134
- ```env
134
+ ```dotenv
135
135
  MAIL_SENDGRID_API_KEY=SG...
136
136
  ```
137
137
 
138
138
  #### Mailgun
139
139
 
140
- ```env
140
+ ```dotenv
141
141
  MAIL_MAILGUN_API_KEY=key-...
142
142
  MAIL_MAILGUN_DOMAIN=mg.yourapp.com
143
143
  ```
@@ -14,6 +14,7 @@ Practical guides for working with Archipel packages in your NestJS application.
14
14
  | [Getting Started](./getting-started) | Install packages, register your first module, implement ports, and run the app. |
15
15
  | [Configuration Management](./configuration) | Type-safe config keys, strategy-based resolution, central registry, and validation. |
16
16
  | [Application Bootstrap](./application-bootstrap) | Compose NestJS startup with platform-bootstrap, Express middleware, security, sessions, and OpenAPI. |
17
+ | [Composition Context](./composition-context) | Stage-aware, configuration-driven module composition without direct process.env access. |
17
18
  | [Implementing Ports](./implementing-ports) | How the port/adapter pattern works, how to write adapters, and how to test them. |
18
19
  | [Controller Best Practices](./controller-best-practices) | Structure, annotate, and implement controllers — regions, DI, ResponseReturn, guards, and the @Api decorator. |
19
20
  | [Request & Response DTOs](./request-response-dtos) | DTO naming conventions, validation decorators, cross-field validation, and class-transformer integration. |
@@ -24,7 +24,7 @@ yarn add @breadstone/archipel-platform-openapi
24
24
 
25
25
  All four variables are **required**:
26
26
 
27
- ```env
27
+ ```dotenv
28
28
  APP_VERSION=1.0.0
29
29
  SWAGGER_CONTACT_NAME=Your Team
30
30
  SWAGGER_CONTACT_URL=https://yourcompany.com
@@ -40,7 +40,7 @@ yarn add @vercel/queue
40
40
 
41
41
  ### Core Variables
42
42
 
43
- ```env
43
+ ```dotenv
44
44
  QUEUE_MAX_JOBS=10000
45
45
  ```
46
46
 
@@ -48,7 +48,7 @@ QUEUE_MAX_JOBS=10000
48
48
 
49
49
  ### BullMQ Variables
50
50
 
51
- ```env
51
+ ```dotenv
52
52
  BULLMQ_REDIS_URL=redis://localhost:6379
53
53
  BULLMQ_PREFIX=myapp:
54
54
  ```
@@ -57,7 +57,7 @@ BULLMQ_PREFIX=myapp:
57
57
 
58
58
  ### Azure Service Bus Variables
59
59
 
60
- ```env
60
+ ```dotenv
61
61
  AZURE_CONNECTION_STRING=Endpoint=sb://my-namespace.servicebus.windows.net/;SharedAccessKeyName=...;SharedAccessKey=...
62
62
  AZURE_RECEIVE_WAIT_MS=5000
63
63
  ```
@@ -66,7 +66,7 @@ AZURE_RECEIVE_WAIT_MS=5000
66
66
 
67
67
  ### Vercel Queues Variables
68
68
 
69
- ```env
69
+ ```dotenv
70
70
  VERCEL_QUEUE_REGION=iad1
71
71
  VERCEL_QUEUE_CONSUMER_GROUP=my-consumer
72
72
  VERCEL_QUEUE_TOKEN=
@@ -43,7 +43,7 @@ When `enabled` is `false`, the module provides a no-op facade (`NoopTelemetryFac
43
43
 
44
44
  ## Configuration
45
45
 
46
- ```env
46
+ ```dotenv
47
47
  TELEMETRY_ENABLED=true
48
48
  TELEMETRY_SERVICE_NAME=my-api
49
49
  TELEMETRY_EXPORTER_ENDPOINT=https://otel-collector.example.com:4318