@ecopex/ecopex-framework 1.0.0 → 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.
- package/index.js +5 -0
- package/libraries/fastify.js +120 -0
- package/libraries/knex.js +1 -1
- package/package.json +6 -2
- package/stores/base.js +1 -1
- package/utils/jsonRouteLoader.js +3 -3
- package/utils/middleware.js +1 -1
- package/utils/routeLoader.js +1 -1
- package/.env +0 -73
- package/database/migrations/20240000135243_timezones.js +0 -22
- package/database/migrations/20240000135244_countries.js +0 -23
- package/database/migrations/20240000135244_create_admins_table.js +0 -66
- package/database/migrations/20240000135244_currencies.js +0 -21
- package/database/migrations/20240000135244_languages.js +0 -21
- package/database/migrations/20240000135244_taxes.js +0 -10
- package/database/migrations/20240000135245_sites.js +0 -37
- package/database/migrations/20240000135246_payment_methods.js +0 -33
- package/database/migrations/20251016113547_devices.js +0 -37
- package/database/migrations/20251019192600_users.js +0 -62
- package/database/migrations/20251019213551_language_lines.js +0 -35
- package/database/migrations/20251222214131_category_groups.js +0 -18
- package/database/migrations/20251222214619_categories.js +0 -27
- package/database/migrations/20251222214848_brands.js +0 -23
- package/database/migrations/20251222214946_products.js +0 -30
- package/database/migrations/20251222215428_product_images.js +0 -18
- package/database/migrations/20251222215553_options.js +0 -30
- package/database/migrations/20251222215806_variants.js +0 -23
- package/database/migrations/20251222215940_attributes.js +0 -25
- package/database/migrations/20251222220135_discounts.js +0 -15
- package/database/migrations/20251222220253_reviews.js +0 -22
- package/database/migrations/20251222220341_favorites.js +0 -10
- package/database/migrations/20251222220422_search_logs.js +0 -17
- package/database/migrations/20251222220636_orders.js +0 -16
- package/database/migrations/20251222220806_order_items.js +0 -19
- package/database/migrations/20251222221317_order_statuses.js +0 -10
- package/database/migrations/20251222221446_order_payments.js +0 -13
- package/database/migrations/20251222221654_order_addresses.js +0 -23
- package/database/migrations/20251222221807_order_status_logs.js +0 -13
- package/database/seeds/admins.js +0 -37
- package/database/seeds/countries.js +0 -203
- package/database/seeds/currencies.js +0 -165
- package/database/seeds/languages.js +0 -113
- package/database/seeds/timezones.js +0 -149
- package/ecosystem.config.js +0 -26
- package/libraries/stores.js +0 -22
- package/routes/admin/auto/admins.json +0 -63
- package/routes/admin/auto/devices.json +0 -37
- package/routes/admin/auto/migrations.json +0 -21
- package/routes/admin/auto/users.json +0 -61
- package/routes/admin/middlewares/index.js +0 -87
- package/routes/admin/spec/auth.js +0 -626
- package/routes/admin/spec/users.js +0 -3
- package/routes/auto/handler.js +0 -635
- package/routes/common/auto/countries.json +0 -28
- package/routes/common/auto/currencies.json +0 -26
- package/routes/common/auto/languages.json +0 -26
- package/routes/common/auto/taxes.json +0 -46
- package/routes/common/auto/timezones.json +0 -29
- package/workers/admin.js +0 -124
- package/workers/api.js +0 -106
package/index.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
|
|
3
|
+
const fastify = require('fastify')({
|
|
4
|
+
logger: {
|
|
5
|
+
level: process.env.LOG_LEVEL || 'info'
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const { loadRoutes } = require('@root/utils/routeLoader');
|
|
10
|
+
const Middleware = require('@root/utils/middleware');
|
|
11
|
+
|
|
12
|
+
// Register plugins
|
|
13
|
+
async function registerPlugins() {
|
|
14
|
+
// Set error handler first, before any plugins
|
|
15
|
+
fastify.setErrorHandler(Middleware.errorHandler);
|
|
16
|
+
fastify.setNotFoundHandler(Middleware.errorNotFoundHandler);
|
|
17
|
+
|
|
18
|
+
// CORS plugin
|
|
19
|
+
await fastify.register(require('@fastify/cors'), {
|
|
20
|
+
origin: process.env.CORS_ORIGIN || '*',
|
|
21
|
+
credentials: true
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Swagger documentation
|
|
25
|
+
const swaggerConfig = require('@root/config/swagger/admin');
|
|
26
|
+
|
|
27
|
+
await fastify.register(require('@fastify/swagger'), swaggerConfig.swagger);
|
|
28
|
+
|
|
29
|
+
// Swagger UI
|
|
30
|
+
await fastify.register(require('@fastify/swagger-ui'), swaggerConfig.swaggerUi);
|
|
31
|
+
|
|
32
|
+
// Fastify Multipart plugin
|
|
33
|
+
fastify.register(require('@fastify/multipart'), {
|
|
34
|
+
attachFieldsToBody: true, // Optional: attaches fields to the body object
|
|
35
|
+
throwFileSizeLimit: true, // Optional: throws an error if the file size limit is exceeded
|
|
36
|
+
limits: {
|
|
37
|
+
fieldNameSize: 100, // Max field name size in bytes
|
|
38
|
+
fieldSize: 100, // Max field value size in bytes
|
|
39
|
+
fields: 10, // Max number of non-file fields
|
|
40
|
+
fileSize: 1000000, // For multipart forms, the max file size in bytes
|
|
41
|
+
files: 1, // Max number of file fields
|
|
42
|
+
headerPairs: 2000, // Max number of header key=>value pairs
|
|
43
|
+
parts: 1000 // For multipart forms, the max number of parts (fields + files)
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Register other middleware
|
|
48
|
+
fastify.addHook('preHandler', Middleware.languageDetection());
|
|
49
|
+
fastify.addHook('preHandler', Middleware.responseFormatter());
|
|
50
|
+
|
|
51
|
+
// Health check endpoint
|
|
52
|
+
fastify.get('/health', async (request, reply) => {
|
|
53
|
+
return {
|
|
54
|
+
status: 'ok',
|
|
55
|
+
service: 'admin',
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
uptime: process.uptime(),
|
|
58
|
+
pid: process.pid
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Load admin routes, common routes, and auto routes
|
|
64
|
+
async function loadAdminRoutes() {
|
|
65
|
+
try {
|
|
66
|
+
// Load admin routes
|
|
67
|
+
await loadRoutes(fastify, __dirname + '/../routes/admin', true, 'admin');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error loading admin routes:', error);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Start admin service
|
|
75
|
+
async function start() {
|
|
76
|
+
try {
|
|
77
|
+
|
|
78
|
+
// Register plugins
|
|
79
|
+
await registerPlugins();
|
|
80
|
+
|
|
81
|
+
// Load admin routes
|
|
82
|
+
await loadAdminRoutes();
|
|
83
|
+
|
|
84
|
+
// Start server
|
|
85
|
+
const port = process.env.PORT || 3001;
|
|
86
|
+
const host = process.env.HOST || '127.0.0.1';
|
|
87
|
+
|
|
88
|
+
fastify.listen({ port, host });
|
|
89
|
+
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error starting admin service:', error);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Graceful shutdown
|
|
97
|
+
process.on('SIGINT', async () => {
|
|
98
|
+
try {
|
|
99
|
+
await fastify.close();
|
|
100
|
+
process.exit(0);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('Error during admin service shutdown:', error);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
process.on('SIGTERM', async () => {
|
|
108
|
+
try {
|
|
109
|
+
await fastify.close();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Error during admin service shutdown:', error);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Start the admin service
|
|
118
|
+
module.exports = {
|
|
119
|
+
start
|
|
120
|
+
}
|
package/libraries/knex.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopex/ecopex-framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Javascript Framework for API and Admin Panel",
|
|
5
5
|
"main": "ecosystem.config.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,11 @@
|
|
|
13
13
|
"prod": "pm2 start ecosystem.config.js --env production",
|
|
14
14
|
"migrate": "knex migrate:latest",
|
|
15
15
|
"migrate:rollback": "knex migrate:rollback",
|
|
16
|
-
"seed": "knex seed:run"
|
|
16
|
+
"seed": "knex seed:run",
|
|
17
|
+
"npm:publish": "npm version patch && npm publish"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
17
21
|
},
|
|
18
22
|
"dependencies": {
|
|
19
23
|
"@aws-sdk/client-s3": "^3.958.0",
|
package/stores/base.js
CHANGED
package/utils/jsonRouteLoader.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const handlers = require('
|
|
4
|
-
const general = require('
|
|
5
|
-
const { add_model } = require('
|
|
3
|
+
const handlers = require('../routes/auto/handler');
|
|
4
|
+
const general = require('../libraries/general');
|
|
5
|
+
const { add_model } = require('../stores');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* JSON Route Loader
|
package/utils/middleware.js
CHANGED
package/utils/routeLoader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const JsonRouteLoader = require('./jsonRouteLoader');
|
|
4
|
-
const general = require('
|
|
4
|
+
const general = require('../libraries/general');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Automatically loads routes from the routes directory
|
package/.env
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# ===========================================
|
|
2
|
-
# SB System Environment Configuration
|
|
3
|
-
# ===========================================
|
|
4
|
-
|
|
5
|
-
# Application Environment
|
|
6
|
-
NODE_ENV=development
|
|
7
|
-
LOG_LEVEL=error
|
|
8
|
-
|
|
9
|
-
# Server Configuration
|
|
10
|
-
HOST=0.0.0.0
|
|
11
|
-
API_PORT=3000
|
|
12
|
-
ADMIN_PORT=3001
|
|
13
|
-
|
|
14
|
-
# Database Configuration
|
|
15
|
-
DB_HOST=127.0.0.1
|
|
16
|
-
DB_PORT=3306
|
|
17
|
-
DB_USER=root
|
|
18
|
-
DB_PASSWORD=Gs1905ua
|
|
19
|
-
DB_NAME=ecommerce
|
|
20
|
-
|
|
21
|
-
# Alternative: Use DATABASE_URL for production
|
|
22
|
-
# DATABASE_URL=mysql://username:password@host:port/database
|
|
23
|
-
|
|
24
|
-
# CORS Configuration
|
|
25
|
-
CORS_ORIGIN=*
|
|
26
|
-
|
|
27
|
-
# PM2 Process Management
|
|
28
|
-
API_INSTANCES=1
|
|
29
|
-
API_EXEC_MODE=fork
|
|
30
|
-
ADMIN_INSTANCES=1
|
|
31
|
-
ADMIN_EXEC_MODE=fork
|
|
32
|
-
|
|
33
|
-
# Internationalization
|
|
34
|
-
DEFAULT_LOCALE=en
|
|
35
|
-
SUPPORTED_LOCALES=en,tr,es
|
|
36
|
-
|
|
37
|
-
# Security (for production)
|
|
38
|
-
# JWT_SECRET=your_jwt_secret_here
|
|
39
|
-
# BCRYPT_ROUNDS=12
|
|
40
|
-
# SESSION_SECRET=your_session_secret_here
|
|
41
|
-
|
|
42
|
-
# Redis (for caching/sessions)
|
|
43
|
-
# REDIS_HOST=localhost
|
|
44
|
-
# REDIS_PORT=6379
|
|
45
|
-
# REDIS_PASSWORD=
|
|
46
|
-
|
|
47
|
-
# Email Configuration (for notifications)
|
|
48
|
-
# SMTP_HOST=smtp.gmail.com
|
|
49
|
-
# SMTP_PORT=587
|
|
50
|
-
# SMTP_USER=your_email@gmail.com
|
|
51
|
-
# SMTP_PASS=your_app_password
|
|
52
|
-
# FROM_EMAIL=noreply@yoursystem.com
|
|
53
|
-
|
|
54
|
-
# File Upload Configuration
|
|
55
|
-
# UPLOAD_MAX_SIZE=10485760
|
|
56
|
-
# UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/gif,application/pdf
|
|
57
|
-
|
|
58
|
-
# Rate Limiting
|
|
59
|
-
# RATE_LIMIT_WINDOW_MS=900000
|
|
60
|
-
# RATE_LIMIT_MAX_REQUESTS=100
|
|
61
|
-
|
|
62
|
-
# Logging
|
|
63
|
-
# LOG_FILE_PATH=./logs/app.log
|
|
64
|
-
# LOG_MAX_SIZE=10m
|
|
65
|
-
# LOG_MAX_FILES=5
|
|
66
|
-
|
|
67
|
-
# Monitoring
|
|
68
|
-
# HEALTH_CHECK_INTERVAL=30000
|
|
69
|
-
# METRICS_ENABLED=true
|
|
70
|
-
|
|
71
|
-
# Development Tools
|
|
72
|
-
# DEBUG=sb_system:*
|
|
73
|
-
# NODE_OPTIONS=--max-old-space-size=4096
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('timezones', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('timezone_id').primary();
|
|
9
|
-
table.string('name', 100).notNullable();
|
|
10
|
-
table.string('code', 100).notNullable();
|
|
11
|
-
table.string('offset', 100).notNullable();
|
|
12
|
-
table.string('gmt', 100).notNullable();
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param { import("knex").Knex } knex
|
|
18
|
-
* @returns { Promise<void> }
|
|
19
|
-
*/
|
|
20
|
-
exports.down = function(knex) {
|
|
21
|
-
return knex.schema.dropTable('timezones');
|
|
22
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('countries', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('country_id').primary();
|
|
9
|
-
table.string('name', 100).notNullable();
|
|
10
|
-
table.string('code', 100).notNullable();
|
|
11
|
-
table.string('iso_code', 100).notNullable();
|
|
12
|
-
table.string('phone_code', 100).notNullable();
|
|
13
|
-
table.string('flag', 100).notNullable();
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param { import("knex").Knex } knex
|
|
19
|
-
* @returns { Promise<void> }
|
|
20
|
-
*/
|
|
21
|
-
exports.down = function(knex) {
|
|
22
|
-
return knex.schema.dropTable('countries');
|
|
23
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('admins', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('admin_id').primary();
|
|
9
|
-
table.integer('country_id').unsigned().references('country_id').inTable('countries');
|
|
10
|
-
|
|
11
|
-
// Basic admin information
|
|
12
|
-
table.string('firstname', 100).nullable();
|
|
13
|
-
table.string('lastname', 100).nullable();
|
|
14
|
-
table.string('username', 100).notNullable().unique();
|
|
15
|
-
table.string('email', 255).nullable().unique();
|
|
16
|
-
table.string('password', 255).notNullable();
|
|
17
|
-
table.enum('role', ['admin', 'manager']).defaultTo('manager');
|
|
18
|
-
|
|
19
|
-
// Two-factor authentication fields
|
|
20
|
-
table.boolean('two_factor_enabled').defaultTo(false);
|
|
21
|
-
table.string('two_factor_secret', 32).nullable(); // TOTP secret
|
|
22
|
-
table.string('phone_number', 20).nullable();
|
|
23
|
-
table.boolean('phone_verified').defaultTo(false);
|
|
24
|
-
table.boolean('email_verified').defaultTo(false);
|
|
25
|
-
|
|
26
|
-
// Login security
|
|
27
|
-
table.integer('login_attempts').defaultTo(0);
|
|
28
|
-
table.timestamp('locked_until').nullable();
|
|
29
|
-
|
|
30
|
-
// Password security
|
|
31
|
-
table.timestamp('password_changed_at').nullable();
|
|
32
|
-
table.string('password_reset_token', 255).nullable();
|
|
33
|
-
|
|
34
|
-
// Email verification
|
|
35
|
-
table.string('email_verification_token', 255).nullable();
|
|
36
|
-
|
|
37
|
-
// Phone verification
|
|
38
|
-
table.string('phone_verification_code', 10).nullable();
|
|
39
|
-
|
|
40
|
-
// Address information
|
|
41
|
-
table.string('address', 255).nullable();
|
|
42
|
-
table.string('city', 100).nullable();
|
|
43
|
-
table.string('state', 100).nullable();
|
|
44
|
-
table.string('zip', 20).nullable();
|
|
45
|
-
|
|
46
|
-
// Status and timestamps
|
|
47
|
-
table.boolean('is_active').defaultTo(true);
|
|
48
|
-
|
|
49
|
-
// Audit timestamps
|
|
50
|
-
table.timestamps(true, true); // created_at and updated_at
|
|
51
|
-
|
|
52
|
-
// Indexes for performance
|
|
53
|
-
table.index(['role']);
|
|
54
|
-
table.index(['is_active']);
|
|
55
|
-
table.index(['two_factor_enabled']);
|
|
56
|
-
table.index(['created_at']);
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param { import("knex").Knex } knex
|
|
62
|
-
* @returns { Promise<void> }
|
|
63
|
-
*/
|
|
64
|
-
exports.down = function(knex) {
|
|
65
|
-
return knex.schema.dropTable('admins');
|
|
66
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('currencies', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('currency_id').primary();
|
|
9
|
-
table.string('name', 100).notNullable();
|
|
10
|
-
table.string('code', 100).notNullable();
|
|
11
|
-
table.string('symbol', 100).notNullable();
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param { import("knex").Knex } knex
|
|
17
|
-
* @returns { Promise<void> }
|
|
18
|
-
*/
|
|
19
|
-
exports.down = function(knex) {
|
|
20
|
-
return knex.schema.dropTable('currencies');
|
|
21
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('languages', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('language_id').primary();
|
|
9
|
-
table.string('name', 100).notNullable();
|
|
10
|
-
table.string('code', 100).notNullable();
|
|
11
|
-
table.string('flag', 100).notNullable();
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param { import("knex").Knex } knex
|
|
17
|
-
* @returns { Promise<void> }
|
|
18
|
-
*/
|
|
19
|
-
exports.down = function(knex) {
|
|
20
|
-
return knex.schema.dropTable('languages');
|
|
21
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('sites', function(table) {
|
|
7
|
-
table.increments('site_id').primary();
|
|
8
|
-
table.integer('admin_id').unsigned().references('admin_id').inTable('admins');
|
|
9
|
-
table.integer('currency_id').unsigned().references('currency_id').inTable('currencies');
|
|
10
|
-
table.integer('timezone_id').unsigned().references('timezone_id').inTable('timezones');
|
|
11
|
-
table.integer('language_id').unsigned().references('language_id').inTable('languages');
|
|
12
|
-
table.integer('country_id').unsigned().references('country_id').inTable('countries');
|
|
13
|
-
table.integer('tax_id').unsigned().references('tax_id').inTable('taxes');
|
|
14
|
-
table.string('name', 100).notNullable();
|
|
15
|
-
table.string('domain', 100).notNullable().unique();
|
|
16
|
-
table.string('logo', 100).notNullable();
|
|
17
|
-
table.string('favicon', 100).notNullable();
|
|
18
|
-
table.string('description', 100).notNullable();
|
|
19
|
-
table.string('keywords', 100).notNullable();
|
|
20
|
-
table.boolean('is_active').defaultTo(true);
|
|
21
|
-
table.datetime('expires_at').notNullable();
|
|
22
|
-
table.timestamps(true, true);
|
|
23
|
-
table.index(['admin_id'], 'site_admin_id_index');
|
|
24
|
-
table.index(['name'], 'site_name_index');
|
|
25
|
-
table.index(['domain'], 'site_domain_index');
|
|
26
|
-
table.index(['created_at'], 'site_created_at_index');
|
|
27
|
-
table.index(['updated_at'], 'site_updated_at_index');
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param { import("knex").Knex } knex
|
|
33
|
-
* @returns { Promise<void> }
|
|
34
|
-
*/
|
|
35
|
-
exports.down = function(knex) {
|
|
36
|
-
return knex.schema.dropTable('sites');
|
|
37
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = knex => knex.schema.createTable('payment_methods', function(table) {
|
|
6
|
-
// Primary key
|
|
7
|
-
table.increments('payment_method_id').primary();
|
|
8
|
-
table.integer('site_id').unsigned().references('site_id').inTable('sites');
|
|
9
|
-
table.integer('currency_id').unsigned().references('currency_id').inTable('currencies');
|
|
10
|
-
table.string('logo').defaultTo(null);
|
|
11
|
-
table.string('name').notNullable();
|
|
12
|
-
table.string('code').unique().notNullable();
|
|
13
|
-
table.string('provider').defaultTo(null);
|
|
14
|
-
table.string('api_key').defaultTo(null);
|
|
15
|
-
table.string('api_secret').defaultTo(null);
|
|
16
|
-
table.string('api_url').defaultTo(null);
|
|
17
|
-
table.string('api_version').defaultTo(null);
|
|
18
|
-
table.boolean('is_active').defaultTo(true);
|
|
19
|
-
table.timestamps(true, true);
|
|
20
|
-
}).createTable('payment_method_translations', table => {
|
|
21
|
-
table.increments('payment_method_translation_id').primary();
|
|
22
|
-
table.integer('payment_method_id').unsigned().references('payment_method_id').inTable('payment_methods').onDelete('CASCADE');
|
|
23
|
-
table.integer('language_id').unsigned().references('language_id').inTable('languages');
|
|
24
|
-
table.string('description').notNullable();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @param { import("knex").Knex } knex
|
|
29
|
-
* @returns { Promise<void> }
|
|
30
|
-
*/
|
|
31
|
-
exports.down = knex =>
|
|
32
|
-
knex.schema.dropTable('payment_method_translations')
|
|
33
|
-
.dropTable('payment_methods');
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('devices', function (table) {
|
|
7
|
-
table.increments('device_id').unsigned().notNullable().primary();
|
|
8
|
-
table.integer('personal_id');
|
|
9
|
-
table.enum('personal_type', ['admin', 'site', 'user']).notNullable();
|
|
10
|
-
table.string('unique_id', 100).notNullable();
|
|
11
|
-
table.string('ip_address', 100).notNullable();
|
|
12
|
-
table.text('device_information').notNullable();
|
|
13
|
-
table.boolean('two_factor_approved').defaultTo(false);
|
|
14
|
-
table.string('token', 255).notNullable();
|
|
15
|
-
table.datetime('last_login_at').notNullable();
|
|
16
|
-
table.string('last_login_ip', 100).notNullable();
|
|
17
|
-
table.datetime('created_at').notNullable().defaultTo(knex.fn.now());
|
|
18
|
-
table.datetime('updated_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
|
|
19
|
-
table.unique(['unique_id', 'personal_id', 'personal_type'], 'device_unique_index')
|
|
20
|
-
table.index(['personal_id', 'personal_type'], 'device_personal_index')
|
|
21
|
-
table.index(['token'], 'device_token_index')
|
|
22
|
-
})
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param { import("knex").Knex } knex
|
|
27
|
-
* @returns { Promise<void> }
|
|
28
|
-
*/
|
|
29
|
-
exports.down = async function(knex) {
|
|
30
|
-
if (process.env.NODE_ENV === 'production') {
|
|
31
|
-
throw new Error('Cannot drop table in production environment.')
|
|
32
|
-
} else {
|
|
33
|
-
if(await knex.schema.hasTable('devices')) {
|
|
34
|
-
return knex.schema.dropTable('devices');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('users', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('user_id').primary();
|
|
9
|
-
|
|
10
|
-
table.integer('site_id').unsigned().references('site_id').inTable('sites');
|
|
11
|
-
|
|
12
|
-
// Basic manager information
|
|
13
|
-
table.string('username', 50).notNullable().unique();
|
|
14
|
-
table.string('email', 255).nullable().unique();
|
|
15
|
-
table.string('password', 255).notNullable();
|
|
16
|
-
table.enum('type_user', ['vip', 'new', 'risky']).defaultTo('new');
|
|
17
|
-
|
|
18
|
-
// Two-factor authentication fields
|
|
19
|
-
table.boolean('two_factor_enabled').defaultTo(false);
|
|
20
|
-
table.string('two_factor_secret', 32).nullable(); // TOTP secret
|
|
21
|
-
table.string('phone_number', 20).nullable();
|
|
22
|
-
table.boolean('phone_verified').defaultTo(false);
|
|
23
|
-
table.boolean('email_verified').defaultTo(false);
|
|
24
|
-
|
|
25
|
-
// Login security
|
|
26
|
-
table.integer('login_attempts').defaultTo(0);
|
|
27
|
-
table.timestamp('locked_until').nullable();
|
|
28
|
-
|
|
29
|
-
// Password security and reset
|
|
30
|
-
table.timestamp('password_changed_at').nullable();
|
|
31
|
-
table.string('password_reset_token', 255).nullable();
|
|
32
|
-
|
|
33
|
-
// Email verification and reset
|
|
34
|
-
table.string('email_verification_token', 255).nullable();
|
|
35
|
-
|
|
36
|
-
// Phone verification and reset
|
|
37
|
-
table.string('phone_verification_code', 10).nullable();
|
|
38
|
-
|
|
39
|
-
// Account security
|
|
40
|
-
table.boolean('is_active').defaultTo(true);
|
|
41
|
-
|
|
42
|
-
// Audit timestamps
|
|
43
|
-
table.timestamps(true, true); // created_at and updated_at
|
|
44
|
-
|
|
45
|
-
// Indexes for performance and security
|
|
46
|
-
table.index(['type_user']);
|
|
47
|
-
table.index(['is_active']);
|
|
48
|
-
table.index(['two_factor_enabled']);
|
|
49
|
-
table.index(['phone_verified']);
|
|
50
|
-
table.index(['email_verified']);
|
|
51
|
-
table.index(['created_at']);
|
|
52
|
-
table.index(['locked_until']);
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param { import("knex").Knex } knex
|
|
58
|
-
* @returns { Promise<void> }
|
|
59
|
-
*/
|
|
60
|
-
exports.down = function(knex) {
|
|
61
|
-
return knex.schema.dropTable('users');
|
|
62
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param { import("knex").Knex } knex
|
|
3
|
-
* @returns { Promise<void> }
|
|
4
|
-
*/
|
|
5
|
-
exports.up = function(knex) {
|
|
6
|
-
return knex.schema.createTable('language_lines', function(table) {
|
|
7
|
-
// Primary key
|
|
8
|
-
table.increments('language_line_id').primary();
|
|
9
|
-
|
|
10
|
-
// Basic manager information
|
|
11
|
-
table.integer('language_id').notNullable();
|
|
12
|
-
table.string('group', 50).notNullable();
|
|
13
|
-
table.string('key', 50).notNullable();
|
|
14
|
-
table.text('text').notNullable();
|
|
15
|
-
table.boolean('is_modified').defaultTo(false);
|
|
16
|
-
|
|
17
|
-
table.timestamps(true, true);
|
|
18
|
-
|
|
19
|
-
table.unique(['language_id', 'group', 'key'], 'language_line_unique_index');
|
|
20
|
-
table.index(['language_id'], 'language_line_language_index');
|
|
21
|
-
table.index(['group'], 'language_line_group_index');
|
|
22
|
-
table.index(['key'], 'language_line_key_index');
|
|
23
|
-
table.index(['is_modified'], 'language_line_is_modified_index');
|
|
24
|
-
table.index(['created_at'], 'language_line_created_at_index');
|
|
25
|
-
table.index(['updated_at'], 'language_line_updated_at_index');
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @param { import("knex").Knex } knex
|
|
31
|
-
* @returns { Promise<void> }
|
|
32
|
-
*/
|
|
33
|
-
exports.down = function(knex) {
|
|
34
|
-
return knex.schema.dropTable('language_lines');
|
|
35
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
exports.up = knex =>
|
|
2
|
-
knex.schema
|
|
3
|
-
.createTable('category_groups', table => {
|
|
4
|
-
table.increments('category_group_id').primary();
|
|
5
|
-
table.integer('site_id').unsigned().references('site_id').inTable('sites');
|
|
6
|
-
table.timestamps(true, true);
|
|
7
|
-
})
|
|
8
|
-
.createTable('category_group_translations', table => {
|
|
9
|
-
table.increments('category_group_translation_id').primary();
|
|
10
|
-
table.integer('category_group_id').unsigned().references('category_group_id').inTable('category_groups').onDelete('CASCADE');
|
|
11
|
-
table.integer('language_id').unsigned().references('language_id').inTable('languages');
|
|
12
|
-
table.string('name').notNullable();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
exports.down = knex =>
|
|
16
|
-
knex.schema
|
|
17
|
-
.dropTable('category_group_translations')
|
|
18
|
-
.dropTable('category_groups');
|