create-lumina-project 1.0.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 (51) hide show
  1. package/bin/cli.js +73 -0
  2. package/package.json +28 -0
  3. package/template/.env.example +15 -0
  4. package/template/.sequelizerc +11 -0
  5. package/template/_gitignore +3 -0
  6. package/template/nodemon.json +5 -0
  7. package/template/package.json +53 -0
  8. package/template/public/img/logo1.png +0 -0
  9. package/template/public/img/logo2.png +0 -0
  10. package/template/scripts/create-controller.ts +89 -0
  11. package/template/scripts/create-factory.ts +98 -0
  12. package/template/scripts/create-migration.ts +98 -0
  13. package/template/scripts/create-model.ts +105 -0
  14. package/template/scripts/maintenance.ts +73 -0
  15. package/template/scripts/migrate.ts +146 -0
  16. package/template/scripts/seed.ts +42 -0
  17. package/template/scripts/stubs/controller.stub +50 -0
  18. package/template/scripts/stubs/factory.stub +19 -0
  19. package/template/scripts/stubs/migration.stub +44 -0
  20. package/template/scripts/stubs/model.stub +39 -0
  21. package/template/server.ts +63 -0
  22. package/template/src/config/database.ts +39 -0
  23. package/template/src/controllers/AuthController.ts +21 -0
  24. package/template/src/controllers/UserController.ts +52 -0
  25. package/template/src/database/factories/Factory.ts +33 -0
  26. package/template/src/database/factories/UserFactory.ts +26 -0
  27. package/template/src/database/migrations/20260205084944-create_user.js +68 -0
  28. package/template/src/database/seeders/DatabaseSeeder.js +32 -0
  29. package/template/src/exceptions/Handler.ts +32 -0
  30. package/template/src/middlewares/Authentication.ts +34 -0
  31. package/template/src/middlewares/Limiter.ts +34 -0
  32. package/template/src/middlewares/Maintenance.ts +37 -0
  33. package/template/src/middlewares/Validator.ts +29 -0
  34. package/template/src/models/User.ts +91 -0
  35. package/template/src/models/index.ts +92 -0
  36. package/template/src/requests/UserRequest.ts +26 -0
  37. package/template/src/routes/api.ts +30 -0
  38. package/template/src/routes/web.ts +29 -0
  39. package/template/src/services/AuthService.ts +29 -0
  40. package/template/src/services/RouteService.ts +15 -0
  41. package/template/src/services/StorageService.ts +59 -0
  42. package/template/src/services/UserService.ts +31 -0
  43. package/template/src/types/Pagination.d.ts +13 -0
  44. package/template/src/types/express/index.d.ts +9 -0
  45. package/template/src/utils/ApiResponse.ts +27 -0
  46. package/template/src/utils/Hash.ts +21 -0
  47. package/template/src/utils/Logger.ts +79 -0
  48. package/template/src/utils/Paginator.ts +41 -0
  49. package/template/tsconfig.json +24 -0
  50. package/template/views/maintenance.html +42 -0
  51. package/template/views/welcome.html +62 -0
@@ -0,0 +1,146 @@
1
+ import { Umzug, SequelizeStorage } from 'umzug';
2
+ import { Sequelize, QueryInterface } from 'sequelize';
3
+ import { pathToFileURL } from 'url';
4
+ import db from '../src/models/index.js';
5
+ import configList from '../src/config/database.js';
6
+ import Logger from '../src/utils/Logger.js';
7
+ import dotenv from 'dotenv';
8
+
9
+ dotenv.config();
10
+
11
+ class MigrationRunner {
12
+ /**
13
+ * The command line argument (e.g., 'up', 'down', 'reset')
14
+ */
15
+ private command: string;
16
+
17
+ constructor() {
18
+ // Get the command from process arguments
19
+ this.command = process.argv[2] || '';
20
+ }
21
+
22
+ /**
23
+ * Main entry point to execute the migration logic.
24
+ */
25
+ public async run(): Promise<void> {
26
+ try {
27
+ // 1. Ensure Database Exists
28
+ await this.ensureDatabaseExists();
29
+
30
+ // 2. Connect to the App Database
31
+ await this.connectDatabase();
32
+
33
+ // 3. Configure Umzug (The Migration Engine)
34
+ const umzug = this.getUmzugInstance();
35
+
36
+ // 4. Execute the requested command
37
+ await this.executeCommand(umzug);
38
+
39
+ process.exit(0);
40
+ } catch (error) {
41
+ Logger.error('Migration failed:', error);
42
+ process.exit(1);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Check if the database exists and create it if not.
48
+ */
49
+ private async ensureDatabaseExists(): Promise<void> {
50
+ const env = process.env.NODE_ENV || 'development';
51
+ const config = (configList as any)[env];
52
+ const dbName = config.database;
53
+
54
+ // Connect to the server, not the specific DB
55
+ const tempSequelize = new Sequelize('', config.username, config.password, {
56
+ host: config.host,
57
+ dialect: config.dialect,
58
+ logging: false,
59
+ });
60
+
61
+ try {
62
+ await tempSequelize.query(`CREATE DATABASE IF NOT EXISTS \`${dbName}\`;`);
63
+ } catch (error) {
64
+ Logger.error('Failed to create database:', error);
65
+ throw error;
66
+ } finally {
67
+ await tempSequelize.close();
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Verify the database connection.
73
+ */
74
+ private async connectDatabase(): Promise<void> {
75
+ await db.connect();
76
+ }
77
+
78
+ /**
79
+ * Initialize and configure Umzug.
80
+ */
81
+ private getUmzugInstance(): Umzug<QueryInterface> {
82
+ const sequelize = db.sequelize;
83
+
84
+ return new Umzug<QueryInterface>({
85
+ migrations: {
86
+ glob: 'src/database/migrations/*.js',
87
+ resolve: ({ name, path, context }) => {
88
+ return {
89
+ name,
90
+ up: async () => {
91
+ // Windows Fix: Convert path to URL
92
+ const migration = await import(pathToFileURL(path as string).href);
93
+ return migration.default.up(context, sequelize.Sequelize);
94
+ },
95
+ down: async () => {
96
+ // Windows Fix: Convert path to URL
97
+ const migration = await import(pathToFileURL(path as string).href);
98
+ return migration.default.down(context, sequelize.Sequelize);
99
+ },
100
+ };
101
+ },
102
+ },
103
+ context: sequelize.getQueryInterface(),
104
+ storage: new SequelizeStorage({ sequelize }),
105
+ logger: console,
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Handle the specific CLI command logic.
111
+ */
112
+ private async executeCommand(umzug: Umzug<QueryInterface>): Promise<void> {
113
+ switch (this.command) {
114
+ case 'up':
115
+ Logger.info('Running Migrations...');
116
+ await umzug.up();
117
+ Logger.info('Migrations executed successfully.');
118
+ break;
119
+
120
+ case 'down':
121
+ Logger.info('Rolling back last migration...');
122
+ await umzug.down();
123
+ Logger.info('Rollback complete.');
124
+ break;
125
+
126
+ case 'reset':
127
+ Logger.info('Resetting Database...');
128
+ await umzug.down({ to: 0 });
129
+ Logger.info('Database reset complete.');
130
+ break;
131
+
132
+ default:
133
+ Logger.info(`
134
+ Unknown command: "${this.command}"
135
+
136
+ Usage:
137
+ npm run migrate -> Run pending migrations
138
+ npm run migrate:undo -> Undo last migration
139
+ npm run migrate:reset -> Undo all migrations
140
+ `);
141
+ break;
142
+ }
143
+ }
144
+ }
145
+
146
+ new MigrationRunner().run();
@@ -0,0 +1,42 @@
1
+ import db from '../src/models/index.js';
2
+ import DatabaseSeeder from '../src/database/seeders/DatabaseSeeder.js';
3
+ import Logger from '../src/utils/Logger.js';
4
+
5
+ class SeederRunner {
6
+ /**
7
+ * Main entry point to execute the seeding logic.
8
+ */
9
+ public async run(): Promise<void> {
10
+ try {
11
+ // 1. Connect to the Database
12
+ await this.connectDatabase();
13
+
14
+ // 2. Execute the Main Seeder
15
+ await this.executeSeeding();
16
+
17
+ Logger.info('Database seeding completed successfully.');
18
+ process.exit(0);
19
+ } catch (error) {
20
+ Logger.error('Seeding failed:', error);
21
+ process.exit(1);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Verify the database connection.
27
+ */
28
+ private async connectDatabase(): Promise<void> {
29
+ await db.connect();
30
+ }
31
+
32
+ /**
33
+ * Instantiate and run the main DatabaseSeeder.
34
+ */
35
+ private async executeSeeding(): Promise<void> {
36
+ Logger.info('Starting Database Seeder...');
37
+
38
+ await DatabaseSeeder.run();
39
+ }
40
+ }
41
+
42
+ new SeederRunner().run();
@@ -0,0 +1,50 @@
1
+ import { Request, Response } from 'express';
2
+ import ApiResponse from '../utils/ApiResponse.js';
3
+
4
+ class {{ControllerName}} {
5
+
6
+ /**
7
+ * Display a listing of the resource.
8
+ */
9
+ public async index(req: Request, res: Response) {
10
+ // const items = await Model.findAll();
11
+ return ApiResponse.success(res, []);
12
+ }
13
+
14
+ /**
15
+ * Store a newly created resource in storage.
16
+ */
17
+ public async store(req: Request, res: Response) {
18
+ // const item = await Model.create(req.body);
19
+ return ApiResponse.success(res, {}, 'Resource created successfully');
20
+ }
21
+
22
+ /**
23
+ * Display the specified resource.
24
+ */
25
+ public async show(req: Request, res: Response) {
26
+ const { id } = req.params;
27
+ // const item = await Model.findByPk(id);
28
+ return ApiResponse.success(res, { id });
29
+ }
30
+
31
+ /**
32
+ * Update the specified resource in storage.
33
+ */
34
+ public async update(req: Request, res: Response) {
35
+ const { id } = req.params;
36
+ // await Model.update(req.body, { where: { id } });
37
+ return ApiResponse.success(res, { id }, 'Resource updated successfully');
38
+ }
39
+
40
+ /**
41
+ * Remove the specified resource from storage.
42
+ */
43
+ public async destroy(req: Request, res: Response) {
44
+ const { id } = req.params;
45
+ // await Model.destroy({ where: { id } });
46
+ return ApiResponse.success(res, null, 'Resource deleted successfully');
47
+ }
48
+ }
49
+
50
+ export default new {{ControllerName}}();
@@ -0,0 +1,19 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import {{ModelName}} from '../../models/{{ModelName}}.js';
3
+ import Factory from './Factory.js';
4
+
5
+ class {{FactoryName}} extends Factory<{{ModelName}}> {
6
+ protected model = {{ModelName}};
7
+
8
+ /**
9
+ * Define the model's default state.
10
+ */
11
+ protected definition() {
12
+ return {
13
+ // name: faker.person.fullName(),
14
+ // email: faker.internet.email(),
15
+ };
16
+ }
17
+ }
18
+
19
+ export default new {{FactoryName}}();
@@ -0,0 +1,44 @@
1
+ import { DataTypes } from 'sequelize';
2
+
3
+ class Create{{ClassName}} {
4
+ /**
5
+ * Run the migrations.
6
+ */
7
+ async up(queryInterface, sequelize) {
8
+ await queryInterface.createTable('{{TableName}}', {
9
+ id: {
10
+ allowNull: false,
11
+ autoIncrement: true,
12
+ primaryKey: true,
13
+ type: DataTypes.BIGINT
14
+ },
15
+
16
+ // Add your columns here...
17
+
18
+ created_at: {
19
+ type: DataTypes.DATE,
20
+ allowNull: false,
21
+ defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
22
+ },
23
+ updated_at: {
24
+ type: DataTypes.DATE,
25
+ allowNull: false,
26
+ defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
27
+ },
28
+ // Uncomment for paranoid mode
29
+ // deleted_at: {
30
+ // type: DataTypes.DATE,
31
+ // allowNull: true,
32
+ // }
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Reverse the migrations.
38
+ */
39
+ async down(queryInterface, sequelize) {
40
+ await queryInterface.dropTable('{{TableName}}');
41
+ }
42
+ }
43
+
44
+ export default new Create{{ClassName}}();
@@ -0,0 +1,39 @@
1
+ import { Model, DataTypes, Sequelize, Optional } from 'sequelize';
2
+
3
+ interface {{ModelName}}Attributes {
4
+ id: number;
5
+ created_at?: Date;
6
+ updated_at?: Date;
7
+ deleted_at?: Date | null;
8
+ }
9
+
10
+ export interface {{ModelName}}CreationAttributes extends Optional<{{ModelName}}Attributes, 'id' | 'created_at' | 'updated_at' | 'deleted_at'> {}
11
+
12
+ class {{ModelName}} extends Model<{{ModelName}}Attributes, {{ModelName}}CreationAttributes> implements {{ModelName}}Attributes {
13
+ declare id: number;
14
+ declare created_at: Date;
15
+ declare updated_at: Date;
16
+ declare deleted_at: Date | null;
17
+
18
+ static initModel(sequelize: Sequelize) {
19
+ {{ModelName}}.init(
20
+ {
21
+ id: {
22
+ type: DataTypes.INTEGER,
23
+ autoIncrement: true,
24
+ primaryKey: true,
25
+ },
26
+ },
27
+ {
28
+ sequelize,
29
+ modelName: '{{ModelName}}',
30
+ tableName: '{{TableName}}', // e.g. 'products'
31
+ paranoid: true,
32
+ timestamps: true,
33
+ underscored: true,
34
+ }
35
+ );
36
+ }
37
+ }
38
+
39
+ export default {{ModelName}};
@@ -0,0 +1,63 @@
1
+ import express, { Application } from 'express';
2
+ import cors from 'cors';
3
+ import helmet from 'helmet';
4
+ import path from 'path';
5
+ import db from './src/models/index.js';
6
+ import RouteService from './src/services/RouteService.js';
7
+ import ExceptionHandler from './src/exceptions/Handler.js';
8
+ import Logger from './src/utils/Logger.js';
9
+ import Limiter from './src/middlewares/Limiter.js';
10
+ import Maintenance from './src/middlewares/Maintenance.js';
11
+ import dotenv from 'dotenv';
12
+
13
+ dotenv.config();
14
+
15
+ const app: Application = express();
16
+ const PORT = process.env.APP_PORT || 3000;
17
+
18
+ // ==========================
19
+ // Global Middleware
20
+ // ==========================
21
+ app.use(Maintenance.handle);
22
+ app.use(helmet({ crossOriginResourcePolicy: false }));
23
+ app.use(cors());
24
+ app.use(express.json());
25
+ app.use(express.urlencoded({ extended: true }));
26
+ app.use(express.static(path.join(process.cwd(), 'public')));
27
+ app.use(Limiter.global);
28
+
29
+ // ==========================
30
+ // Register Routes
31
+ // ==========================
32
+ // This loads both your API and Web routes
33
+ RouteService.boot(app);
34
+
35
+ // ==========================
36
+ // Error Handling
37
+ // ==========================
38
+
39
+ // 404 Not Found Handler
40
+ app.use(ExceptionHandler.notFound);
41
+
42
+ // Global Error Handler
43
+ app.use(ExceptionHandler.handle);
44
+
45
+ // ==========================
46
+ // Start Server
47
+ // ==========================
48
+ const start = async () => {
49
+ try {
50
+ // Test Database Connection
51
+ await db.connect();
52
+
53
+ // Start Listening
54
+ app.listen(PORT, () => {
55
+ Logger.info(`Server running on http://localhost:${PORT}`);
56
+ });
57
+ } catch (error) {
58
+ Logger.error('Unable to connect to the database:', error);
59
+ process.exit(1);
60
+ }
61
+ };
62
+
63
+ start();
@@ -0,0 +1,39 @@
1
+ import { Options } from 'sequelize';
2
+ import Logger from '../utils/Logger.js';
3
+ import dotenv from 'dotenv';
4
+
5
+ dotenv.config();
6
+
7
+ class DatabaseConfig {
8
+ public development: Options;
9
+ public test: Options;
10
+ public production: Options;
11
+
12
+ constructor() {
13
+ this.development = this.getEnvironmentConfig();
14
+ this.test = this.getEnvironmentConfig('test');
15
+ this.production = this.getEnvironmentConfig('production');
16
+ }
17
+
18
+ /**
19
+ * Helper to generate config based on the environment.
20
+ * This reduces repetition.
21
+ */
22
+ private getEnvironmentConfig(env: 'development' | 'test' | 'production' = 'development'): Options {
23
+ const isTest = env === 'test';
24
+ const isProd = env === 'production';
25
+
26
+ return {
27
+ username: process.env.DB_USERNAME,
28
+ password: process.env.DB_PASSWORD,
29
+ database: isTest ? process.env.DB_DATABASE_TEST : process.env.DB_DATABASE,
30
+ host: process.env.DB_HOST,
31
+ port: Number(process.env.DB_PORT) || 3306,
32
+ dialect: (process.env.DB_DIALECT as any) || 'mysql',
33
+ // Disable logging in test/production to keep logs clean
34
+ logging: isProd || isTest ? false : (msg) => Logger.info(`[SQL] ${msg}`),
35
+ };
36
+ }
37
+ }
38
+
39
+ export default new DatabaseConfig();
@@ -0,0 +1,21 @@
1
+ import { Request, Response } from 'express';
2
+ import AuthService from '../services/AuthService.js';
3
+ import ApiResponse from '../utils/ApiResponse.js';
4
+
5
+ class AuthController {
6
+ public async login(req: Request, res: Response) {
7
+ try {
8
+ const { email, password } = req.body;
9
+ const result = await AuthService.login(email, password);
10
+ return ApiResponse.success(res, result, 'Login successful');
11
+ } catch (error: any) {
12
+ return ApiResponse.error(res, error.message, 401);
13
+ }
14
+ }
15
+
16
+ public async me(req: Request, res: Response) {
17
+ return ApiResponse.success(res, req.user);
18
+ }
19
+ }
20
+
21
+ export default new AuthController();
@@ -0,0 +1,52 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import UserService from '../services/UserService.js';
3
+ import ApiResponse from '../utils/ApiResponse.js';
4
+
5
+ class UserController {
6
+ /**
7
+ * Get paginated list of users.
8
+ */
9
+ public async index(req: Request, res: Response, next: NextFunction) {
10
+ try {
11
+ const page = Number(req.query.page) || 1;
12
+ const limit = Number(req.query.limit) || 15;
13
+ const users = await UserService.getAllUsers(page, limit);
14
+ return ApiResponse.success(res, users, 'Users retrieved successfully');
15
+ } catch (error) {
16
+ next(error);
17
+ }
18
+ }
19
+
20
+ public async store(req: Request, res: Response, next: NextFunction) {
21
+ try {
22
+ const user = await UserService.createUser(req.body);
23
+ return ApiResponse.success(res, user, 'User created successfully', 201);
24
+ } catch (error) {
25
+ next(error);
26
+ }
27
+ }
28
+
29
+ public async uploadAvatar(req: Request, res: Response, next: NextFunction) {
30
+ try {
31
+ if (!req.file) {
32
+ return ApiResponse.error(res, 'No file uploaded', 400);
33
+ }
34
+
35
+ // 1. Get the file path relative to your server
36
+ const filePath = `uploads/${req.file.filename}`;
37
+
38
+ // 2. Update the user in the DB (assuming you have req.user from AuthMiddleware)
39
+ await UserService.updateAvatar(req.user.id, filePath);
40
+
41
+ // 3. Return success
42
+ return ApiResponse.success(res, {
43
+ path: filePath,
44
+ url: `${req.protocol}://${req.get('host')}/${filePath}`
45
+ }, 'Avatar uploaded successfully');
46
+ } catch (error) {
47
+ next(error);
48
+ }
49
+ }
50
+ }
51
+
52
+ export default new UserController();
@@ -0,0 +1,33 @@
1
+ import { Model, ModelStatic } from 'sequelize';
2
+
3
+ export default abstract class Factory<T extends Model> {
4
+ protected abstract model: ModelStatic<T>;
5
+
6
+ // abstract method where you define the default state
7
+ protected abstract definition(): Record<string, any>;
8
+
9
+ // Make a single object (not saved to DB)
10
+ public make(overrides: Record<string, any> = {}): Record<string, any> {
11
+ return {
12
+ ...this.definition(),
13
+ ...overrides,
14
+ };
15
+ }
16
+
17
+ // Make multiple objects (not saved to DB)
18
+ public makeMany(count: number, overrides: Record<string, any> = {}): Record<string, any>[] {
19
+ return Array.from({ length: count }).map(() => this.make(overrides));
20
+ }
21
+
22
+ // Create single record in DB
23
+ public async create(overrides: Record<string, any> = {}): Promise<T> {
24
+ const data = this.make(overrides);
25
+ return await this.model.create(data as any);
26
+ }
27
+
28
+ // Create multiple records in DB
29
+ public async createMany(count: number, overrides: Record<string, any> = {}): Promise<T[]> {
30
+ const data = this.makeMany(count, overrides);
31
+ return await this.model.bulkCreate(data as any);
32
+ }
33
+ }
@@ -0,0 +1,26 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import User from '../../models/User.js'; // Import your Model
3
+ import Factory from './Factory.js';
4
+
5
+ class UserFactory extends Factory<User> {
6
+ protected model = User;
7
+
8
+ protected definition() {
9
+ return {
10
+ firstname: faker.person.firstName(),
11
+ lastname: faker.person.lastName(),
12
+ email: faker.internet.email(),
13
+ password: '$2b$10$YourHashedPasswordHere',
14
+ role: 'user',
15
+ avatar: null,
16
+ };
17
+ }
18
+
19
+ public admin() {
20
+ return {
21
+ role: 'admin',
22
+ };
23
+ }
24
+ }
25
+
26
+ export default new UserFactory();
@@ -0,0 +1,68 @@
1
+ import { DataTypes } from 'sequelize';
2
+
3
+ class CreateUserTable {
4
+ /**
5
+ * Run the migrations.
6
+ */
7
+ async up(queryInterface, Sequelize) {
8
+ await queryInterface.createTable('users', {
9
+ id: {
10
+ allowNull: false,
11
+ autoIncrement: true,
12
+ primaryKey: true,
13
+ type: DataTypes.BIGINT
14
+ },
15
+ firstname: {
16
+ type: DataTypes.STRING(50),
17
+ allowNull: false
18
+ },
19
+ lastname: {
20
+ type: DataTypes.STRING(50),
21
+ allowNull: false
22
+ },
23
+ email: {
24
+ type: DataTypes.STRING(100),
25
+ unique: true,
26
+ allowNull: false
27
+ },
28
+ password: {
29
+ type: DataTypes.STRING(255),
30
+ allowNull: false
31
+ },
32
+ role: {
33
+ type: DataTypes.STRING(20),
34
+ allowNull: false,
35
+ defaultValue: 'user'
36
+ },
37
+ avatar: {
38
+ type: DataTypes.TEXT,
39
+ allowNull: true,
40
+ defaultValue: null,
41
+ },
42
+ created_at: {
43
+ type: DataTypes.DATE,
44
+ allowNull: false,
45
+ defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
46
+ },
47
+ updated_at: {
48
+ type: DataTypes.DATE,
49
+ allowNull: false,
50
+ defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
51
+ },
52
+ deleted_at: {
53
+ type: DataTypes.DATE,
54
+ allowNull: true,
55
+ defaultValue: null,
56
+ },
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Reverse the migrations.
62
+ */
63
+ async down(queryInterface, Sequelize) {
64
+ await queryInterface.dropTable('users');
65
+ }
66
+ }
67
+
68
+ export default new CreateUserTable();
@@ -0,0 +1,32 @@
1
+ import UserFactory from '../factories/UserFactory.js';
2
+ import Logger from '../../utils/Logger.js';
3
+
4
+ class DatabaseSeeder {
5
+ /**
6
+ * Run the database seeds.
7
+ */
8
+ async run() {
9
+ Logger.info('Seeding database...');
10
+
11
+ try {
12
+ // 1. Create a specific Admin User
13
+ await UserFactory.create({
14
+ firstname: 'Admin',
15
+ lastname: 'Lumina',
16
+ email: 'admin@lumina.com',
17
+ password: "lumina123",
18
+ role: 'admin',
19
+ });
20
+
21
+ // 2. Create random users
22
+ await UserFactory.createMany(20);
23
+
24
+ Logger.info('Seeding complete!');
25
+ } catch (error) {
26
+ Logger.error('Seeding failed:', error);
27
+ throw error;
28
+ }
29
+ }
30
+ }
31
+
32
+ export default new DatabaseSeeder();