@flusys/nestjs-core 4.0.1 → 4.1.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 (2) hide show
  1. package/README.md +462 -562
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,742 +1,642 @@
1
- # Core Package Guide
1
+ # @flusys/nestjs-core
2
2
 
3
- > **Package:** `@flusys/nestjs-core`
4
- > **Version:** 4.0.1
5
- > **Type:** Pure TypeScript foundation (zero NestJS dependencies)
3
+ > Foundation infrastructure for NestJS applications — type-safe environment configuration, TypeORM migration CLI, intelligent data seeding, and modular Swagger documentation.
6
4
 
7
- Foundation layer providing type-safe configuration, database utilities, migration CLI, seeders with intelligent pattern detection, and Swagger setup.
5
+ [![npm version](https://img.shields.io/npm/v/@flusys/nestjs-core.svg)](https://www.npmjs.com/package/@flusys/nestjs-core)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![NestJS](https://img.shields.io/badge/NestJS-11.x-red.svg)](https://nestjs.com/)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
9
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18.x-green.svg)](https://nodejs.org/)
10
+
11
+ ---
8
12
 
9
13
  ## Table of Contents
10
14
 
11
- - [Package Architecture](#package-architecture)
12
- - [Environment Configuration](#environment-configuration)
13
- - [Database Interfaces](#database-interfaces)
14
- - [Migration System](#migration-system)
15
+ - [Overview](#overview)
16
+ - [Features](#features)
17
+ - [Architecture](#architecture)
18
+ - [Compatibility](#compatibility)
19
+ - [Installation](#installation)
20
+ - [Environment Setup](#environment-setup)
21
+ - [Quick Start](#quick-start)
22
+ - [EnvConfigService](#envconfigservice)
23
+ - [Migration CLI](#migration-cli)
24
+ - [Migration Config File](#migration-config-file)
25
+ - [CLI Commands](#cli-commands)
26
+ - [Programmatic API](#programmatic-api)
15
27
  - [Seed System](#seed-system)
16
- - [Field Pattern Detection](#field-pattern-detection)
28
+ - [BaseSeeder](#baseseeder)
29
+ - [SeedRunner](#seedrunner)
30
+ - [DataGenerator](#datagenerator)
31
+ - [Seed CLI](#seed-cli)
17
32
  - [Swagger Documentation](#swagger-documentation)
18
- - [API Reference](#api-reference)
33
+ - [setupSwaggerDocs](#setupswaggerdocs)
34
+ - [setupModuleSwaggerDocs](#setupmoduleswaggerdocs)
35
+ - [Database Utilities](#database-utilities)
36
+ - [Core Interfaces](#core-interfaces)
37
+ - [Injection Tokens & Constants](#injection-tokens--constants)
38
+ - [Multi-Tenant Support](#multi-tenant-support)
39
+ - [Troubleshooting](#troubleshooting)
40
+ - [License](#license)
19
41
 
20
42
  ---
21
43
 
22
- ## Package Architecture
44
+ ## Overview
23
45
 
24
- ```
25
- nestjs-core/src/
26
- ├── config/
27
- │ └── env-config.service.ts # Environment configuration singleton
28
- ├── constants/
29
- │ └── database.constants.ts # MODULE_OPTIONS, DEFAULT_TENANT_HEADER
30
- ├── interfaces/
31
- │ ├── app-config.interfaces.ts # IBootstrapAppConfig, IDynamicModuleConfig
32
- │ ├── base-entity.interface.ts # IBaseEntity, ISoftDeletable, ITimestampable
33
- │ ├── database.interface.ts # IDatabaseConfig, ITenantDatabaseConfig, IDataSourceBuildOptions
34
- │ └── migration.interface.ts # IMigrationConfig, IMigrationResult
35
- ├── utils/
36
- │ └── datasource-config.builder.ts # DataSource utilities
37
- ├── migration/
38
- │ ├── cli.ts # CLI entry point
39
- │ ├── migration.cli.ts # Migration CLI commands
40
- │ ├── datasource.factory.ts # DataSource factory
41
- │ └── migration.runner.ts # Migration execution
42
- ├── seeders/
43
- │ ├── cli.ts # Seed CLI entry point
44
- │ ├── base-seeder.ts # Abstract base seeder class
45
- │ ├── seed-runner.ts # Seed orchestration
46
- │ ├── seed-config.ts # Global seed configuration
47
- │ ├── entity-reader.ts # TypeORM metadata extraction
48
- │ ├── data-generator.ts # Faker.js data generation
49
- │ └── field-patterns.ts # Intelligent field pattern detection
50
- ├── docs/
51
- │ └── docs.config.ts # Swagger setup utilities
52
- └── index.ts
53
- ```
46
+ `@flusys/nestjs-core` is the lowest-level dependency in the FLUSYS NestJS monorepo. Every other package depends on it.
47
+
48
+ **Key design decision:** This package is **pure TypeScript with zero NestJS runtime dependencies** (except the isolated `docs/` module). The migration and seed CLIs run as standalone Node.js processes — no NestJS app bootstrap required. This makes it usable in CI pipelines, build scripts, and non-NestJS tools.
54
49
 
55
50
  ---
56
51
 
57
- ## Environment Configuration
52
+ ## Features
58
53
 
59
- ```typescript
60
- import { envConfig } from '@flusys/nestjs-core/config';
54
+ - **Type-safe environment config** — Strongly typed `process.env` access with restricted key protection and validation
55
+ - **Migration CLI** Full CLI and programmatic API for TypeORM migrations, including multi-tenant (run-for-all-tenants)
56
+ - **Data seeder** — Metadata-driven test data generation with Faker.js, topological sort for dependency resolution, and custom seeder support
57
+ - **Swagger setup** — Modular API documentation with advanced filtering by tags, schemas, parameters, and examples
58
+ - **DataSource utilities** — TypeORM DataSource configuration builders for single and multi-tenant setups
59
+ - **Core interfaces** — Contract definitions (entities, config, database, migrations) used by all feature modules
60
+ - **SnakeNamingStrategy** — All columns use `snake_case` by default via `typeorm-naming-strategies`
61
+
62
+ ---
63
+
64
+ ## Architecture
65
+
66
+ ```
67
+ @flusys/nestjs-core ← THIS PACKAGE (pure TypeScript)
68
+
69
+ @flusys/nestjs-shared ← NestJS shared infrastructure
70
+
71
+ auth | iam | storage | email | form-builder | event-manager | notification | localization
61
72
  ```
62
73
 
63
- ### Available Methods
64
-
65
- | Method | Description |
66
- |--------|-------------|
67
- | `tryGetValue(key, throwOnMissing?)` | Get env value (throws for restricted keys) |
68
- | `getNumber(key, throwOnMissing?)` | Get env value as number |
69
- | `getBoolean(key, throwOnMissing?)` | Get env value as boolean |
70
- | `getPort()` | Get PORT (default: 3000) |
71
- | `isProduction()` | Check if MODE !== 'DEV' |
72
- | `getFrontendUrl()` | Get FRONTEND_URL |
73
- | `getOrigins()` | Get ALLOW_ORIGINS as comma-separated array |
74
- | `getTypeOrmConfig()` | Get database config |
75
- | `getJwtConfig()` | Get JWT config (secret, expiration, refreshSecret, refreshExpiration) |
76
- | `getRedisUrl()` | Get Redis connection URL (default: redis://localhost:6379) |
77
- | `getMailConfig()` | Get mail configuration (MAIL_FROM, MAIL_APP_PASSWORD) |
78
- | `getTenantId()` | Get TENANT_ID |
79
- | `useTenantMode()` | Check USE_TENANT_MODE |
80
- | `getLogConfig()` | Get logging config `{ dir, level, maxSize, maxFiles }` |
81
- | `getEnv()` | Get all env vars as `Record<string, string>` |
74
+ `nestjs-core` is the only FLUSYS package with no upstream FLUSYS dependencies. All other packages depend on it.
82
75
 
83
- ### Restricted Keys
76
+ ---
84
77
 
85
- The following keys require using specific methods (prevents misuse):
78
+ ## Compatibility
86
79
 
87
- | Key | Use Instead |
88
- |-----|-------------|
89
- | `FRONTEND_URL` | `getFrontendUrl()` |
90
- | `ALLOW_ORIGINS` | `getOrigins()` |
91
- | `PORT` | `getPort()` |
92
- | `MODE` | `isProduction()` |
93
- | `DB_HOST/PORT/USER/PASSWORD` | `getTypeOrmConfig()` |
80
+ | Package | Version |
81
+ |---------|---------|
82
+ | `typeorm` | `^0.3.0` |
83
+ | `typeorm-naming-strategies` | `^4.1.0` |
84
+ | `@faker-js/faker` | `^8.0.0` |
85
+ | `dotenv` | `^16.0.0` |
86
+ | `@nestjs/common` | `^11.0.0` *(docs/ only)* |
87
+ | `@nestjs/swagger` | `^8.0.0` *(docs/ only)* |
88
+ | Node.js | `>= 18.x` |
89
+ | TypeScript | `>= 5.0` |
94
90
 
95
91
  ---
96
92
 
97
- ## Database Interfaces
93
+ ## Installation
98
94
 
99
- ### Core Interfaces
95
+ ```bash
96
+ npm install @flusys/nestjs-core
97
+ ```
100
98
 
101
- ```typescript
102
- type DatabaseType = 'mysql' | 'postgres' | 'mariadb' | 'sqlite' | 'mssql';
103
- type DatabaseMode = 'single' | 'multi-tenant';
99
+ ```bash
100
+ # Peer dependencies
101
+ npm install typeorm typeorm-naming-strategies @faker-js/faker dotenv
104
102
 
105
- interface IDatabaseConfig {
106
- type: DatabaseType;
107
- host?: string;
108
- port?: number;
109
- username?: string;
110
- password?: string;
111
- database?: string;
112
- }
103
+ # For migration and seed CLIs
104
+ npm install -D ts-node tsconfig-paths
113
105
 
114
- interface ITenantDatabaseConfig {
115
- id: string;
116
- database: string;
117
- name?: string;
118
- host?: string;
119
- port?: number;
120
- username?: string;
121
- password?: string;
122
- enableCompanyFeature?: boolean;
123
- enableEmailVerification?: boolean;
124
- permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
125
- }
106
+ # For Swagger (docs/ module only)
107
+ npm install @nestjs/common @nestjs/swagger
108
+ ```
126
109
 
127
- interface IBootstrapAppConfig {
128
- databaseMode: 'single' | 'multi-tenant';
129
- enableCompanyFeature: boolean;
130
- permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
131
- enableEmailVerification?: boolean;
132
- }
110
+ ---
133
111
 
134
- interface IDataSourceBuildOptions {
135
- type: string;
136
- host?: string;
137
- port?: number;
138
- username?: string;
139
- password?: string;
140
- database: string;
141
- entities: any[];
142
- migrations: string[];
143
- migrationsTableName: string;
144
- synchronize: boolean;
145
- namingStrategy?: any;
146
- }
112
+ ## Environment Setup
113
+
114
+ Create a `.env` file in your project root:
115
+
116
+ ```env
117
+ PORT=2002
118
+ MODE=dev
119
+ FRONTEND_URL=http://localhost:2001
120
+ ALLOW_ORIGINS=http://localhost:2001,http://localhost:3000
121
+
122
+ # Database
123
+ DB_HOST=localhost
124
+ DB_PORT=5432
125
+ DB_USER=postgres
126
+ DB_PASSWORD=password
127
+ DB_NAME=myapp
128
+
129
+ # JWT
130
+ JWT_SECRET=your-jwt-secret-min-32-chars
131
+ JWT_EXPIRATION=15m
132
+ REFRESH_TOKEN_SECRET=your-refresh-secret
133
+ REFRESH_TOKEN_EXPIRATION=7d
134
+
135
+ # Cache
136
+ REDIS_URL=redis://localhost:6379
137
+
138
+ # Email
139
+ MAIL_FROM=noreply@example.com
140
+ MAIL_APP_PASSWORD=app-password
141
+
142
+ # Multi-tenant (optional)
143
+ TENANT_ID=
144
+ USE_TENANT_MODE=false
145
+
146
+ # Logging
147
+ LOG_DIR=logs
148
+ LOG_LEVEL=debug
149
+ LOG_MAX_SIZE=20m
150
+ LOG_MAX_FILES=14d
151
+ DISABLE_HTTP_LOGGING=false
147
152
  ```
148
153
 
149
- ### Entity Interfaces
154
+ ---
150
155
 
151
- ```typescript
152
- interface IBaseEntity {
153
- id: string;
154
- createdAt: Date;
155
- updatedAt: Date;
156
- deletedAt?: Date | null;
157
- }
156
+ ## Quick Start
158
157
 
159
- interface ISoftDeletable {
160
- deletedAt?: Date | null;
161
- }
158
+ ### Environment Config
162
159
 
163
- interface ITimestampable {
164
- createdAt: Date;
165
- updatedAt: Date;
166
- }
160
+ ```typescript
161
+ import { envConfig } from '@flusys/nestjs-core';
162
+
163
+ const port = envConfig.getPort(); // number (default: 3000)
164
+ const isProd = envConfig.isProduction(); // boolean
165
+ const db = envConfig.getTypeOrmConfig(); // { host, port, username, password }
166
+ const jwt = envConfig.getJwtConfig(); // { secret, expiration, refreshSecret, refreshExpiration }
167
+ const origins = envConfig.getOrigins(); // string[] from ALLOW_ORIGINS
168
+ const redis = envConfig.getRedisUrl(); // string
169
+ const mail = envConfig.getMailConfig(); // { MAIL_FROM, MAIL_APP_PASSWORD }
170
+ const logConfig = envConfig.getLogConfig(); // { dir, level, maxSize, maxFiles, disableHttpLogging }
171
+ const tenantId = envConfig.getTenantId(); // string | null
172
+ const multiTenant = envConfig.useTenantMode(); // boolean
173
+
174
+ // Custom variable (throws if missing when throwOnMissing: true)
175
+ const myVar = envConfig.tryGetValue('MY_CUSTOM_VAR', true);
176
+ ```
167
177
 
168
- interface IOrderable {
169
- serial?: number | null;
178
+ ### Add Migration Scripts to package.json
179
+
180
+ ```json
181
+ {
182
+ "scripts": {
183
+ "migration:generate": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli generate",
184
+ "migration:run": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli run",
185
+ "migration:revert": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli revert",
186
+ "migration:status": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli status",
187
+ "migration:run:all": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/migration/cli run:all",
188
+ "seed:run": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli run",
189
+ "seed:clear": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli clear",
190
+ "seed:status": "ts-node -r tsconfig-paths/register ./node_modules/@flusys/nestjs-core/seeders/cli status"
191
+ }
170
192
  }
193
+ ```
171
194
 
172
- interface IMetadata {
173
- metadata?: Record<string, any> | null;
174
- }
195
+ ### Setup Swagger
175
196
 
176
- interface ICompanyOwned {
177
- companyId?: string | null;
197
+ ```typescript
198
+ import { NestFactory } from '@nestjs/core';
199
+ import { setupSwaggerDocs } from '@flusys/nestjs-core/docs';
200
+
201
+ async function bootstrap() {
202
+ const app = await NestFactory.create(AppModule);
203
+ setupSwaggerDocs(app, { title: 'My API', version: '1.0' });
204
+ await app.listen(3000);
178
205
  }
179
206
  ```
180
207
 
181
208
  ---
182
209
 
183
- ## Migration System
210
+ ## EnvConfigService
184
211
 
185
- ### CLI Commands
212
+ A singleton pre-instantiated as `envConfig`. Loads `.env` on import via `dotenv`.
186
213
 
187
- ```bash
188
- npm run migration:generate -- -n CreateUsers # Generate migration
189
- npm run migration:run # Run pending migrations
190
- npm run migration:revert # Revert last migration
191
- npm run migration:status # Show migration status
192
- TENANT_ID=tenant1 npm run migration:run # Specific tenant
193
- npm run migration:run:all # All tenants
194
- npm run migration:revert:all # Revert all tenants
195
- npm run migration:status:all # Status all tenants
196
- ```
214
+ ### Restricted Keys
215
+
216
+ The following keys cannot be accessed via `tryGetValue()` — use their dedicated typed methods instead:
217
+
218
+ `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASSWORD`, `DB_NAME`, `JWT_SECRET`, `JWT_EXPIRATION`, `REFRESH_TOKEN_SECRET`, `REFRESH_TOKEN_EXPIRATION`, `MAIL_FROM`, `MAIL_APP_PASSWORD`, `REDIS_URL`
219
+
220
+ ### Method Reference
221
+
222
+ | Method | Returns | Description |
223
+ |--------|---------|-------------|
224
+ | `tryGetValue(key, throwOnMissing?)` | `string` | Get any non-restricted env var |
225
+ | `getNumber(key, throwOnMissing?)` | `number` | Get env var as number |
226
+ | `getBoolean(key, throwOnMissing?)` | `boolean` | Get env var as boolean |
227
+ | `getPort()` | `number` | `PORT` (default: 3000) |
228
+ | `isProduction()` | `boolean` | `MODE !== 'DEV'` (case-insensitive) |
229
+ | `getFrontendUrl()` | `string` | `FRONTEND_URL` |
230
+ | `getOrigins()` | `string[]` | `ALLOW_ORIGINS` split by comma |
231
+ | `getTypeOrmConfig()` | `IDatabaseConfig` | DB connection config |
232
+ | `getJwtConfig()` | `IJwtConfig` | JWT secrets and expirations |
233
+ | `getRedisUrl()` | `string` | `REDIS_URL` (default: `redis://localhost:6379`) |
234
+ | `getMailConfig()` | `IMailConfig` | `MAIL_FROM`, `MAIL_APP_PASSWORD` |
235
+ | `getTenantId()` | `string \| null` | `TENANT_ID` or null |
236
+ | `useTenantMode()` | `boolean` | `USE_TENANT_MODE` |
237
+ | `getLogConfig()` | `ILogConfig` | Logging configuration |
238
+ | `getEnv()` | `Record<string, string>` | Full `process.env` snapshot |
239
+
240
+ ---
197
241
 
198
- ### Migration Configuration
242
+ ## Migration CLI
243
+
244
+ ### Migration Config File
245
+
246
+ Create `migration.config.ts` in your project root:
199
247
 
200
248
  ```typescript
201
249
  import { IMigrationConfig } from '@flusys/nestjs-core';
250
+ import { AuthModule } from '@flusys/nestjs-auth';
251
+ import { IAMModule } from '@flusys/nestjs-iam';
202
252
 
203
- const migrationConfig: IMigrationConfig = {
253
+ const config: IMigrationConfig = {
204
254
  defaultDatabaseConfig: {
205
255
  type: 'postgres',
206
- host: 'localhost',
207
- port: 5432,
208
- username: 'user',
209
- password: 'password',
210
- database: 'app_db',
211
- },
212
- bootstrapAppConfig: {
213
- databaseMode: 'multi-tenant',
214
- enableCompanyFeature: true,
256
+ host: process.env.DB_HOST ?? 'localhost',
257
+ port: Number(process.env.DB_PORT ?? 5432),
258
+ username: process.env.DB_USER ?? 'postgres',
259
+ password: process.env.DB_PASSWORD ?? '',
260
+ database: process.env.DB_NAME ?? 'myapp',
215
261
  },
216
- tenants: [
217
- { id: 'tenant1', database: 'tenant1_db' },
218
- { id: 'tenant2', database: 'tenant2_db', host: 'different-server.com' },
262
+ entities: [
263
+ ...AuthModule.getEntities({ enableCompanyFeature: true, enableEmailVerification: true }),
264
+ ...IAMModule.getEntities({ enableCompanyFeature: true, permissionMode: 'FULL' }),
265
+ // ... other module entities
219
266
  ],
220
- migrationsPath: './src/persistence/migrations',
221
- entities: (tenantConfig) => {
222
- // Dynamic entity resolution per tenant
223
- return tenantConfig?.enableCompanyFeature
224
- ? [UserWithCompany, RoleWithCompany]
225
- : [User, Role];
226
- },
227
- migrationsTableName: 'typeorm_migrations',
267
+ migrationsPath: 'src/migrations',
268
+ migrationsTableName: 'migrations',
228
269
  };
270
+
271
+ export default config;
229
272
  ```
230
273
 
231
- ### Core Functions
274
+ ### CLI Commands
275
+
276
+ ```bash
277
+ # Generate a new migration (compares entities to current DB schema)
278
+ npm run migration:generate -- -n CreateUsersTable
279
+
280
+ # Run all pending migrations
281
+ npm run migration:run
282
+
283
+ # Revert the last applied migration
284
+ npm run migration:revert
285
+
286
+ # Show migration status (which are applied, which are pending)
287
+ npm run migration:status
288
+
289
+ # Multi-tenant: run migrations for all tenants
290
+ npm run migration:run:all
291
+ ```
292
+
293
+ ### Programmatic API
232
294
 
233
295
  ```typescript
234
296
  import {
235
- generateMigration,
297
+ createMigrationDataSource,
236
298
  runMigrations,
237
299
  revertMigration,
238
300
  migrationStatus,
301
+ generateMigration,
239
302
  runForAllTenants,
240
- createMigrationDataSource,
241
- } from '@flusys/nestjs-core/migration';
303
+ } from '@flusys/nestjs-core';
242
304
 
243
- // Generate new migration
244
- await generateMigration(config, 'CreateUsersTable', tenantId?);
305
+ // Create a DataSource for migration operations
306
+ const dataSource = await createMigrationDataSource(config, tenantId);
245
307
 
246
308
  // Run pending migrations
247
- const result: IMigrationResult = await runMigrations(config, tenantId?);
309
+ await runMigrations(dataSource);
248
310
 
249
311
  // Revert last migration
250
- const result: IMigrationResult = await revertMigration(config, tenantId?);
312
+ await revertMigration(dataSource);
251
313
 
252
314
  // Check status
253
- await migrationStatus(config, tenantId?);
315
+ const status = await migrationStatus(dataSource);
316
+
317
+ // Generate a new migration file
318
+ await generateMigration(config, 'MigrationName');
254
319
 
255
- // Multi-tenant operations
256
- const results: IMigrationResult[] = await runForAllTenants(config, 'run');
320
+ // Multi-tenant: run for all configured tenants
321
+ await runForAllTenants(config, runMigrations);
257
322
  ```
258
323
 
259
324
  ---
260
325
 
261
326
  ## Seed System
262
327
 
263
- ### CLI Commands
264
-
265
- ```bash
266
- npm run seed:run # Seed all entities
267
- npm run seed:run -- --entity=User --count=100 # Specific entity
268
- npm run seed:run -- --count=50 --clear # Clear before seeding
269
- npm run seed:clear # Clear all data
270
- npm run seed:clear -- --hard # Hard delete
271
- npm run seed:status # Show status
272
- npm run seed:run:all # Multi-tenant
273
- ```
274
-
275
- ### Seed Configuration
276
-
277
- ```typescript
278
- import { configureSeedConfig, seedConfig, ISeedConfig } from '@flusys/nestjs-core/seeders';
279
-
280
- interface ISeedConfig {
281
- counts: Record<string, number>; // Per-entity counts
282
- order: string[]; // Preferred seeding order
283
- skipEntities: string[]; // Entities to skip
284
- locale: string; // Faker locale
285
- respectSoftDelete: boolean; // Default clear behavior
286
- }
287
-
288
- // Configure before running seeders
289
- configureSeedConfig({
290
- counts: { User: 50, Product: 100, Order: 200 },
291
- order: ['User', 'Company', 'Product', 'Order'],
292
- skipEntities: ['migrations', 'typeorm_metadata', 'Migration'],
293
- locale: 'en',
294
- respectSoftDelete: true,
295
- });
296
- ```
297
-
298
- ### SeedRunner
299
-
300
- The main orchestrator for seed operations:
301
-
302
- ```typescript
303
- import { SeedRunner, ISeedOptions, ISeedResult } from '@flusys/nestjs-core/seeders';
304
-
305
- const runner = new SeedRunner(dataSource, logger?);
306
-
307
- // Custom seeder management
308
- runner.registerCustomSeeder('User', new UserSeeder(dataSource)); // Register
309
- runner.unregisterCustomSeeder('User'); // Unregister
310
- runner.hasCustomSeeder('User'); // Check: boolean
311
-
312
- // Run all entities in dependency order
313
- const results: ISeedResult[] = await runner.runAll({
314
- count: 50, // Records per entity
315
- clear: true, // Clear before seeding
316
- entity: 'User', // Seed specific entity only
317
- respectSoftDelete: true, // Use soft delete when clearing
318
- skipIfExists: false, // Skip if data exists
319
- dryRun: false, // Preview without executing
320
- continueOnError: true, // Continue on failures
321
- batchSize: 1000, // Batch size for bulk inserts
322
- onProgress: (current, total, entity) => { },
323
- });
324
-
325
- // Run single entity
326
- const result: ISeedResult = await runner.runSingle('User', options);
327
-
328
- // Clear all data (reverse dependency order)
329
- const results = await runner.clearAll(hard?, continueOnError?);
328
+ ### BaseSeeder
330
329
 
331
- // Get status
332
- const status = await runner.getStatus();
333
- // Returns: [{ entity, tableName, count, isEmpty, hasSoftDelete }]
334
- ```
335
-
336
- ### Custom Seeders
337
-
338
- Extend `BaseSeeder<T>` for entity-specific seeding logic:
330
+ Extend `BaseSeeder` to create custom seeders:
339
331
 
340
332
  ```typescript
341
- import { BaseSeeder, DataGenerator } from '@flusys/nestjs-core/seeders';
342
-
343
- // BaseSeeder provides:
344
- // - repository: Repository<T> - TypeORM repository
345
- // - metadata: EntityMetadata - Entity metadata
346
- // - generate(count): Promise<T[]> - Abstract (must implement)
347
- // - clear(hard?): Promise<void> - Clear entity data
348
- // - count(includeDeleted?): Promise<number>
349
- // - isEmpty(): Promise<boolean>
350
- // - getEntityName(): string
351
- // - withTransaction(fn): Promise<R>
352
-
353
- class UserSeeder extends BaseSeeder<User> {
354
- private generator: DataGenerator;
355
-
356
- constructor(ds: DataSource) {
357
- super(ds, User);
358
- this.generator = new DataGenerator('en');
333
+ import { BaseSeeder, SeedRunner } from '@flusys/nestjs-core';
334
+ import { DataSource } from 'typeorm';
335
+
336
+ export class UserSeeder extends BaseSeeder {
337
+ name = 'UserSeeder';
338
+ order = 1; // Lower runs first (topological sort by dependencies)
339
+ dependencies = []; // Seeder names this depends on
340
+
341
+ async run(dataSource: DataSource): Promise<void> {
342
+ const repo = dataSource.getRepository(User);
343
+ await repo.save([
344
+ { email: 'admin@example.com', name: 'Admin User' },
345
+ ]);
359
346
  }
360
347
 
361
- async generate(count: number): Promise<User[]> {
362
- const users: User[] = [];
363
- for (let i = 0; i < count; i++) {
364
- users.push(this.repository.create({
365
- email: faker.internet.email(),
366
- name: faker.person.fullName(),
367
- password: await bcrypt.hash('password123', 12),
368
- }));
369
- }
370
- return this.repository.save(users);
348
+ async clear(dataSource: DataSource): Promise<void> {
349
+ await dataSource.getRepository(User).delete({});
371
350
  }
372
351
  }
373
-
374
- // Register before running
375
- const runner = new SeedRunner(dataSource);
376
- runner.registerCustomSeeder('User', new UserSeeder(dataSource));
377
- await runner.runAll({ count: 50, clear: true });
378
352
  ```
379
353
 
380
- ### Seeder Interfaces
354
+ ### SeedRunner
381
355
 
382
356
  ```typescript
383
- interface ISeedResult {
384
- entity: string;
385
- success: boolean;
386
- count: number;
387
- error?: string;
388
- dryRun?: boolean;
389
- skipped?: boolean;
390
- }
357
+ import { SeedRunner, seedConfig } from '@flusys/nestjs-core';
391
358
 
392
- interface IEntityInfo {
393
- name: string;
394
- tableName: string;
395
- columns: IColumnInfo[];
396
- relations: IRelationInfo[];
397
- hasSoftDelete: boolean;
398
- hasCompany: boolean;
399
- }
359
+ // Register seeders
360
+ seedConfig.register([UserSeeder, RoleSeeder, PermissionSeeder]);
400
361
 
401
- interface IColumnInfo {
402
- name: string;
403
- propertyName: string;
404
- type: string;
405
- length?: number | string;
406
- isNullable: boolean;
407
- isUnique: boolean;
408
- isPrimary: boolean;
409
- isGenerated: boolean;
410
- default?: any;
411
- enum?: any[];
412
- precision?: number;
413
- scale?: number;
414
- }
362
+ // Run all seeders (respects order and dependencies)
363
+ const runner = new SeedRunner(dataSource);
364
+ const result = await runner.run();
365
+ console.log(`Seeded ${result.count} records`);
415
366
 
416
- interface IRelationInfo {
417
- propertyName: string;
418
- type: 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many';
419
- targetEntity: string;
420
- isNullable: boolean;
421
- joinColumnName?: string;
422
- }
367
+ // Clear all seeded data (in reverse order)
368
+ await runner.clear();
369
+
370
+ // Check seeder status
371
+ const status = await runner.status();
423
372
  ```
424
373
 
425
- ### EntityReader
374
+ ### DataGenerator
426
375
 
427
- Extracts TypeORM metadata for intelligent seeding:
376
+ Generates realistic test data from TypeORM entity metadata using Faker.js:
428
377
 
429
378
  ```typescript
430
- import { EntityReader, IEntityInfo, IColumnInfo } from '@flusys/nestjs-core/seeders';
431
-
432
- const reader = new EntityReader(dataSource);
433
-
434
- // Get all entities
435
- const entities = reader.getAllEntities();
379
+ import { DataGenerator } from '@flusys/nestjs-core';
436
380
 
437
- // Get detailed entity info
438
- const info: IEntityInfo = reader.getEntityInfo('User');
381
+ const generator = new DataGenerator(dataSource);
439
382
 
440
- // Get seeding order (topological sort by FK dependencies)
441
- const order: string[] = reader.getSeedingOrder(skipEntities?);
442
- // Independent entities first, then dependents
383
+ // Auto-detect field types and generate appropriate data
384
+ const fakeUser = generator.generate(User, {
385
+ overrides: { email: 'specific@email.com' },
386
+ count: 10, // generate 10 records
387
+ });
443
388
  ```
444
389
 
445
- ### DataGenerator
390
+ **Automatic field pattern detection:**
446
391
 
447
- Generates realistic sample data using Faker.js:
392
+ | Pattern | Generated value |
393
+ |---------|----------------|
394
+ | `email` | `faker.internet.email()` |
395
+ | `name`, `title` | `faker.person.fullName()` |
396
+ | `phone` | `faker.phone.number()` |
397
+ | `address` | `faker.location.streetAddress()` |
398
+ | `url`, `website` | `faker.internet.url()` |
399
+ | `description`, `text` | `faker.lorem.paragraph()` |
400
+ | `slug` | `faker.helpers.slugify()` |
401
+ | `uuid`, `id` | `faker.string.uuid()` |
402
+ | `boolean`, `isActive` | `faker.datatype.boolean()` |
403
+ | `date`, `createdAt` | `faker.date.recent()` |
404
+ | `number`, `price` | `faker.number.int()` |
448
405
 
449
- ```typescript
450
- import { DataGenerator, IColumnInfo } from '@flusys/nestjs-core/seeders';
406
+ ### Seed CLI
451
407
 
452
- const generator = new DataGenerator('en');
453
-
454
- // Generate value for a column
455
- const value = generator.generateValue(columnInfo);
408
+ ```bash
409
+ # Run all seeders
410
+ npm run seed:run
456
411
 
457
- // Generate complete entity
458
- const entity = generator.generateEntity(columns);
412
+ # Clear all seeded data
413
+ npm run seed:clear
459
414
 
460
- // Relation helpers
461
- const relatedId = generator.generateRelationId(relatedEntities);
462
- const relatedIds = generator.generateRelationIds(relatedEntities, min?, max?);
415
+ # Show seeder status
416
+ npm run seed:status
463
417
  ```
464
418
 
465
419
  ---
466
420
 
467
- ## Field Pattern Detection
421
+ ## Swagger Documentation
468
422
 
469
- Intelligent field pattern detection for realistic data generation.
423
+ ### setupSwaggerDocs
470
424
 
471
- ### Supported Patterns
425
+ Sets up a single global Swagger UI for the whole application:
472
426
 
473
427
  ```typescript
474
- import { detectFieldPattern } from '@flusys/nestjs-core/seeders';
475
-
476
- // Pattern detection returns one of 30 patterns:
477
- type FieldPatternType =
478
- | 'skip' // System fields (id, createdAt, etc.)
479
- | 'null' // Audit fields (createdById, etc.)
480
- | 'boolean' // Boolean fields with keywords
481
- | 'token' // Token fields
482
- | 'firstName' | 'lastName' | 'fullName'
483
- | 'email' | 'phone'
484
- | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode'
485
- | 'url' | 'domain' | 'slug'
486
- | 'description' | 'summary' | 'content' | 'title'
487
- | 'username' | 'password'
488
- | 'birthdate' | 'futureDate' | 'recentDateOrNull'
489
- | 'serial' | 'company'
490
- | 'emailProvider' // smtp, sendgrid, mailgun, ses, postmark
491
- | 'formAccessType'; // public, authenticated, permission
492
-
493
- // Detect pattern for a column
494
- const pattern = detectFieldPattern(column);
428
+ import { setupSwaggerDocs } from '@flusys/nestjs-core/docs';
429
+
430
+ setupSwaggerDocs(app, {
431
+ title: 'My API',
432
+ description: 'API documentation',
433
+ version: '1.0.0',
434
+ path: 'api/docs', // default: 'api/docs'
435
+ bearerAuthEnabled: true, // default: true
436
+ persistAuthorization: true, // default: true
437
+ });
495
438
  ```
496
439
 
497
- ### System Fields
440
+ ### setupModuleSwaggerDocs
498
441
 
499
- Automatically handled fields (public API exports `SYSTEM_FIELDS` only):
442
+ Sets up module-scoped Swagger documentation at separate URLs — one per feature module:
500
443
 
501
444
  ```typescript
502
- import { SYSTEM_FIELDS, isSystemField } from '@flusys/nestjs-core/seeders';
503
-
504
- // Exported constant
505
- SYSTEM_FIELDS = ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdById', 'updatedById', 'deletedById'];
445
+ import { setupModuleSwaggerDocs } from '@flusys/nestjs-core/docs';
506
446
 
507
- // Check if a field is a system field
508
- isSystemField('createdAt'); // true
509
-
510
- // Internal constants (not exported, for reference only):
511
- // AUDIT_FIELDS = ['createdbyid', 'updatedbyid', 'deletedbyid'];
512
- // IDENTITY_FIELDS = ['id', 'createdat', 'updatedat', 'deletedat'];
513
- // BOOLEAN_KEYWORDS = ['verified', 'active', 'enabled', 'public', 'readonly', 'valid'];
447
+ setupModuleSwaggerDocs(app, [
448
+ {
449
+ title: 'Authentication API',
450
+ description: 'Auth endpoints',
451
+ version: '1.0.0',
452
+ path: 'api/docs/auth',
453
+ includeTags: ['Authentication', 'Users', 'Companies'],
454
+ },
455
+ {
456
+ title: 'IAM API',
457
+ description: 'Permissions and roles',
458
+ version: '1.0.0',
459
+ path: 'api/docs/iam',
460
+ includeTags: ['Roles', 'Actions', 'Permissions'],
461
+ },
462
+ {
463
+ title: 'Storage API',
464
+ description: 'File management',
465
+ version: '1.0.0',
466
+ path: 'api/docs/storage',
467
+ includeTags: ['Files', 'Folders'],
468
+ },
469
+ ]);
514
470
  ```
515
471
 
516
- ### Type Category Detection
472
+ ### IModuleSwaggerOptions
517
473
 
518
474
  ```typescript
519
- import { detectTypeCategory } from '@flusys/nestjs-core/seeders';
520
-
521
- // Categorize database type
522
- const category = detectTypeCategory('varchar'); // 'string'
523
- // Categories: string | integer | decimal | boolean | date | timestamp | time | uuid | json | array | unknown
524
-
525
- // Internal utility (not exported): getStringLengthCategory()
526
- // String length categorization:
527
- // 50 chars → 'word'
528
- // ≤ 255 chars → 'sentence'
529
- // > 255 chars → 'paragraph'
475
+ interface IModuleSwaggerOptions {
476
+ title: string;
477
+ description?: string;
478
+ version?: string;
479
+ path: string;
480
+ includeTags?: string[]; // Whitelist specific controller tags
481
+ excludeTags?: string[]; // Blacklist specific controller tags
482
+ includeSchemas?: string[]; // Whitelist specific DTO schemas
483
+ excludeSchemas?: string[]; // Blacklist specific DTO schemas
484
+ bearerAuthEnabled?: boolean;
485
+ persistAuthorization?: boolean;
486
+ }
530
487
  ```
531
488
 
532
489
  ---
533
490
 
534
- ## Swagger Documentation
535
-
536
- ### Setup Functions
491
+ ## Database Utilities
537
492
 
538
493
  ```typescript
539
- import { setupSwaggerDocs, setupModuleSwaggerDocs, IModuleSwaggerOptions } from '@flusys/nestjs-core/docs';
494
+ import { buildDataSourceOptions, getMigrationsFolderPath, getActiveTenants } from '@flusys/nestjs-core';
495
+
496
+ // Build a TypeORM DataSourceOptions object
497
+ const options = buildDataSourceOptions({
498
+ config: databaseConfig,
499
+ entities: [...authEntities, ...iamEntities],
500
+ migrationsPath: 'src/migrations',
501
+ migrationsTableName: 'migrations',
502
+ });
540
503
 
541
- // Variadic API for multiple configs
542
- setupSwaggerDocs(app, authConfig, adminConfig, iamConfig);
504
+ // Get migrations folder path (supports tenant-specific subdirectories)
505
+ const migrationsPath = getMigrationsFolderPath('src/migrations', 'tenant-1');
543
506
 
544
- // Array API for module docs
545
- setupModuleSwaggerDocs(app, [
546
- { title: 'Auth API', path: 'auth/docs', bearerAuth: true },
547
- { title: 'Admin API', path: 'admin/docs', excludeTags: ['public'] },
548
- ]);
507
+ // Get all active tenant configs
508
+ const tenants = getActiveTenants(migrationConfig);
549
509
  ```
550
510
 
551
- ### Configuration Options
511
+ ---
512
+
513
+ ## Core Interfaces
514
+
515
+ These interfaces are used as contracts across all FLUSYS feature modules:
552
516
 
553
517
  ```typescript
554
- interface IModuleSwaggerOptions {
555
- modules?: Type<unknown>[]; // Include specific modules
556
- title: string;
557
- description: string;
558
- version?: string; // Default: '1.0'
559
- path: string; // Swagger UI path
560
- bearerAuth?: boolean; // Add JWT auth
561
- globalHeaders?: ISwaggerGlobalHeader[];
562
- excludeTags?: string[]; // Hide endpoints by tag
563
- excludeSchemaProperties?: ISchemaPropertyExclusion[];
564
- excludeQueryParameters?: IQueryParameterExclusion[];
565
- excludeExamples?: IExampleExclusion[];
566
- }
518
+ // Entity contracts
519
+ interface IIdentity { id: string; createdAt: Date; updatedAt: Date; deletedAt?: Date | null; }
567
520
 
568
- interface ISchemaPropertyExclusion {
569
- schemaName: string;
570
- properties: string[];
521
+ // Bootstrap configuration (fixed at startup)
522
+ interface IBootstrapAppConfig {
523
+ databaseMode: 'single' | 'multi-tenant';
524
+ enableCompanyFeature: boolean;
525
+ enableEmailVerification?: boolean;
526
+ permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
571
527
  }
572
528
 
573
- interface IQueryParameterExclusion {
574
- pathPattern: string; // Supports wildcards: /iam/permissions/*
575
- method?: string; // Optional: 'post', 'get', etc.
576
- parameters: string[];
529
+ // DataSource configuration
530
+ interface IDatabaseConfig {
531
+ type: 'postgres' | 'mysql' | 'mariadb' | 'sqlite' | 'mssql';
532
+ host: string;
533
+ port: number;
534
+ username: string;
535
+ password: string;
536
+ database: string;
577
537
  }
578
538
 
579
- interface ISwaggerGlobalHeader {
580
- name: string;
581
- description: string;
582
- required?: boolean;
583
- example?: string;
539
+ // Multi-tenant config
540
+ interface ITenantDatabaseConfig extends IDatabaseConfig { id: string; }
541
+
542
+ // Module options for dynamic modules
543
+ interface IDynamicModuleConfig {
544
+ global?: boolean;
545
+ includeController?: boolean;
584
546
  }
585
547
 
586
- interface IExampleExclusion {
587
- pathPattern: string; // Supports wildcards: /auth/*
588
- method?: string; // Optional: 'post', 'get', etc.
589
- examples: string[]; // Example names to exclude
548
+ // DataSource service options (base for all module configs)
549
+ interface IDataSourceServiceOptions {
550
+ defaultDatabaseConfig?: IDatabaseConfig;
551
+ tenantDefaultDatabaseConfig?: IDatabaseConfig;
552
+ tenants?: ITenantDatabaseConfig[];
590
553
  }
591
554
  ```
592
555
 
593
- ### Conditional Schema Exclusion
556
+ ---
557
+
558
+ ## Injection Tokens & Constants
594
559
 
595
560
  ```typescript
596
- setupModuleSwaggerDocs(app, [{
597
- title: 'Auth API',
598
- path: 'auth/docs',
599
- bearerAuth: true,
600
- excludeSchemaProperties: enableCompanyFeature ? undefined : [
601
- { schemaName: 'LoginResponseDto', properties: ['company', 'branch'] },
602
- { schemaName: 'UserDto', properties: ['companyId'] },
603
- ],
604
- excludeTags: enableCompanyFeature ? undefined : ['Companies', 'Branches'],
605
- }]);
561
+ import {
562
+ MIGRATION_CONFIG_TOKEN,
563
+ SEED_CONFIG_TOKEN,
564
+ DATASOURCE_TOKEN,
565
+ } from '@flusys/nestjs-core';
606
566
  ```
607
567
 
608
568
  ---
609
569
 
610
- ## API Reference
570
+ ## Multi-Tenant Support
611
571
 
612
- ### Interfaces
572
+ `nestjs-core` provides the foundation for multi-tenant architectures:
613
573
 
614
574
  ```typescript
615
- import {
616
- // Database
617
- IDatabaseConfig,
618
- ITenantDatabaseConfig,
619
- IDataSourceBuildOptions,
620
- // App Config
621
- IBootstrapAppConfig,
622
- IDynamicModuleConfig,
623
- IDataSourceServiceOptions,
624
- IModuleOptionsFactory,
625
- IAsyncModuleOptions,
626
- // Migration
627
- IMigrationConfig,
628
- IMigrationResult,
629
- EntityResolver,
630
- // Entity Contracts
631
- IBaseEntity,
632
- ISoftDeletable,
633
- ITimestampable,
634
- IOrderable,
635
- ICompanyOwned,
636
- IMetadata,
637
- } from '@flusys/nestjs-core';
638
- ```
575
+ import { buildDataSourceOptions, getDatabaseForTenant, getActiveTenants } from '@flusys/nestjs-core';
639
576
 
640
- ### Constants
577
+ // Get database config for a specific tenant
578
+ const tenantDb = getDatabaseForTenant(migrationConfig, 'tenant-id');
641
579
 
642
- ```typescript
643
- import { MODULE_OPTIONS, DEFAULT_TENANT_HEADER } from '@flusys/nestjs-core';
580
+ // Build a DataSource for that tenant
581
+ const dsOptions = buildDataSourceOptions({
582
+ config: tenantDb,
583
+ entities: [...allEntities],
584
+ migrationsPath: getMigrationsFolderPath('src/migrations', 'tenant-id'),
585
+ });
586
+
587
+ // Run migrations for all configured tenants
588
+ await runForAllTenants(migrationConfig, async (dataSource) => {
589
+ await runMigrations(dataSource);
590
+ });
644
591
  ```
645
592
 
646
- ### Config
593
+ ---
647
594
 
648
- ```typescript
649
- import { envConfig } from '@flusys/nestjs-core/config';
650
- ```
595
+ ## Troubleshooting
651
596
 
652
- ### Utils
597
+ **`Cannot find migration config file`**
653
598
 
654
- ```typescript
655
- import {
656
- buildDataSourceOptions,
657
- getDatabaseForTenant,
658
- resolveEntities,
659
- getActiveTenants,
660
- getMigrationsFolderPath,
661
- getMigrationsGlobPattern,
662
- } from '@flusys/nestjs-core/utils';
663
- ```
599
+ Ensure `migration.config.ts` exists at the project root and exports a default `IMigrationConfig` object. The CLI looks for it relative to the current working directory.
664
600
 
665
- ### Migration
601
+ ---
666
602
 
667
- ```typescript
668
- import {
669
- createMigrationDataSource,
670
- initializeDataSource,
671
- runMigrationCli,
672
- generateMigration,
673
- runMigrations,
674
- revertMigration,
675
- migrationStatus,
676
- runForAllTenants,
677
- ensureMigrationsFolder,
678
- } from '@flusys/nestjs-core/migration';
679
- ```
603
+ **`RESTRICTED_KEY` error from `tryGetValue`**
680
604
 
681
- ### Seeders
605
+ You are trying to access a sensitive key (DB credentials, JWT secrets) via the generic accessor. Use the typed method instead:
682
606
 
683
607
  ```typescript
684
- import {
685
- // Classes
686
- BaseSeeder,
687
- SeedRunner,
688
- EntityReader,
689
- DataGenerator,
690
- // Interfaces
691
- ISeedResult,
692
- ISeedOptions,
693
- ISeederLogger,
694
- IEntityInfo,
695
- IColumnInfo,
696
- IRelationInfo,
697
- ISeedConfig,
698
- // Functions
699
- defaultLogger,
700
- seedConfig,
701
- configureSeedConfig,
702
- runSeedCli,
703
- getEntityCount,
704
- shouldSkipEntity,
705
- getSeedingOrder,
706
- // Field pattern functions
707
- detectFieldPattern,
708
- detectTypeCategory,
709
- isSystemField,
710
- // Constants
711
- SYSTEM_FIELDS,
712
- } from '@flusys/nestjs-core/seeders';
608
+ // Wrong
609
+ envConfig.tryGetValue('JWT_SECRET') // throws RestrictedKeyError
610
+
611
+ // Correct
612
+ envConfig.getJwtConfig().secret
713
613
  ```
714
614
 
715
- > **Note:** The following are internal utilities in `field-patterns.ts` not exported from the public API: `FieldPatternType` (type), `ColumnTypeCategory` (type), `AUDIT_FIELDS`, `IDENTITY_FIELDS`, `BOOLEAN_KEYWORDS`, `getStringLengthCategory`, `getTokenLength`.
615
+ ---
616
+
617
+ **`SnakeNamingStrategy` column name mismatch**
716
618
 
717
- ### Swagger
619
+ All columns use `snake_case` by default. A TypeScript property `createdAt` maps to column `created_at`. If your existing schema uses camelCase, override the naming strategy in `buildDataSourceOptions`.
620
+
621
+ ---
622
+
623
+ **Seeder runs out of order**
624
+
625
+ Set explicit `order` numbers or use `dependencies` to declare which seeders must run before yours:
718
626
 
719
627
  ```typescript
720
- import {
721
- setupSwaggerDocs,
722
- setupModuleSwaggerDocs,
723
- IModuleSwaggerOptions,
724
- ISchemaPropertyExclusion,
725
- IQueryParameterExclusion,
726
- ISwaggerGlobalHeader,
727
- IExampleExclusion,
728
- } from '@flusys/nestjs-core/docs';
628
+ export class ProductSeeder extends BaseSeeder {
629
+ name = 'ProductSeeder';
630
+ dependencies = ['CategorySeeder']; // CategorySeeder must run first
631
+ }
729
632
  ```
730
633
 
731
634
  ---
732
635
 
733
- ## Dependencies
636
+ ## License
734
637
 
735
- - `dotenv` - Environment variable loading
736
- - `typeorm` - Migration/seeder utilities (DataSource, EntityMetadata)
737
- - `@faker-js/faker` - Seed data generation
738
- - `@nestjs/common`, `@nestjs/swagger` - Swagger documentation setup only
638
+ MIT © FLUSYS
739
639
 
740
640
  ---
741
641
 
742
- **Last Updated:** 2026-02-25
642
+ > Part of the **FLUSYS** framework — a full-stack monorepo powering Angular 21 + NestJS 11 applications.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-core",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "description": "Core types, interfaces, and constants for Flusys NestJS packages",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",