@ecopex/ecopex-framework 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 (81) hide show
  1. package/.env +73 -0
  2. package/README.md +248 -0
  3. package/bun.lockb +0 -0
  4. package/config/swagger/admin.js +44 -0
  5. package/config/swagger/api.js +19 -0
  6. package/database/migrations/20240000135243_timezones.js +22 -0
  7. package/database/migrations/20240000135244_countries.js +23 -0
  8. package/database/migrations/20240000135244_create_admins_table.js +66 -0
  9. package/database/migrations/20240000135244_currencies.js +21 -0
  10. package/database/migrations/20240000135244_languages.js +21 -0
  11. package/database/migrations/20240000135244_taxes.js +10 -0
  12. package/database/migrations/20240000135245_sites.js +37 -0
  13. package/database/migrations/20240000135246_payment_methods.js +33 -0
  14. package/database/migrations/20251016113547_devices.js +37 -0
  15. package/database/migrations/20251019192600_users.js +62 -0
  16. package/database/migrations/20251019213551_language_lines.js +35 -0
  17. package/database/migrations/20251222214131_category_groups.js +18 -0
  18. package/database/migrations/20251222214619_categories.js +27 -0
  19. package/database/migrations/20251222214848_brands.js +23 -0
  20. package/database/migrations/20251222214946_products.js +30 -0
  21. package/database/migrations/20251222215428_product_images.js +18 -0
  22. package/database/migrations/20251222215553_options.js +30 -0
  23. package/database/migrations/20251222215806_variants.js +23 -0
  24. package/database/migrations/20251222215940_attributes.js +25 -0
  25. package/database/migrations/20251222220135_discounts.js +15 -0
  26. package/database/migrations/20251222220253_reviews.js +22 -0
  27. package/database/migrations/20251222220341_favorites.js +10 -0
  28. package/database/migrations/20251222220422_search_logs.js +17 -0
  29. package/database/migrations/20251222220636_orders.js +16 -0
  30. package/database/migrations/20251222220806_order_items.js +19 -0
  31. package/database/migrations/20251222221317_order_statuses.js +10 -0
  32. package/database/migrations/20251222221446_order_payments.js +13 -0
  33. package/database/migrations/20251222221654_order_addresses.js +23 -0
  34. package/database/migrations/20251222221807_order_status_logs.js +13 -0
  35. package/database/seeds/admins.js +37 -0
  36. package/database/seeds/countries.js +203 -0
  37. package/database/seeds/currencies.js +165 -0
  38. package/database/seeds/languages.js +113 -0
  39. package/database/seeds/timezones.js +149 -0
  40. package/ecosystem.config.js +26 -0
  41. package/env.example +73 -0
  42. package/knexfile.js +3 -0
  43. package/libraries/2fa.js +22 -0
  44. package/libraries/aws.js +63 -0
  45. package/libraries/bcrypt.js +284 -0
  46. package/libraries/controls.js +113 -0
  47. package/libraries/date.js +14 -0
  48. package/libraries/general.js +8 -0
  49. package/libraries/image.js +57 -0
  50. package/libraries/jwt.js +178 -0
  51. package/libraries/knex.js +7 -0
  52. package/libraries/slug.js +14 -0
  53. package/libraries/stores.js +22 -0
  54. package/libraries/upload.js +194 -0
  55. package/locales/en/messages.json +4 -0
  56. package/locales/en/sql.json +3 -0
  57. package/locales/en/validation.json +52 -0
  58. package/locales/es/validation.json +52 -0
  59. package/locales/tr/validation.json +59 -0
  60. package/package.json +75 -0
  61. package/routes/admin/auto/admins.json +63 -0
  62. package/routes/admin/auto/devices.json +37 -0
  63. package/routes/admin/auto/migrations.json +21 -0
  64. package/routes/admin/auto/users.json +61 -0
  65. package/routes/admin/middlewares/index.js +87 -0
  66. package/routes/admin/spec/auth.js +626 -0
  67. package/routes/admin/spec/users.js +3 -0
  68. package/routes/auto/handler.js +635 -0
  69. package/routes/common/auto/countries.json +28 -0
  70. package/routes/common/auto/currencies.json +26 -0
  71. package/routes/common/auto/languages.json +26 -0
  72. package/routes/common/auto/taxes.json +46 -0
  73. package/routes/common/auto/timezones.json +29 -0
  74. package/stores/base.js +73 -0
  75. package/stores/index.js +195 -0
  76. package/utils/i18n.js +187 -0
  77. package/utils/jsonRouteLoader.js +587 -0
  78. package/utils/middleware.js +154 -0
  79. package/utils/routeLoader.js +227 -0
  80. package/workers/admin.js +124 -0
  81. package/workers/api.js +106 -0
@@ -0,0 +1,62 @@
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
+ };
@@ -0,0 +1,35 @@
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
+ };
@@ -0,0 +1,18 @@
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');
@@ -0,0 +1,27 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('categories', table => {
4
+ table.increments('category_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.integer('parent_id').unsigned().nullable().references('category_id').inTable('categories').onDelete('SET NULL');
7
+ table.integer('category_group_id').unsigned().references('category_group_id').inTable('category_groups');
8
+ table.integer('order').notNullable().defaultTo(0);
9
+ table.boolean('is_active').defaultTo(true);
10
+ table.string('image').nullable();
11
+ table.string('icon').nullable();
12
+ table.string('color', 7).nullable();
13
+ table.timestamps(true, true);
14
+ })
15
+ .createTable('category_translations', table => {
16
+ table.increments('category_translation_id').primary();
17
+ table.integer('category_id').unsigned().references('category_id').inTable('categories').onDelete('CASCADE');
18
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
19
+ table.string('name').notNullable();
20
+ table.text('description').nullable();
21
+ table.string('slug').notNullable();
22
+ });
23
+
24
+ exports.down = knex =>
25
+ knex.schema
26
+ .dropTable('category_translations')
27
+ .dropTable('categories');
@@ -0,0 +1,23 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('brands', table => {
4
+ table.increments('brand_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.boolean('is_active').defaultTo(true);
7
+ table.string('image').nullable();
8
+ table.string('icon').nullable();
9
+ table.string('color', 7).nullable();
10
+ table.timestamps(true, true);
11
+ })
12
+ .createTable('brand_translations', table => {
13
+ table.increments('brand_translation_id').primary();
14
+ table.integer('brand_id').unsigned().references('brand_id').inTable('brands').onDelete('CASCADE');
15
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
16
+ table.string('name').notNullable();
17
+ table.string('slug').notNullable();
18
+ });
19
+
20
+ exports.down = knex =>
21
+ knex.schema
22
+ .dropTable('brand_translations')
23
+ .dropTable('brands');
@@ -0,0 +1,30 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('products', table => {
4
+ table.increments('product_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.integer('brand_id').unsigned().references('brand_id').inTable('brands');
7
+ table.integer('category_id').unsigned().references('category_id').inTable('categories');
8
+ table.integer('currency_id').unsigned().references('currency_id').inTable('currencies');
9
+ table.integer('country_id').unsigned().references('country_id').inTable('countries');
10
+ table.integer('tax_id').unsigned().references('tax_id').inTable('taxes');
11
+ table.enum('product_type', ['physical', 'digital', 'service', 'third_party']).notNullable();
12
+ table.boolean('is_active').defaultTo(true);
13
+ table.timestamps(true, true);
14
+ })
15
+ .createTable('product_translations', table => {
16
+ table.increments('product_translation_id').primary();
17
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
18
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
19
+ table.string('title').notNullable();
20
+ table.text('description');
21
+ table.string('slug').notNullable();
22
+ table.index(['title'], 'product_title_index', {
23
+ type: 'fulltext'
24
+ });
25
+ });
26
+
27
+ exports.down = knex =>
28
+ knex.schema
29
+ .dropTable('product_translations')
30
+ .dropTable('products');
@@ -0,0 +1,18 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('product_images', table => {
3
+ table.increments('product_image_id').primary();
4
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
5
+ table.string('image_url').notNullable();
6
+ table.boolean('is_main').defaultTo(false);
7
+ table.integer('order').defaultTo(0);
8
+ table.boolean('is_active').defaultTo(true);
9
+ table.timestamps(true, true);
10
+ table.index(['product_id'], 'product_image_product_index');
11
+ table.index(['is_main'], 'product_image_is_main_index');
12
+ table.index(['order'], 'product_image_order_index');
13
+ table.index(['created_at'], 'product_image_created_at_index');
14
+ table.index(['updated_at'], 'product_image_updated_at_index');
15
+ });
16
+
17
+ exports.down = knex =>
18
+ knex.schema.dropTable('product_images');
@@ -0,0 +1,30 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('option_types', table => {
4
+ table.increments('option_type_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.string('code').unique();
7
+ })
8
+ .createTable('option_type_translations', table => {
9
+ table.increments('option_type_translation_id').primary();
10
+ table.integer('option_type_id').unsigned().references('option_type_id').inTable('option_types').onDelete('CASCADE');
11
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
12
+ table.string('name').notNullable();
13
+ })
14
+ .createTable('option_values', table => {
15
+ table.increments('option_value_id').primary();
16
+ table.integer('option_type_id').unsigned().references('option_type_id').inTable('option_types').onDelete('CASCADE');
17
+ })
18
+ .createTable('option_value_translations', table => {
19
+ table.increments('option_value_translation_id').primary();
20
+ table.integer('option_value_id').unsigned().references('option_value_id').inTable('option_values').onDelete('CASCADE');
21
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
22
+ table.string('value').notNullable();
23
+ });
24
+
25
+ exports.down = knex =>
26
+ knex.schema
27
+ .dropTable('option_value_translations')
28
+ .dropTable('option_values')
29
+ .dropTable('option_type_translations')
30
+ .dropTable('option_types');
@@ -0,0 +1,23 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('product_variants', table => {
4
+ table.increments('product_variant_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
7
+ table.string('sku').unique();
8
+ table.decimal('price', 10, 2);
9
+ table.decimal('discount_price', 10, 2);
10
+ table.integer('stock').defaultTo(0);
11
+ })
12
+ .createTable('product_variant_options', table => {
13
+ table.increments('product_variant_option_id').primary();
14
+ table.integer('product_variant_id').unsigned().references('product_variant_id').inTable('product_variants').onDelete('CASCADE');
15
+ table.integer('option_value_id').unsigned().references('option_value_id').inTable('option_values').onDelete('CASCADE');
16
+ table.integer('option_type_id').unsigned().references('option_type_id').inTable('option_types').onDelete('CASCADE');
17
+ table.decimal('variant_price', 16, 2).defaultTo(0);
18
+ });
19
+
20
+ exports.down = knex =>
21
+ knex.schema
22
+ .dropTable('product_variant_options')
23
+ .dropTable('product_variants');
@@ -0,0 +1,25 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('attributes', table => {
4
+ table.increments('attribute_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.integer('category_id').unsigned().references('category_id').inTable('categories').onDelete('CASCADE');
7
+ })
8
+ .createTable('attribute_translations', table => {
9
+ table.increments('attribute_translation_id').primary();
10
+ table.integer('attribute_id').unsigned().references('attribute_id').inTable('attributes').onDelete('CASCADE');
11
+ table.integer('language_id').unsigned().references('language_id').inTable('languages');
12
+ table.string('name').notNullable();
13
+ })
14
+ .createTable('product_attributes', table => {
15
+ table.increments('product_attribute_id').primary();
16
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
17
+ table.integer('attribute_id').unsigned().references('attribute_id').inTable('attributes').onDelete('CASCADE');
18
+ table.string('value').notNullable();
19
+ });
20
+
21
+ exports.down = knex =>
22
+ knex.schema
23
+ .dropTable('product_attributes')
24
+ .dropTable('attribute_translations')
25
+ .dropTable('attributes');
@@ -0,0 +1,15 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('discounts', table => {
3
+ table.increments('discount_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.enum('type', ['global', 'category']);
6
+ table.integer('brand_id').unsigned().nullable().references('brand_id').inTable('brands');
7
+ table.integer('category_id').unsigned().nullable().references('category_id').inTable('categories');
8
+ table.decimal('percentage', 5, 2).defaultTo(0);
9
+ table.decimal('amount', 16, 2).defaultTo(0);
10
+ table.date('start_date');
11
+ table.date('end_date');
12
+ });
13
+
14
+ exports.down = knex =>
15
+ knex.schema.dropTable('discounts');
@@ -0,0 +1,22 @@
1
+ exports.up = knex =>
2
+ knex.schema
3
+ .createTable('reviews', table => {
4
+ table.increments('review_id').primary();
5
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
6
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
7
+ table.integer('user_id').unsigned().references('user_id').inTable('users');
8
+ table.integer('rating').defaultTo(0);
9
+ table.text('comment');
10
+ table.boolean('is_approved').defaultTo(false);
11
+ table.timestamps(true, true);
12
+ })
13
+ .createTable('review_images', table => {
14
+ table.increments('review_image_id').primary();
15
+ table.integer('review_id').unsigned().references('review_id').inTable('reviews').onDelete('CASCADE');
16
+ table.string('image_url').notNullable();
17
+ });
18
+
19
+ exports.down = knex =>
20
+ knex.schema
21
+ .dropTable('review_images')
22
+ .dropTable('reviews');
@@ -0,0 +1,10 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('favorites', table => {
3
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
4
+ table.integer('user_id').unsigned().references('user_id').inTable('users').onDelete('CASCADE');
5
+ table.integer('product_id').unsigned().references('product_id').inTable('products').onDelete('CASCADE');
6
+ table.primary(['site_id', 'user_id', 'product_id']);
7
+ });
8
+
9
+ exports.down = knex =>
10
+ knex.schema.dropTable('favorites');
@@ -0,0 +1,17 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('search_logs', table => {
3
+ table.increments('search_log_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('user_id').unsigned().references('user_id').inTable('users');
6
+ table.string('keyword').notNullable();
7
+ table.integer('search_count').defaultTo(1);
8
+ table.timestamp('last_searched_at').notNullable();
9
+ table.timestamps(true, true);
10
+ table.index(['site_id'], 'search_log_site_index');
11
+ table.index(['user_id'], 'search_log_user_index');
12
+ table.index(['keyword'], 'search_log_keyword_index');
13
+ table.index(['last_searched_at'], 'search_log_last_searched_at_index');
14
+ });
15
+
16
+ exports.down = knex =>
17
+ knex.schema.dropTable('search_logs');
@@ -0,0 +1,16 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('orders', table => {
3
+ table.increments('order_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('user_id').nullable().unsigned().references('user_id').inTable('users');
6
+ table.string('order_number').unique().notNullable();
7
+ table.decimal('subtotal', 10, 2).notNullable();
8
+ table.decimal('discount_total', 10, 2).defaultTo(0);
9
+ table.decimal('shipping_total', 10, 2).defaultTo(0);
10
+ table.decimal('grand_total', 10, 2).notNullable();
11
+
12
+ table.timestamps(true, true);
13
+ });
14
+
15
+ exports.down = knex =>
16
+ knex.schema.dropTable('orders');
@@ -0,0 +1,19 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('order_items', table => {
3
+ table.increments('order_item_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('order_id').unsigned().references('order_id').inTable('orders').onDelete('CASCADE');
6
+ table.integer('product_id').unsigned().nullable().references('product_id').inTable('products');
7
+ table.integer('product_variant_id').unsigned().nullable().references('product_variant_id').inTable('product_variants');
8
+ table.integer('currency_id').unsigned().nullable().references('currency_id').inTable('currencies');
9
+ table.integer('discount_id').unsigned().nullable().references('discount_id').inTable('discounts');
10
+ table.integer('tax_id').unsigned().nullable().references('tax_id').inTable('taxes');
11
+ table.decimal('unit_price', 10, 2).notNullable();
12
+ table.decimal('discount_price', 10, 2).nullable();
13
+ table.integer('quantity').notNullable();
14
+ table.decimal('total_price', 10, 2).notNullable();
15
+ table.timestamps(true, true);
16
+ });
17
+
18
+ exports.down = knex =>
19
+ knex.schema.dropTable('order_items');
@@ -0,0 +1,10 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('order_statuses', table => {
3
+ table.increments('order_status_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.string('code').unique().notNullable();
6
+ table.boolean('is_default').defaultTo(false);
7
+ });
8
+
9
+ exports.down = knex =>
10
+ knex.schema.dropTable('order_statuses');
@@ -0,0 +1,13 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('order_payments', table => {
3
+ table.increments('order_payment_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('order_id').unsigned().references('order_id').inTable('orders').onDelete('CASCADE');
6
+ table.integer('order_status_id').unsigned().references('order_status_id').inTable('order_statuses');
7
+ table.integer('payment_method_id').unsigned().references('payment_method_id').inTable('payment_methods');
8
+ table.decimal('amount', 10, 2).notNullable();
9
+ table.timestamps(true, true);
10
+ });
11
+
12
+ exports.down = knex =>
13
+ knex.schema.dropTable('order_payments');
@@ -0,0 +1,23 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('order_addresses', table => {
3
+ table.increments('order_address_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('order_id').unsigned().references('order_id').inTable('orders').onDelete('CASCADE');
6
+ table.enum('type', ['billing', 'shipping']).notNullable();
7
+
8
+ table.string('full_name');
9
+ table.string('phone');
10
+ table.string('country');
11
+ table.string('city');
12
+ table.string('district');
13
+ table.text('address');
14
+ table.string('postal_code');
15
+
16
+ table.string('tax_number');
17
+ table.string('tax_office');
18
+
19
+ table.timestamps(true, true);
20
+ });
21
+
22
+ exports.down = knex =>
23
+ knex.schema.dropTable('order_addresses');
@@ -0,0 +1,13 @@
1
+ exports.up = knex =>
2
+ knex.schema.createTable('order_status_logs', table => {
3
+ table.increments('order_status_log_id').primary();
4
+ table.integer('site_id').unsigned().references('site_id').inTable('sites');
5
+ table.integer('order_id').unsigned().references('order_id').inTable('orders').onDelete('CASCADE');
6
+ table.integer('status_id').unsigned().references('order_status_id').inTable('order_statuses');
7
+ table.integer('changed_by').unsigned().nullable().references('admin_id').inTable('admins');
8
+ table.text('note');
9
+ table.timestamps(true, true);
10
+ });
11
+
12
+ exports.down = knex =>
13
+ knex.schema.dropTable('order_status_logs');
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Seed the admins table with a default admin user.
3
+ * @param { import("knex").Knex } knex
4
+ */
5
+ const bcrypt = require('bcryptjs');
6
+
7
+ exports.seed = async function(knex) {
8
+ // Hash the password using bcrypt
9
+ const hashedPassword = await bcrypt.hash('123123', 10);
10
+
11
+ // Inserts a default admin user
12
+ await knex('admins').insert([
13
+ {
14
+ firstname: 'Admin',
15
+ lastname: 'Admin',
16
+ username: 'admin',
17
+ email: 'admin@admin.com',
18
+ password: hashedPassword,
19
+ role: 'admin',
20
+ two_factor_enabled: true,
21
+ two_factor_secret: 'WZVMTNVU4JZAXHAKSYJIKN7S2IRAZSS5',
22
+ is_active: true
23
+ },
24
+ {
25
+ firstname: 'Support',
26
+ lastname: 'Support',
27
+ username: 'support',
28
+ email: 'support@support.com',
29
+ password: hashedPassword,
30
+ role: 'support',
31
+ two_factor_enabled: true,
32
+ two_factor_secret: 'WZVMTNVU4JZAXHAKSYJIKN7S2IRAZSS5',
33
+ is_active: true
34
+ }
35
+ ]).onConflict('username').merge();
36
+ };
37
+