@vritti/api-sdk 0.0.2 → 0.0.5

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.
package/README.md CHANGED
@@ -1,44 +1,494 @@
1
1
  # @vritti/api-sdk
2
2
 
3
- A TypeScript SDK for interacting with Vritti APIs.
3
+ NestJS SDK for multi-tenant applications with automatic database routing, JWT authentication, and request-scoped tenant context management.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@vritti/api-sdk.svg)](https://www.npmjs.com/package/@vritti/api-sdk)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
+ ## Features
9
+
10
+ - 🏢 **Multi-tenant Database Management**: Automatic tenant routing with connection pooling
11
+ - 🔐 **JWT Authentication**: Built-in auth guard with refresh token validation
12
+ - 🌐 **Gateway & Microservice Support**: Optimized for both HTTP APIs and RabbitMQ workers
13
+ - 🎯 **Request-Scoped Context**: Tenant information available throughout the request lifecycle
14
+ - 🛡️ **Decorators**: `@Public()`, `@Onboarding()`, and `@Tenant()` for flexible access control
15
+ - ⚡ **Zero Configuration**: Auto-registers guards and interceptors
16
+
8
17
  ## Installation
9
18
 
10
19
  ```bash
11
20
  # npm
12
- npm install @vritti/api-sdk
21
+ npm install @vritti/api-sdk @nestjs/jwt @nestjs/config @prisma/client
13
22
 
14
23
  # yarn
15
- yarn add @vritti/api-sdk
24
+ yarn add @vritti/api-sdk @nestjs/jwt @nestjs/config @prisma/client
16
25
 
17
26
  # pnpm
18
- pnpm add @vritti/api-sdk
27
+ pnpm add @vritti/api-sdk @nestjs/jwt @nestjs/config @prisma/client
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ### Gateway Mode (HTTP API)
33
+
34
+ For REST APIs and GraphQL gateways that serve HTTP requests:
35
+
36
+ ```typescript
37
+ import { Module } from '@nestjs/common';
38
+ import { ConfigModule, ConfigService } from '@nestjs/config';
39
+ import { PrismaClient } from '@prisma/client';
40
+ import { AuthConfigModule, DatabaseModule } from '@vritti/api-sdk';
41
+
42
+ @Module({
43
+ imports: [
44
+ // Environment configuration
45
+ ConfigModule.forRoot({ isGlobal: true }),
46
+
47
+ // Multi-tenant database (Gateway mode)
48
+ DatabaseModule.forServer({
49
+ inject: [ConfigService],
50
+ useFactory: (config: ConfigService) => ({
51
+ primaryDb: {
52
+ host: config.get('PRIMARY_DB_HOST'),
53
+ port: config.get('PRIMARY_DB_PORT'),
54
+ username: config.get('PRIMARY_DB_USERNAME'),
55
+ password: config.get('PRIMARY_DB_PASSWORD'),
56
+ database: config.get('PRIMARY_DB_DATABASE'),
57
+ },
58
+ prismaClientConstructor: PrismaClient,
59
+ }),
60
+ }),
61
+
62
+ // JWT authentication
63
+ AuthConfigModule.forRootAsync(),
64
+ ],
65
+ })
66
+ export class AppModule {}
67
+ ```
68
+
69
+ ### Microservice Mode (RabbitMQ Workers)
70
+
71
+ For microservices that process messages from queues:
72
+
73
+ ```typescript
74
+ import { Module } from '@nestjs/common';
75
+ import { ConfigModule, ConfigService } from '@nestjs/config';
76
+ import { PrismaClient } from '@prisma/client';
77
+ import { AuthConfigModule, DatabaseModule } from '@vritti/api-sdk';
78
+
79
+ @Module({
80
+ imports: [
81
+ ConfigModule.forRoot({ isGlobal: true }),
82
+
83
+ // Multi-tenant database (Microservice mode)
84
+ DatabaseModule.forMicroservice({
85
+ inject: [ConfigService],
86
+ useFactory: (config: ConfigService) => ({
87
+ prismaClientConstructor: PrismaClient,
88
+ }),
89
+ }),
90
+
91
+ AuthConfigModule.forRootAsync(),
92
+ ],
93
+ })
94
+ export class AppModule {}
95
+ ```
96
+
97
+ ## Environment Variables
98
+
99
+ ### Required for All Modes
100
+
101
+ ```bash
102
+ JWT_SECRET=your-access-token-secret-key
103
+ ```
104
+
105
+ ### Required for Gateway Mode
106
+
107
+ ```bash
108
+ # Primary database (tenant registry)
109
+ PRIMARY_DB_HOST=localhost
110
+ PRIMARY_DB_PORT=5432
111
+ PRIMARY_DB_USERNAME=postgres
112
+ PRIMARY_DB_PASSWORD=postgres
113
+ PRIMARY_DB_DATABASE=vritti_primary
114
+ PRIMARY_DB_SCHEMA=public
115
+
116
+ # Optional
117
+ JWT_REFRESH_SECRET=your-refresh-token-secret-key
118
+ PRIMARY_DB_SSL_MODE=prefer # Options: require, prefer, disable
119
+ ```
120
+
121
+ ## Usage Examples
122
+
123
+ ### Public Endpoints
124
+
125
+ Use `@Public()` to bypass authentication:
126
+
127
+ ```typescript
128
+ import { Controller, Post, Body } from '@nestjs/common';
129
+ import { Public } from '@vritti/api-sdk';
130
+
131
+ @Controller('auth')
132
+ export class AuthController {
133
+ @Public()
134
+ @Post('login')
135
+ async login(@Body() dto: LoginDto) {
136
+ // No authentication required
137
+ return this.authService.login(dto);
138
+ }
139
+ }
140
+ ```
141
+
142
+ ### Onboarding Endpoints
143
+
144
+ Use `@Onboarding()` for registration/verification flows:
145
+
146
+ ```typescript
147
+ import { Controller, Post, Request } from '@nestjs/common';
148
+ import { Onboarding } from '@vritti/api-sdk';
149
+
150
+ @Controller('onboarding')
151
+ export class OnboardingController {
152
+ @Onboarding()
153
+ @Post('verify-email')
154
+ async verifyEmail(@Request() req) {
155
+ const userId = req.user.id; // Available from auth guard
156
+ return this.onboardingService.verifyEmail(userId);
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### Accessing Tenant Information
162
+
163
+ Use `@Tenant()` to inject tenant metadata:
164
+
165
+ ```typescript
166
+ import { Controller, Get, Post, Body } from '@nestjs/common';
167
+ import { Tenant, TenantInfo } from '@vritti/api-sdk';
168
+
169
+ @Controller('users')
170
+ export class UsersController {
171
+ @Get('info')
172
+ async getTenantInfo(@Tenant() tenant: TenantInfo) {
173
+ return {
174
+ id: tenant.id,
175
+ subdomain: tenant.subdomain,
176
+ type: tenant.type, // STARTER, PROFESSIONAL, ENTERPRISE
177
+ };
178
+ }
179
+
180
+ @Post()
181
+ async createUser(
182
+ @Body() dto: CreateUserDto,
183
+ @Tenant() tenant: TenantInfo,
184
+ ) {
185
+ this.logger.log(`Creating user for tenant: ${tenant.subdomain}`);
186
+ // Tenant-specific logic
187
+ if (tenant.type === 'ENTERPRISE') {
188
+ // Enable enterprise features
189
+ }
190
+ return this.usersService.create(dto);
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### Using Tenant Database Service
196
+
197
+ Access tenant-specific database connections:
198
+
199
+ ```typescript
200
+ import { Injectable } from '@nestjs/common';
201
+ import { TenantDatabaseService } from '@vritti/api-sdk';
202
+
203
+ @Injectable()
204
+ export class UsersService {
205
+ constructor(
206
+ private readonly tenantDb: TenantDatabaseService,
207
+ ) {}
208
+
209
+ async findAll() {
210
+ // Automatically uses tenant's database
211
+ const db = await this.tenantDb.getClient();
212
+ return db.user.findMany();
213
+ }
214
+
215
+ async create(data: CreateUserDto) {
216
+ const db = await this.tenantDb.getClient();
217
+ return db.user.create({ data });
218
+ }
219
+ }
220
+ ```
221
+
222
+ ### Using Base Repositories
223
+
224
+ The SDK provides base repository classes for common CRUD operations with automatic tenant scoping:
225
+
226
+ #### Primary Database Repositories
227
+
228
+ For entities in the primary/platform database (tenants, users, sessions, etc.):
229
+
230
+ ```typescript
231
+ import { Injectable } from '@nestjs/common';
232
+ import { PrimaryBaseRepository, PrimaryDatabaseService } from '@vritti/api-sdk';
233
+ import { User, CreateUserDto, UpdateUserDto } from './types';
234
+
235
+ @Injectable()
236
+ export class UserRepository extends PrimaryBaseRepository<
237
+ User,
238
+ CreateUserDto,
239
+ UpdateUserDto
240
+ > {
241
+ constructor(database: PrimaryDatabaseService) {
242
+ // Use model delegate pattern - type-safe with IDE autocomplete!
243
+ super(database, (prisma) => prisma.user);
244
+ }
245
+
246
+ // Add custom methods as needed
247
+ async findByEmail(email: string): Promise<User | null> {
248
+ return this.model.findUnique({ where: { email } });
249
+ }
250
+
251
+ async findActiveUsers(): Promise<User[]> {
252
+ return this.model.findMany({
253
+ where: { status: 'ACTIVE' },
254
+ orderBy: { createdAt: 'desc' },
255
+ });
256
+ }
257
+ }
258
+ ```
259
+
260
+ #### Tenant Database Repositories
261
+
262
+ For tenant-scoped entities (products, orders, customers, etc.):
263
+
264
+ ```typescript
265
+ import { Injectable } from '@nestjs/common';
266
+ import { TenantBaseRepository, TenantDatabaseService } from '@vritti/api-sdk';
267
+ import { Product, CreateProductDto, UpdateProductDto } from './types';
268
+
269
+ @Injectable()
270
+ export class ProductRepository extends TenantBaseRepository<
271
+ Product,
272
+ CreateProductDto,
273
+ UpdateProductDto
274
+ > {
275
+ constructor(database: TenantDatabaseService) {
276
+ // Short syntax is also supported
277
+ super(database, (p) => p.product);
278
+ }
279
+
280
+ // Custom methods for product-specific queries
281
+ async findBySku(sku: string): Promise<Product | null> {
282
+ return this.model.findUnique({ where: { sku } });
283
+ }
284
+
285
+ async findInStock(): Promise<Product[]> {
286
+ return this.model.findMany({
287
+ where: { quantity: { gt: 0 } },
288
+ });
289
+ }
290
+ }
291
+ ```
292
+
293
+ #### Available Base Repository Methods
294
+
295
+ Both `PrimaryBaseRepository` and `TenantBaseRepository` provide these methods:
296
+
297
+ ```typescript
298
+ // Create
299
+ await repository.create(data);
300
+
301
+ // Read
302
+ await repository.findById(id);
303
+ await repository.findOne({ where: { email } });
304
+ await repository.findMany({ where: { status: 'ACTIVE' } });
305
+
306
+ // Update
307
+ await repository.update(id, data);
308
+ await repository.updateMany({ status: 'PENDING' }, { status: 'ACTIVE' });
309
+
310
+ // Delete
311
+ await repository.delete(id);
312
+ await repository.deleteMany({ status: 'INACTIVE' });
313
+
314
+ // Count & Exists
315
+ await repository.count({ status: 'ACTIVE' });
316
+ await repository.exists({ email: 'user@example.com' });
19
317
  ```
20
318
 
21
- ## Usage
319
+ #### Benefits of the Model Delegate Pattern
22
320
 
23
321
  ```typescript
24
- import { getHello } from '@vritti/api-sdk';
322
+ // Type-safe with IDE autocomplete
323
+ super(database, (prisma) => prisma.user);
324
+
325
+ // ✅ Refactor-friendly - TypeScript errors if model name changes
326
+ super(database, (p) => p.emailVerification);
327
+
328
+ // ✅ Works with complex model names
329
+ super(database, (p) => p.inventoryItem);
25
330
 
26
- const message = getHello();
27
- console.log(message); // "Hello, World!"
331
+ // No hardcoded strings
332
+ // ❌ Old way: super(database, 'user') // Error-prone!
28
333
  ```
29
334
 
30
- ## API Documentation
335
+ ## Architecture
336
+
337
+ ### Gateway Mode (`forServer()`)
338
+
339
+ **How it works:**
340
+ 1. HTTP request arrives with tenant identifier (subdomain or `x-tenant-id` header)
341
+ 2. `TenantContextInterceptor` extracts tenant identifier
342
+ 3. `PrimaryDatabaseService` queries tenant registry for configuration
343
+ 4. `VrittiAuthGuard` validates JWT tokens and tenant status
344
+ 5. Tenant context is available throughout the request via `TenantContextService`
31
345
 
32
- ### `getHello()`
346
+ **Tenant Resolution:**
347
+ - Primary: Subdomain (`acme.api.vritti.com` → `acme`)
348
+ - Fallback: `x-tenant-id` header
33
349
 
34
- Returns a greeting message.
350
+ ### Microservice Mode (`forMicroservice()`)
351
+
352
+ **How it works:**
353
+ 1. RabbitMQ message arrives with embedded tenant information
354
+ 2. `MessageTenantContextInterceptor` extracts tenant from message payload
355
+ 3. Tenant context is set in `TenantContextService`
356
+ 4. No primary database lookup needed (tenant info comes from gateway)
357
+
358
+ **Expected Message Format:**
359
+ ```typescript
360
+ {
361
+ dto: { /* your data */ },
362
+ tenant: {
363
+ id: 'tenant-uuid',
364
+ subdomain: 'acme',
365
+ type: 'ENTERPRISE',
366
+ databaseHost: 'tenant-db.aws.com',
367
+ databaseName: 'acme_db',
368
+ // ... other config
369
+ }
370
+ }
371
+ ```
35
372
 
36
- **Returns:** `string` - A hello world message
373
+ ## API Reference
374
+
375
+ ### Modules
376
+
377
+ #### `DatabaseModule`
378
+
379
+ - **`forServer(options)`**: Configure for Gateway/HTTP mode
380
+ - **`forMicroservice(options)`**: Configure for RabbitMQ/messaging mode
381
+
382
+ #### `AuthConfigModule`
383
+
384
+ - **`forRootAsync()`**: Register JWT authentication with global guard
385
+
386
+ ### Services
387
+
388
+ #### `TenantDatabaseService`
389
+
390
+ Access tenant-specific database connections.
391
+
392
+ ```typescript
393
+ class TenantDatabaseService {
394
+ async getClient<T = any>(): Promise<T>
395
+ clearConnection(tenantId: string): void
396
+ }
397
+ ```
398
+
399
+ #### `PrimaryDatabaseService`
400
+
401
+ Access the primary/platform database (tenant registry). Use this for cloud-api operations like managing tenants, users, sessions, etc.
402
+
403
+ ```typescript
404
+ class PrimaryDatabaseService {
405
+ async getPrimaryDbClient<T = any>(): Promise<T>
406
+ async getTenantInfo(identifier: string): Promise<TenantInfo | null>
407
+ }
408
+ ```
37
409
 
38
410
  **Example:**
39
411
  ```typescript
40
- const greeting = getHello();
41
- // Returns: "Hello, World!"
412
+ @Injectable()
413
+ export class TenantRepository {
414
+ constructor(private readonly database: PrimaryDatabaseService) {}
415
+
416
+ async findAll() {
417
+ const prisma = await this.database.getPrimaryDbClient<PrismaClient>();
418
+ return prisma.tenant.findMany();
419
+ }
420
+ }
421
+ ```
422
+
423
+ #### `TenantContextService`
424
+
425
+ Manage request-scoped tenant context.
426
+
427
+ ```typescript
428
+ class TenantContextService {
429
+ getTenant(): TenantInfo
430
+ setTenant(tenant: TenantInfo): void
431
+ hasTenant(): boolean
432
+ clearTenant(): void
433
+ }
434
+ ```
435
+
436
+ ### Decorators
437
+
438
+ #### `@Public()`
439
+
440
+ Bypass authentication on specific endpoints.
441
+
442
+ #### `@Onboarding()`
443
+
444
+ Accept only onboarding tokens (for registration/verification flows).
445
+
446
+ #### `@Tenant()`
447
+
448
+ Inject tenant metadata into controller methods.
449
+
450
+ ### Interfaces
451
+
452
+ #### `TenantInfo`
453
+
454
+ ```typescript
455
+ interface TenantInfo {
456
+ id: string;
457
+ subdomain: string;
458
+ type: 'STARTER' | 'PROFESSIONAL' | 'ENTERPRISE';
459
+ status: 'ACTIVE' | 'INACTIVE' | 'SUSPENDED';
460
+ databaseHost: string;
461
+ databasePort?: number;
462
+ databaseName: string;
463
+ databaseUsername: string;
464
+ databasePassword: string;
465
+ databaseSchema?: string;
466
+ sslMode?: 'require' | 'prefer' | 'disable';
467
+ }
468
+ ```
469
+
470
+ #### `DatabaseModuleOptions`
471
+
472
+ ```typescript
473
+ interface DatabaseModuleOptions {
474
+ // Gateway mode only
475
+ primaryDb?: {
476
+ host: string;
477
+ port?: number;
478
+ username: string;
479
+ password: string;
480
+ database: string;
481
+ schema?: string;
482
+ sslMode?: 'require' | 'prefer' | 'disable';
483
+ };
484
+
485
+ // Required for both modes
486
+ prismaClientConstructor: any;
487
+
488
+ // Optional
489
+ connectionCacheTTL?: number; // Default: 300000 (5 minutes)
490
+ maxConnections?: number; // Default: 10
491
+ }
42
492
  ```
43
493
 
44
494
  ## Development
@@ -47,11 +497,10 @@ const greeting = getHello();
47
497
 
48
498
  - Node.js 18+
49
499
  - Yarn
500
+ - PostgreSQL (for testing)
50
501
 
51
502
  ### Setup
52
503
 
53
- Clone the repository and install dependencies:
54
-
55
504
  ```bash
56
505
  git clone https://github.com/vritti-hub/api-sdk.git
57
506
  cd api-sdk
@@ -60,14 +509,13 @@ yarn install
60
509
 
61
510
  ### Available Scripts
62
511
 
63
- - `yarn dev` - Run the SDK in watch mode using tsx
64
- - `yarn build` - Build the SDK for production (outputs CJS and ESM formats)
65
- - `yarn type-check` - Run TypeScript type checking
512
+ - `yarn dev` - Run in watch mode
513
+ - `yarn build` - Build for production
514
+ - `yarn type-check` - TypeScript type checking
66
515
  - `yarn test` - Run tests
67
516
  - `yarn test:watch` - Run tests in watch mode
68
- - `yarn lint` - Lint source files with ESLint
517
+ - `yarn lint` - Lint source files
69
518
  - `yarn format` - Format code with Prettier
70
- - `yarn format:check` - Check code formatting
71
519
  - `yarn clean` - Remove build artifacts
72
520
 
73
521
  ### Project Structure
@@ -75,40 +523,166 @@ yarn install
75
523
  ```
76
524
  api-sdk/
77
525
  ├── src/
78
- └── index.ts # Main entry point
79
- ├── dist/ # Build output (generated)
80
- ├── .prettierrc # Prettier configuration
81
- ├── eslint.config.js # ESLint configuration
82
- ├── tsconfig.json # TypeScript configuration
83
- └── package.json # Package configuration
526
+ ├── auth/ # Authentication module
527
+ │ │ ├── guards/ # VrittiAuthGuard
528
+ │ │ ├── decorators/ # @Public, @Onboarding
529
+ │ │ └── auth-config.module.ts
530
+ ├── database/ # Database module
531
+ │ │ ├── services/ # Database services
532
+ │ │ ├── interceptors/ # Tenant context interceptors
533
+ │ │ ├── decorators/ # @Tenant
534
+ │ │ ├── interfaces/ # TypeScript interfaces
535
+ │ │ └── database.module.ts
536
+ │ ├── request/ # Request utilities (internal)
537
+ │ └── index.ts # Public API exports
538
+ ├── dist/ # Build output
539
+ └── package.json
84
540
  ```
85
541
 
86
- ## Building
542
+ ## Best Practices
87
543
 
88
- The SDK is built using [tsup](https://tsup.egoist.dev/) which generates both CommonJS and ESM outputs with TypeScript declarations:
544
+ ### 1. Environment Variables
89
545
 
90
- ```bash
91
- yarn build
546
+ Always use `ConfigService` and validate environment variables at startup:
547
+
548
+ ```typescript
549
+ import { plainToClass } from 'class-transformer';
550
+ import { IsString, IsNumber, validateSync } from 'class-validator';
551
+
552
+ class EnvironmentVariables {
553
+ @IsString()
554
+ JWT_SECRET: string;
555
+
556
+ @IsString()
557
+ PRIMARY_DB_HOST: string;
558
+
559
+ @IsNumber()
560
+ PRIMARY_DB_PORT: number;
561
+ }
562
+
563
+ export function validate(config: Record<string, unknown>) {
564
+ const validatedConfig = plainToClass(EnvironmentVariables, config, {
565
+ enableImplicitConversion: true,
566
+ });
567
+ const errors = validateSync(validatedConfig, {
568
+ skipMissingProperties: false,
569
+ });
570
+
571
+ if (errors.length > 0) {
572
+ throw new Error(errors.toString());
573
+ }
574
+ return validatedConfig;
575
+ }
92
576
  ```
93
577
 
94
- This will create:
95
- - `dist/index.js` - ESM build
96
- - `dist/index.cjs` - CommonJS build
97
- - `dist/index.d.ts` - TypeScript declarations for ESM
98
- - `dist/index.d.cts` - TypeScript declarations for CJS
578
+ ### 2. Database Connections
99
579
 
100
- ## Testing
580
+ Let the SDK manage connection pooling. Don't create custom Prisma instances:
101
581
 
102
- Run the test suite:
582
+ ```typescript
583
+ // ✅ Good
584
+ @Injectable()
585
+ export class UsersService {
586
+ constructor(private readonly tenantDb: TenantDatabaseService) {}
587
+
588
+ async findAll() {
589
+ const db = await this.tenantDb.getClient();
590
+ return db.user.findMany();
591
+ }
592
+ }
593
+
594
+ // ❌ Bad - Don't do this
595
+ @Injectable()
596
+ export class UsersService {
597
+ private prisma = new PrismaClient(); // ❌ Breaks multi-tenancy
598
+ }
599
+ ```
103
600
 
104
- ```bash
105
- yarn test
601
+ ### 3. Tenant Context
602
+
603
+ Always use `@Tenant()` decorator instead of manually accessing `TenantContextService`:
604
+
605
+ ```typescript
606
+ // ✅ Good
607
+ @Get('info')
608
+ async getInfo(@Tenant() tenant: TenantInfo) {
609
+ return { subdomain: tenant.subdomain };
610
+ }
611
+
612
+ // ❌ Bad - Avoid manual service injection
613
+ @Get('info')
614
+ async getInfo() {
615
+ const tenant = this.tenantContext.getTenant(); // ❌ Unnecessary
616
+ }
106
617
  ```
107
618
 
108
- Run tests in watch mode during development:
619
+ ## Troubleshooting
109
620
 
110
- ```bash
111
- yarn test:watch
621
+ ### Issue: "TenantContextService not found"
622
+
623
+ **Cause:** DatabaseModule not imported or registered incorrectly.
624
+
625
+ **Solution:** Ensure `DatabaseModule.forServer()` or `forMicroservice()` is imported in your module.
626
+
627
+ ### Issue: "JWT secret not configured"
628
+
629
+ **Cause:** Missing `JWT_SECRET` environment variable.
630
+
631
+ **Solution:** Add `JWT_SECRET` to your `.env` file.
632
+
633
+ ### Issue: "Tenant identifier not found"
634
+
635
+ **Cause:** Request missing subdomain and `x-tenant-id` header.
636
+
637
+ **Solution:** Ensure requests include tenant identifier:
638
+ - Use subdomain: `https://acme.api.vritti.com`
639
+ - Or add header: `x-tenant-id: acme`
640
+
641
+ ### Issue: "Connection pool exhausted"
642
+
643
+ **Cause:** Too many concurrent tenants or connections not released.
644
+
645
+ **Solution:** Increase `maxConnections` in DatabaseModule options:
646
+
647
+ ```typescript
648
+ DatabaseModule.forServer({
649
+ useFactory: () => ({
650
+ // ...
651
+ maxConnections: 20, // Increase from default 10
652
+ }),
653
+ })
654
+ ```
655
+
656
+ ## Migration Guide
657
+
658
+ ### From Manual Setup to SDK
659
+
660
+ If you're migrating from a manual setup:
661
+
662
+ 1. Remove manual interceptor registrations
663
+ 2. Remove manual guard registrations
664
+ 3. Replace custom tenant context with `@Tenant()` decorator
665
+ 4. Update imports to use SDK exports
666
+
667
+ **Before:**
668
+ ```typescript
669
+ @Module({
670
+ imports: [RequestModule],
671
+ providers: [
672
+ { provide: APP_GUARD, useClass: VrittiAuthGuard },
673
+ { provide: APP_INTERCEPTOR, useClass: TenantContextInterceptor },
674
+ ],
675
+ })
676
+ ```
677
+
678
+ **After:**
679
+ ```typescript
680
+ @Module({
681
+ imports: [
682
+ DatabaseModule.forServer({ /* config */ }),
683
+ AuthConfigModule.forRootAsync(),
684
+ ],
685
+ })
112
686
  ```
113
687
 
114
688
  ## Contributing