@bluealba/platform-cli 1.0.1 → 1.0.2

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 (42) hide show
  1. package/dist/index.js +277 -9
  2. package/docs/404.mdx +5 -0
  3. package/docs/architecture/api-explorer.mdx +478 -0
  4. package/docs/architecture/architecture-diagrams.mdx +12 -0
  5. package/docs/architecture/authentication-system.mdx +903 -0
  6. package/docs/architecture/authorization-system.mdx +886 -0
  7. package/docs/architecture/bootstrap.mdx +1442 -0
  8. package/docs/architecture/gateway-architecture.mdx +845 -0
  9. package/docs/architecture/multi-tenancy.mdx +1150 -0
  10. package/docs/architecture/overview.mdx +776 -0
  11. package/docs/architecture/scheduler.mdx +818 -0
  12. package/docs/architecture/shell.mdx +885 -0
  13. package/docs/architecture/ui-extension-points.mdx +781 -0
  14. package/docs/architecture/user-states.mdx +794 -0
  15. package/docs/development/overview.mdx +21 -0
  16. package/docs/development/workflow.mdx +914 -0
  17. package/docs/getting-started/core-concepts.mdx +892 -0
  18. package/docs/getting-started/installation.mdx +780 -0
  19. package/docs/getting-started/overview.mdx +83 -0
  20. package/docs/getting-started/quick-start.mdx +940 -0
  21. package/docs/guides/adding-documentation-sites.mdx +1367 -0
  22. package/docs/guides/creating-services.mdx +1736 -0
  23. package/docs/guides/creating-ui-modules.mdx +1860 -0
  24. package/docs/guides/identity-providers.mdx +1007 -0
  25. package/docs/guides/mermaid-diagrams.mdx +212 -0
  26. package/docs/guides/using-feature-flags.mdx +1059 -0
  27. package/docs/guides/working-with-rooms.mdx +566 -0
  28. package/docs/index.mdx +57 -0
  29. package/docs/platform-cli/commands.mdx +604 -0
  30. package/docs/platform-cli/overview.mdx +195 -0
  31. package/package.json +5 -2
  32. package/skills/ba-platform/platform-cli.skill.md +26 -0
  33. package/skills/ba-platform/platform.skill.md +35 -0
  34. package/templates/application-monorepo-template/gitignore +95 -0
  35. package/templates/bootstrap-service-template/gitignore +57 -0
  36. package/templates/bootstrap-service-template/src/main.ts +6 -16
  37. package/templates/customization-ui-module-template/gitignore +73 -0
  38. package/templates/nestjs-service-module-template/gitignore +56 -0
  39. package/templates/platform-init-template/{{platformName}}-core/gitignore +97 -0
  40. package/templates/react-ui-module-template/Dockerfile +1 -1
  41. package/templates/react-ui-module-template/caddy/Caddyfile +1 -1
  42. package/templates/react-ui-module-template/gitignore +72 -0
@@ -0,0 +1,845 @@
1
+ ---
2
+ title: Gateway Service Architecture
3
+ description: Deep dive into the PAE NestJS Gateway Service - routing, proxying, HTTP/2, WebSocket, catalog integration, and platform context
4
+ ---
5
+
6
+ import { Card, CardGrid, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
7
+
8
+ The **PAE NestJS Gateway Service** is the central entry point for all platform traffic. Built with NestJS and Fastify, it handles authentication, authorization, routing, and request proxying to backend services and micro-frontends.
9
+
10
+ ## Role and Responsibilities
11
+
12
+ The gateway acts as a **reverse proxy** and **API gateway** with the following responsibilities:
13
+
14
+ <CardGrid stagger>
15
+ <Card title="Traffic Entry Point" icon="star">
16
+ Single entry point for all HTTP and WebSocket traffic, handling SSL termination and HTTP/2
17
+ </Card>
18
+
19
+ <Card title="Authentication" icon="approve-check">
20
+ Validates JWT tokens, API keys, and service credentials for every request
21
+ </Card>
22
+
23
+ <Card title="Authorization" icon="shield">
24
+ Enforces RBAC policies and operation-based access control before proxying requests
25
+ </Card>
26
+
27
+ <Card title="Request Routing" icon="random">
28
+ Resolves target services dynamically using the catalog and forwards requests
29
+ </Card>
30
+
31
+ <Card title="Context Management" icon="seti:json">
32
+ Manages tenant, user, and application context throughout request lifecycle
33
+ </Card>
34
+
35
+ <Card title="Header Enrichment" icon="seti:config">
36
+ Adds platform context headers to forwarded requests for downstream services
37
+ </Card>
38
+ </CardGrid>
39
+
40
+ ---
41
+
42
+ ## Architecture Overview
43
+
44
+ ```
45
+ ┌─────────────────────────────────────────────────────────────────┐
46
+ │ PAE NestJS Gateway │
47
+ │ │
48
+ │ ┌────────────────────────────────────────────────────────────┐ │
49
+ │ │ HTTP/2 Server (Fastify) │ │
50
+ │ │ SSL/TLS Termination │ │
51
+ │ └────────────────────┬───────────────────────────────────────┘ │
52
+ │ │ │
53
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
54
+ │ │ Authentication Middleware │ │
55
+ │ │ • JWT Validation (Cookie-based) │ │
56
+ │ │ • API Key Validation │ │
57
+ │ │ • Service-to-Service Auth │ │
58
+ │ └────────────────────┬───────────────────────────────────────┘ │
59
+ │ │ │
60
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
61
+ │ │ Tenant Resolution Middleware │ │
62
+ │ │ • Subdomain Pattern Matching │ │
63
+ │ │ • URL Pattern Matching │ │
64
+ │ │ • Cookie/Header-based Resolution │ │
65
+ │ └────────────────────┬───────────────────────────────────────┘ │
66
+ │ │ │
67
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
68
+ │ │ Platform Context Setup │ │
69
+ │ │ • Store tenant, user, app in request context │ │
70
+ │ │ • Validate tenant access for user │ │
71
+ │ └────────────────────┬───────────────────────────────────────┘ │
72
+ │ │ │
73
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
74
+ │ │ Catalog Route Resolution │ │
75
+ │ │ • Query catalog for target module │ │
76
+ │ │ • Match request path to module routes │ │
77
+ │ │ • Handle tenant-based module restrictions │ │
78
+ │ └────────────────────┬───────────────────────────────────────┘ │
79
+ │ │ │
80
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
81
+ │ │ Authorization Guard │ │
82
+ │ │ • Check user has required operations │ │
83
+ │ │ • Evaluate authorization rules │ │
84
+ │ │ • Enforce tenant-scoped access │ │
85
+ │ └────────────────────┬───────────────────────────────────────┘ │
86
+ │ │ │
87
+ │ ┌────────────────────▼───────────────────────────────────────┐ │
88
+ │ │ Proxy Middleware │ │
89
+ │ │ • Add forwarding headers │ │
90
+ │ │ • Sign requests for cloud functions │ │
91
+ │ │ • Forward to target service │ │
92
+ │ └────────────────────┬───────────────────────────────────────┘ │
93
+ └────────────────────────┼───────────────────────────────────────┘
94
+
95
+ ┌────────────────┼────────────────┐
96
+ ▼ ▼ ▼
97
+ ┌─────────┐ ┌──────────┐ ┌──────────────┐
98
+ │ Service │ │ UI │ │ Lambda │
99
+ │ A │ │ Shell │ │ Function │
100
+ └─────────┘ └──────────┘ └──────────────┘
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Core Modules
106
+
107
+ ### 1. Authentication Module
108
+
109
+ Handles all authentication mechanisms.
110
+
111
+ **Location**: `apps/pae-nestjs-gateway-service/src/authentication/`
112
+
113
+ **Key Components**:
114
+ - `authentication.service.ts` - Core authentication logic
115
+ - `guards/auth.guard.ts` - Authentication guard for routes
116
+ - `guards/auth.middleware.ts` - Authentication middleware
117
+ - `api-keys/` - API key authentication
118
+ - `oauth-providers/` - Multi-IDP OAuth support
119
+ - `impersonation/` - User impersonation feature
120
+
121
+ **Supported Authentication Methods**:
122
+
123
+ <Tabs>
124
+ <TabItem label="JWT Cookie">
125
+ ```typescript
126
+ // Extract JWT from HTTP-only cookie
127
+ const token = request.cookies[AUTH_COOKIE_NAME];
128
+ const user = await jwtService.verify(token, { secret });
129
+
130
+ // Decoded JWT contains:
131
+ {
132
+ id: 'user-123',
133
+ username: 'john@acme.com',
134
+ displayName: 'John Doe',
135
+ tenantId: 'acme',
136
+ groups: ['admins', 'users'],
137
+ applications: ['app-1', 'app-2']
138
+ }
139
+ ```
140
+ </TabItem>
141
+
142
+ <TabItem label="API Key">
143
+ ```typescript
144
+ // Extract API key from Authorization header
145
+ const apiKey = extractBearerToken(request);
146
+
147
+ // Validate against database
148
+ const user = await apiKeysService.getUserForApiKey(apiKey);
149
+
150
+ // Returns user context if valid
151
+ ```
152
+ </TabItem>
153
+
154
+ <TabItem label="Service-to-Service">
155
+ ```typescript
156
+ // Special case: SERVICE_ACCESS_SECRET
157
+ if (apiKey === process.env.SERVICE_ACCESS_SECRET) {
158
+ return {
159
+ id: 'service',
160
+ username: 'service',
161
+ displayName: 'Service Account',
162
+ authProviderName: 'service-access',
163
+ groups: [],
164
+ applications: []
165
+ };
166
+ }
167
+ ```
168
+ </TabItem>
169
+ </Tabs>
170
+
171
+ <Aside type="note">
172
+ The authentication guard runs on **every request** except public routes. Public routes are marked with `@Public()` decorator or match configured passthrough patterns.
173
+ </Aside>
174
+
175
+ ---
176
+
177
+ ### 2. Authorization Module
178
+
179
+ Enforces access control policies.
180
+
181
+ **Location**: `apps/pae-nestjs-gateway-service/src/authorization/`
182
+
183
+ **Key Components**:
184
+ - `authorization.service.ts` - Authorization logic
185
+ - `authorization.guard.ts` - Authorization guard
186
+
187
+ **Authorization Flow**:
188
+
189
+ ```typescript
190
+ async authorizeRequest(context: ExecutionContext, username: string, tenantId?: number) {
191
+ // 1. Get user's allowed resources (applications + operations), filtered by tenant
192
+ const allowedResources = await authzService.getAuthorizedResourcesForUser(username, tenantId);
193
+
194
+ // 2. Get catalog and resolve target module
195
+ const catalog = await catalogService.getCatalog();
196
+ const targetModule = catalogService.resolveTargetModule(catalog, requestPath);
197
+
198
+ // 3. Check if user is authorized for this module/path/method
199
+ const isAuthorized = paeInstance.isAuthorized(
200
+ targetModule,
201
+ catalog,
202
+ allowedResources,
203
+ requestPath,
204
+ requestMethod
205
+ );
206
+
207
+ // 4. Add authorization headers for downstream services
208
+ this.addAuthzHeaders(context, allowedResources);
209
+
210
+ return isAuthorized;
211
+ }
212
+ ```
213
+
214
+ **Authorization Headers Added**:
215
+
216
+ ```http
217
+ x-forwarded-user-operations: users::read,users::write,orders::read
218
+ ```
219
+
220
+ ---
221
+
222
+ ### 3. Tenant Module
223
+
224
+ Manages multi-tenancy.
225
+
226
+ **Location**: `apps/pae-nestjs-gateway-service/src/tenants/`
227
+
228
+ **Key Components**:
229
+ - `tenants.service.ts` - Tenant CRUD operations
230
+ - `tenant-resolver.service.ts` - Tenant resolution from requests
231
+ - `pattern-matchers/` - URL pattern matching strategies
232
+ - `tenant.guard.ts` - Tenant validation guard
233
+
234
+ **Tenant Resolution Strategies**:
235
+
236
+ <Tabs>
237
+ <TabItem label="Subdomain">
238
+ ```typescript
239
+ // Extract tenant from subdomain
240
+ // acme.platform.com → tenant: 'acme'
241
+
242
+ const host = req.headers.host; // 'acme.platform.com'
243
+ const subdomain = host.split('.')[0]; // 'acme'
244
+ const tenant = await tenantsService.findByCode(subdomain);
245
+ ```
246
+ </TabItem>
247
+
248
+ <TabItem label="Path">
249
+ ```typescript
250
+ // Extract tenant from URL path
251
+ // platform.com/tenants/acme/app → tenant: 'acme'
252
+
253
+ const pathPattern = '/tenants/:tenantCode/*';
254
+ const match = matchPath(req.url, pathPattern);
255
+ const tenant = await tenantsService.findByCode(match.tenantCode);
256
+ ```
257
+ </TabItem>
258
+
259
+ <TabItem label="Header">
260
+ ```typescript
261
+ // Extract tenant from custom header
262
+ // x-tenant-id: acme → tenant: 'acme'
263
+
264
+ const tenantCode = req.headers['x-tenant-id'];
265
+ const tenant = await tenantsService.findByCode(tenantCode);
266
+ ```
267
+ </TabItem>
268
+
269
+ <TabItem label="Cookie">
270
+ ```typescript
271
+ // Extract tenant from cookie
272
+ // tenant=acme → tenant: 'acme'
273
+
274
+ const tenantCode = req.cookies['tenant'];
275
+ const tenant = await tenantsService.findByCode(tenantCode);
276
+ ```
277
+ </TabItem>
278
+
279
+ <TabItem label="Query Param">
280
+ ```typescript
281
+ // Extract tenant from query parameter
282
+ // ?tenant=acme → tenant: 'acme'
283
+
284
+ const tenantCode = req.query.tenant;
285
+ const tenant = await tenantsService.findByCode(tenantCode);
286
+ ```
287
+ </TabItem>
288
+ </Tabs>
289
+
290
+ **Tenant URL Patterns**:
291
+
292
+ Tenants can be configured with multiple URL patterns:
293
+
294
+ ```typescript
295
+ interface TenantUrlPattern {
296
+ id: string;
297
+ tenantId: string;
298
+ type: 'SUBDOMAIN' | 'PATH' | 'CUSTOM_DOMAIN' | 'QUERY_PARAM' | 'HEADER';
299
+ pattern: string;
300
+ priority: number; // Higher priority patterns checked first
301
+ }
302
+
303
+ // Examples:
304
+ {
305
+ type: 'SUBDOMAIN',
306
+ pattern: 'acme.platform.com'
307
+ }
308
+
309
+ {
310
+ type: 'CUSTOM_DOMAIN',
311
+ pattern: 'acme-corp.com'
312
+ }
313
+
314
+ {
315
+ type: 'PATH',
316
+ pattern: '/t/acme/*'
317
+ }
318
+ ```
319
+
320
+ ---
321
+
322
+ ### 4. Catalog Module
323
+
324
+ Dynamic service registry and route resolution.
325
+
326
+ **Location**: `apps/pae-nestjs-gateway-service/src/catalog/`
327
+
328
+ **Key Components**:
329
+ - `catalog.service.ts` - Catalog management
330
+ - `catalog.repository.ts` - Data persistence
331
+ - `catalog-gateway.service.ts` - Gateway-specific catalog logic
332
+
333
+ **Catalog Structure**:
334
+
335
+ ```typescript
336
+ interface CatalogItem {
337
+ id: string;
338
+ name: string;
339
+ code: string;
340
+ type: 'service' | 'app' | 'tool' | 'cloud-function' | 'utility' | 'documentation';
341
+ baseUrl: string;
342
+
343
+ protocol?: 'http' | 'https';
344
+ port: number;
345
+
346
+ ui?: {
347
+ route: string;
348
+ bundleFile: string;
349
+ mountAtSelector: string;
350
+ customProps: {};
351
+ };
352
+
353
+
354
+ // Authorization
355
+ authorization: {
356
+ operations?: string[];
357
+ isPublic?: boolean;
358
+ routes?: {}
359
+ }
360
+
361
+ // Metadata
362
+ createdAt: Date;
363
+ createdBy: string;
364
+ updatedAt: Date;
365
+ updatedBy: string;
366
+ }
367
+ ```
368
+
369
+ **Route Resolution**:
370
+
371
+ ```typescript
372
+ // Example: Resolve target for /api/habits/123
373
+ const catalog = await catalogService.getCatalog();
374
+ const targetModule = catalogService.resolveTargetModule(catalog, '/api/habits/123');
375
+
376
+ // Returns:
377
+ {
378
+ name: 'habits-service',
379
+ type: 'service',
380
+ baseUrl: '/api/habits',
381
+ protocol: 'http',
382
+ port: 80
383
+ }
384
+ ```
385
+
386
+ **Tenant-Scoped Catalog**:
387
+
388
+ The catalog can be filtered by tenant to restrict available modules:
389
+
390
+ ```typescript
391
+ // Get catalog filtered by tenant
392
+ const catalog = await catalogService.getCatalog(tenantId);
393
+
394
+ // Only returns modules assigned to this tenant
395
+ // via tenant_application_restrictions table
396
+ ```
397
+
398
+ ---
399
+
400
+ ### 5. Proxy Module
401
+
402
+ Forwards requests to target services.
403
+
404
+ **Location**: `apps/pae-nestjs-gateway-service/src/proxy/`
405
+
406
+ **Key Components**:
407
+ - `proxy.service.ts` - Request forwarding logic
408
+ - `proxy.middleware.ts` - Proxy middleware
409
+ - `build-forward-url.ts` - URL construction
410
+
411
+ **Proxy Flow**:
412
+
413
+ ```typescript
414
+ async forwardRequest(targetModule: CatalogItem, req: FastifyRequest, reply: FastifyReply) {
415
+ // 1. Build target URL
416
+ const targetUrl = buildForwardURL(targetModule, req, tenantConfig, impersonationMode);
417
+
418
+ // 2. Add forward headers
419
+ const forwardHeaders = {
420
+ 'x-forwarded-host': req.headers.host,
421
+ 'x-forwarded-server': localIpAddress,
422
+ 'x-forwarded-uri': req.url,
423
+ 'x-forwarded-proto': req.protocol,
424
+ 'x-forwarded-for': req.ip,
425
+ 'x-forwarded-user-id': user.id,
426
+ 'x-forwarded-user': user.username,
427
+ 'x-forwarded-user-name': user.displayName,
428
+ 'x-forwarded-user-operations': Array.from(allowedOperations).join(','),
429
+ 'x-forwarded-tenant-config': base64(tenant),
430
+ 'x-forwarded-tenant': base64(tenant), // only in multi-tenant mode
431
+ 'x-forwarded-allowed-tenants': base64(tenant), // only in multi-tenant mode
432
+ };
433
+
434
+ // 3. Sign request if cloud function requires it
435
+ if (targetModule.cloudFunction?.requiresSignature) {
436
+ const signature = await signCloudFunctionRequest(req, targetModule, targetUrl);
437
+ Object.assign(forwardHeaders, signature);
438
+ }
439
+
440
+ // 4. Forward request using Fastify reply-from
441
+ reply.from(targetUrl, {
442
+ rewriteRequestHeaders: (_, headers) => ({
443
+ ...headers,
444
+ ...forwardHeaders
445
+ })
446
+ });
447
+ }
448
+ ```
449
+
450
+ **Forward Headers**:
451
+
452
+ The gateway adds these headers to every proxied request:
453
+
454
+ ```http
455
+ x-forwarded-host: platform.com
456
+ x-forwarded-server: 192.168.1.10
457
+ x-forwarded-uri: /api/habits/123
458
+ x-forwarded-protocol: https
459
+ x-forwarded-for: 203.0.113.45
460
+ x-forwarded-user-id: john@acme.com
461
+ x-forwarded-user: john@acme.com
462
+ x-forwarded-user-name: John Doe
463
+ x-forwarded-auth-provider-name: okta
464
+ x-forwarded-tenant: eyJ0ZW5hbnRJZCI6ImFjbWUifQ==
465
+ x-forwarded-tenant-config: eyJtb2RlIjoibXVsdGktdGVuYW50In0=
466
+ x-forwarded-allowed-tenants: W3siaWQiOiJhY21lIn1d
467
+ x-forwarded-user-operations: habits.read,habits.write,habits.delete
468
+ ```
469
+
470
+ <Aside type="tip" title="Service Implementation">
471
+ Backend services should extract these headers to get platform context. The `pae-service-nestjs-sdk` provides decorators to automatically extract context:
472
+
473
+ ```typescript
474
+ @Get()
475
+ async findAll(@PlatformContext() ctx: PlatformContext) {
476
+ // ctx contains tenant, user, and other context
477
+ }
478
+ ```
479
+ </Aside>
480
+
481
+ ---
482
+
483
+ ### 6. Platform Context Module
484
+
485
+ Manages request-scoped context.
486
+
487
+ **Location**: `apps/pae-nestjs-gateway-service/src/platform-context/`
488
+
489
+ **Key Component**:
490
+ - `context/context.service.ts` - Context management using nestjs-cls
491
+
492
+ **Context Storage**:
493
+
494
+ The gateway uses `nestjs-cls` (Continuation-Local Storage) to store request-scoped data:
495
+
496
+ ```typescript
497
+ @Injectable()
498
+ export class PlatformContextService {
499
+ constructor(private readonly cls: ClsService) {}
500
+
501
+ // Store session
502
+ setSession(session: Session) {
503
+ this.cls.set('pae::session', session);
504
+ }
505
+
506
+ // Store user
507
+ setAuthUser(user: AuthUserWithApplications) {
508
+ this.cls.set('pae::authUser', user);
509
+ }
510
+
511
+ // Store tenant
512
+ setTenant(tenant: Tenant | null) {
513
+ this.cls.set('tenant', tenant);
514
+ }
515
+
516
+ // Store target module
517
+ setTargetModule(targetModule: CatalogItem) {
518
+ this.cls.set('targetModule', targetModule);
519
+ }
520
+
521
+ // Retrieve from context
522
+ getAuthUser(): AuthUserWithApplications {
523
+ return this.cls.get('pae::authUser');
524
+ }
525
+ }
526
+ ```
527
+
528
+ **Context Flow**:
529
+
530
+ ```
531
+ 1. Request arrives
532
+ 2. Authentication middleware → setSession(), setAuthUser()
533
+ 3. Tenant middleware → setTenant()
534
+ 4. Catalog middleware → setTargetModule()
535
+ 5. Any service/guard can access context via PlatformContextService
536
+ 6. Request completes → context automatically cleaned up
537
+ ```
538
+
539
+ ---
540
+
541
+ ## HTTP/2 and WebSocket Support
542
+
543
+ ### HTTP/2 Configuration
544
+
545
+ The gateway uses Fastify with HTTP/2 support:
546
+
547
+ ```typescript
548
+ // apps/pae-nestjs-gateway-service/src/main.ts
549
+ const httpsOptions = {
550
+ http2: true,
551
+ https: {
552
+ key: fs.readFileSync(process.env.SSL_KEY_PATH),
553
+ cert: fs.readFileSync(process.env.SSL_CERT_PATH)
554
+ }
555
+ };
556
+
557
+ const app = await NestFactory.create<FastifyAdapter>(
558
+ AppModule,
559
+ new FastifyAdapter(httpsOptions)
560
+ );
561
+
562
+ await app.listen(443, '0.0.0.0');
563
+ ```
564
+
565
+ **HTTP/2 Benefits**:
566
+ - Multiplexing: Multiple requests over single connection
567
+ - Header compression: Reduces bandwidth
568
+ - Server push: Proactive resource delivery
569
+ - Binary protocol: Faster parsing
570
+
571
+ ### WebSocket Support
572
+
573
+ The gateway supports WebSocket connections:
574
+
575
+ ```typescript
576
+ // WebSocket proxying
577
+ const targetWsUrl = targetModule.serviceUrl.replace('http', 'ws');
578
+
579
+ // Forward WebSocket upgrade
580
+ reply.hijack();
581
+ const ws = new WebSocket(targetWsUrl, {
582
+ headers: forwardHeaders
583
+ });
584
+
585
+ // Pipe messages bidirectionally
586
+ clientWs.on('message', data => ws.send(data));
587
+ ws.on('message', data => clientWs.send(data));
588
+ ```
589
+
590
+ ---
591
+
592
+ ## Lambda Function Integration
593
+
594
+ The gateway can route to AWS Lambda functions (or other cloud functions).
595
+
596
+ **Lambda Configuration**:
597
+
598
+ ```typescript
599
+ // Register Lambda function in catalog
600
+ {
601
+ code: 'pdf-generator',
602
+ name: 'PDF Generator Function',
603
+ type: 'CLOUD_FUNCTION',
604
+ baseUrl: '/api/pdf',
605
+ cloudFunction: {
606
+ provider: 'AWS_LAMBDA',
607
+ functionName: 'pae-pdf-generator',
608
+ region: 'us-east-1',
609
+ requiresSignature: true
610
+ }
611
+ }
612
+ ```
613
+
614
+ **Request Signing**:
615
+
616
+ For functions that require AWS Signature V4:
617
+
618
+ ```typescript
619
+ // apps/pae-nestjs-gateway-service/src/proxy/create-cloud-function-signer.ts
620
+ export const createCloudFunctionSigner = (module: CatalogItem, targetUrl: string) => {
621
+ return async (req: FastifyRequest) => {
622
+ const signature = aws4.sign({
623
+ service: 'lambda',
624
+ region: module.cloudFunction.region,
625
+ method: req.method,
626
+ path: new URL(targetUrl).pathname,
627
+ headers: {
628
+ 'content-type': req.headers['content-type'],
629
+ 'host': new URL(targetUrl).host
630
+ },
631
+ body: req.body
632
+ }, {
633
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
634
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
635
+ });
636
+
637
+ return signature.headers;
638
+ };
639
+ };
640
+ ```
641
+
642
+ ---
643
+
644
+ ## Configuration
645
+
646
+ ### Environment Variables
647
+
648
+ The gateway requires these environment variables:
649
+
650
+ <Tabs>
651
+ <TabItem label="Core">
652
+ ```bash
653
+ # Service Access
654
+ SERVICE_ACCESS_SECRET=secret-for-service-to-service-auth
655
+ JWT_SECRET=secret-for-jwt-validation
656
+
657
+ # Authentication Service
658
+ AUTHN_SERVICE_URL=http://pae-authn-service:4000
659
+
660
+ # Ports
661
+ HTTP_PORT=80
662
+ HTTPS_PORT=443
663
+ ```
664
+ </TabItem>
665
+
666
+ <TabItem label="HTTPS">
667
+ ```bash
668
+ # HTTPS Configuration
669
+ HTTPS=true
670
+ HTTP2=true
671
+ SSL_CERT_PATH=/etc/ssl/cert.pem
672
+ SSL_KEY_PATH=/etc/ssl/key.pem
673
+ ```
674
+ </TabItem>
675
+
676
+ <TabItem label="Database">
677
+ ```bash
678
+ # Database
679
+ DB_CLIENT=pg
680
+ DB_URL=postgresql://user:pass@host:5432/db
681
+ ```
682
+ </TabItem>
683
+
684
+ <TabItem label="Optional">
685
+ ```bash
686
+ # Logging
687
+ LOG_LEVEL=debug
688
+ LOG_JSON=true
689
+
690
+ # Observability
691
+ TRACE_URL=http://jaeger:14268/api/traces
692
+
693
+ # Auth Passthrough (regex)
694
+ AUTH_PASSTHROUGH_PATTERN=^/_/.*
695
+
696
+ # AWS (for Lambda)
697
+ AWS_REGION=us-east-1
698
+ AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
699
+ AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
700
+ ```
701
+ </TabItem>
702
+ </Tabs>
703
+
704
+ ---
705
+
706
+ ## Performance Considerations
707
+
708
+ ### Connection Pooling
709
+
710
+ The gateway maintains connection pools to backend services:
711
+
712
+ ```typescript
713
+ // Fastify reply-from configuration
714
+ app.register(fastifyReplyFrom, {
715
+ base: targetUrl,
716
+ // Connection pool settings
717
+ http: {
718
+ connections: 100, // Max connections per host
719
+ pipelining: 10 // Max pipelined requests
720
+ }
721
+ });
722
+ ```
723
+
724
+ ### Caching
725
+
726
+ The catalog is cached to avoid database queries on every request:
727
+
728
+ ```typescript
729
+ // Cache catalog in memory with TTL
730
+ private catalogCache: {
731
+ data: CatalogItem[];
732
+ timestamp: number;
733
+ ttl: number; // 5 minutes
734
+ };
735
+
736
+ async getCatalog() {
737
+ if (this.isCacheValid()) {
738
+ return this.catalogCache.data;
739
+ }
740
+
741
+ const catalog = await this.catalogRepository.findAll();
742
+ this.catalogCache = {
743
+ data: catalog,
744
+ timestamp: Date.now(),
745
+ ttl: 5 * 60 * 1000
746
+ };
747
+
748
+ return catalog;
749
+ }
750
+ ```
751
+
752
+ ### Request Timeouts
753
+
754
+ Configure timeouts to prevent hanging requests:
755
+
756
+ ```typescript
757
+ // Fastify timeout configuration
758
+ const app = await NestFactory.create(AppModule, new FastifyAdapter({
759
+ connectionTimeout: 30000, // 30 seconds
760
+ keepAliveTimeout: 5000 // 5 seconds
761
+ }));
762
+ ```
763
+
764
+ ---
765
+
766
+ ## Error Handling
767
+
768
+ The gateway implements comprehensive error handling:
769
+
770
+ ```typescript
771
+ // Global exception filter
772
+ @Catch()
773
+ export class GlobalExceptionFilter implements ExceptionFilter {
774
+ catch(exception: unknown, host: ArgumentsHost) {
775
+ const ctx = host.switchToHttp();
776
+ const response = ctx.getResponse();
777
+ const request = ctx.getRequest();
778
+
779
+ // Log error with context
780
+ logger.error({
781
+ error: exception,
782
+ path: request.url,
783
+ method: request.method,
784
+ user: request.user?.username,
785
+ tenant: request.tenant?.code
786
+ });
787
+
788
+ // Send appropriate response
789
+ if (exception instanceof HttpException) {
790
+ response.status(exception.getStatus()).send({
791
+ statusCode: exception.getStatus(),
792
+ message: exception.message,
793
+ timestamp: new Date().toISOString(),
794
+ path: request.url
795
+ });
796
+ } else {
797
+ response.status(500).send({
798
+ statusCode: 500,
799
+ message: 'Internal server error',
800
+ timestamp: new Date().toISOString(),
801
+ path: request.url
802
+ });
803
+ }
804
+ }
805
+ }
806
+ ```
807
+
808
+ ---
809
+
810
+ ## Health Checks
811
+
812
+ The gateway exposes health check endpoints:
813
+
814
+ ```http
815
+ GET /_/health
816
+ ```
817
+
818
+ Response:
819
+ ```json
820
+ {
821
+ healthy: 'ok'
822
+ }
823
+ ```
824
+
825
+ ---
826
+
827
+ ## Security Considerations
828
+
829
+ <Aside type="caution" title="Security Best Practices">
830
+ 1. **Always use HTTPS** in production environments
831
+ 2. **Rotate secrets regularly** (JWT_SECRET, SERVICE_ACCESS_SECRET)
832
+ 3. **Keep SSL certificates up to date** - automate renewal with Let's Encrypt
833
+ 4. **Rate limit endpoints** to prevent abuse
834
+ 5. **Validate all inputs** before proxying to services
835
+ 6. **Log security events** (failed auth, authorization denials)
836
+ 7. **Implement CSRF protection** for browser-based requests
837
+ </Aside>
838
+
839
+ ---
840
+
841
+ ## Next Steps
842
+
843
+ - **[Authentication System](/_/docs/architecture/authentication-system/)** - Deep dive into authentication flows
844
+ - **[Authorization System](/_/docs/architecture/authorization-system/)** - Understanding RBAC and permissions
845
+ - **[Multi-Tenancy](/_/docs/architecture/multi-tenancy/)** - Tenant isolation and context