ojamoto_models 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 (65) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/LICENSE +21 -0
  3. package/certificates/global-bundle.pem +2736 -0
  4. package/config/config.js +52 -0
  5. package/index.js +3 -0
  6. package/migrations/2026000001-create-users.js +97 -0
  7. package/migrations/2026000002-create-and-seed-roles.js +43 -0
  8. package/migrations/2026000003-create-admin-users.js +83 -0
  9. package/migrations/2026000004-create-devices.js +67 -0
  10. package/migrations/2026000005-create-products.js +87 -0
  11. package/migrations/2026000006-create-addresses.js +74 -0
  12. package/migrations/2026000007-create-wallets.js +44 -0
  13. package/migrations/2026000008-create-kyc-verification.js +51 -0
  14. package/migrations/2026000009-create-seller-profiles.js +80 -0
  15. package/migrations/2026000010-create-user-roles.js +48 -0
  16. package/migrations/2026000011-create-sessions.js +61 -0
  17. package/migrations/2026000012-create-escrows.js +80 -0
  18. package/migrations/2026000013-create-wallet-transactions.js +70 -0
  19. package/migrations/2026000014-create-product-images.js +43 -0
  20. package/migrations/2026000015-create-escrow-events.js +50 -0
  21. package/migrations/2026000016-create-logistics.js +55 -0
  22. package/migrations/2026000017-create-ratings.js +56 -0
  23. package/migrations/2026000018-create-disputes.js +84 -0
  24. package/migrations/2026000019-create-dispute-evidence.js +50 -0
  25. package/migrations/2026000020-create-dispute-messages.js +44 -0
  26. package/migrations/2026000021-create-notifications.js +50 -0
  27. package/migrations/2026000022-create-audit-logs.js +57 -0
  28. package/migrations/2026000023-create-webhook-logs.js +46 -0
  29. package/migrations/2026000024-create-user-otps.js +75 -0
  30. package/migrations/2026000025-create-password-reset-otps.js +43 -0
  31. package/migrations/2026000026-create-seller-badges.js +43 -0
  32. package/migrations/2026000027-add-fulltext-index-for-search.js +15 -0
  33. package/migrations/2026000028-create-admin-notifications.js +53 -0
  34. package/migrations/2026000029-create-pin-reset-otp.js +30 -0
  35. package/models/Address.js +76 -0
  36. package/models/AdminNotification.js +59 -0
  37. package/models/AdminUser.js +115 -0
  38. package/models/AuditLog.js +70 -0
  39. package/models/Device.js +82 -0
  40. package/models/Dispute.js +109 -0
  41. package/models/DisputeEvidence.js +62 -0
  42. package/models/DisputeMessage.js +57 -0
  43. package/models/Escrow.js +110 -0
  44. package/models/EscrowEvent.js +63 -0
  45. package/models/KycVerification.js +62 -0
  46. package/models/Logistics.js +62 -0
  47. package/models/Notification.js +58 -0
  48. package/models/PasswordResetOTP.js +52 -0
  49. package/models/PinResetOTP.js +48 -0
  50. package/models/Product.js +100 -0
  51. package/models/ProductImage.js +54 -0
  52. package/models/Rating.js +74 -0
  53. package/models/Role.js +43 -0
  54. package/models/SellerBadges.js +45 -0
  55. package/models/SellerProfile.js +92 -0
  56. package/models/Session.js +67 -0
  57. package/models/User.js +198 -0
  58. package/models/UserOTP.js +84 -0
  59. package/models/UserRole.js +42 -0
  60. package/models/Wallet.js +63 -0
  61. package/models/WalletTransaction.js +81 -0
  62. package/models/WebhookLog.js +52 -0
  63. package/models/index.js +23 -0
  64. package/package.json +30 -0
  65. package/services/constants.js +162 -0
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+
5
+ module.exports = (sequelize) => {
6
+ class PasswordResetOtp extends Model {
7
+ static associate(models) {}
8
+ }
9
+
10
+ PasswordResetOtp.init(
11
+ {
12
+ password_reset_otp_id: {
13
+ type: DataTypes.INTEGER,
14
+ primaryKey: true,
15
+ autoIncrement: true,
16
+ allowNull: false,
17
+ },
18
+ email: {
19
+ type: DataTypes.STRING,
20
+ allowNull: false,
21
+ },
22
+ otp: {
23
+ type: DataTypes.STRING,
24
+ allowNull: false,
25
+ comment: "Hashed before storage",
26
+ },
27
+ expires_at: {
28
+ type: DataTypes.DATE,
29
+ allowNull: false,
30
+ },
31
+ },
32
+ {
33
+ sequelize,
34
+ modelName: "PasswordResetOtp",
35
+ tableName: "password_reset_otps",
36
+ timestamps: true,
37
+ paranoid: false,
38
+ createdAt: "created_at",
39
+ updatedAt: "updated_at",
40
+ indexes: [
41
+ {
42
+ unique: true,
43
+ fields: ["email"],
44
+ name: "password_reset_otps_email_unique",
45
+ },
46
+ ],
47
+ },
48
+ );
49
+
50
+ PasswordResetOtp.removeAttribute("id");
51
+ return PasswordResetOtp;
52
+ };
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+
5
+ module.exports = (sequelize) => {
6
+ class PinResetOtp extends Model {
7
+ static associate(models) {
8
+ PinResetOtp.belongsTo(models.User, { foreignKey: "user_id", as: "user" });
9
+ }
10
+ }
11
+
12
+ PinResetOtp.init(
13
+ {
14
+ pin_reset_otp_id: {
15
+ type: DataTypes.INTEGER,
16
+ primaryKey: true,
17
+ autoIncrement: true,
18
+ },
19
+ user_id: {
20
+ type: DataTypes.INTEGER,
21
+ allowNull: false,
22
+ unique: true,
23
+ references: { model: "users", key: "user_id" },
24
+ onDelete: "CASCADE",
25
+ },
26
+ otp: {
27
+ type: DataTypes.STRING,
28
+ allowNull: false,
29
+ comment: "Hashed before storage",
30
+ },
31
+ expires_at: {
32
+ type: DataTypes.DATE,
33
+ allowNull: false,
34
+ },
35
+ },
36
+ {
37
+ sequelize,
38
+ modelName: "PinResetOtp",
39
+ tableName: "pin_reset_otps",
40
+ timestamps: true,
41
+ createdAt: "created_at",
42
+ updatedAt: "updated_at",
43
+ },
44
+ );
45
+
46
+ PinResetOtp.removeAttribute("id");
47
+ return PinResetOtp;
48
+ };
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+ const { PRODUCT_CONDITION, PRODUCT_STATUS } = require("../services/constants");
5
+
6
+ module.exports = (sequelize) => {
7
+ class Product extends Model {
8
+ static associate(models) {
9
+ Product.belongsTo(models.User, {
10
+ foreignKey: "seller_id",
11
+ as: "seller",
12
+ });
13
+
14
+ Product.hasMany(models.ProductImage, {
15
+ foreignKey: "product_id",
16
+ as: "images",
17
+ });
18
+
19
+ Product.hasMany(models.Escrow, {
20
+ foreignKey: "product_id",
21
+ as: "escrows",
22
+ });
23
+ }
24
+ }
25
+
26
+ Product.init(
27
+ {
28
+ product_id: {
29
+ type: DataTypes.INTEGER,
30
+ primaryKey: true,
31
+ autoIncrement: true,
32
+ },
33
+ seller_id: {
34
+ type: DataTypes.INTEGER,
35
+ allowNull: false,
36
+ references: { model: "users", key: "user_id" },
37
+ onDelete: "CASCADE",
38
+ },
39
+ name: {
40
+ type: DataTypes.STRING(255),
41
+ allowNull: false,
42
+ },
43
+ description: {
44
+ type: DataTypes.TEXT,
45
+ allowNull: true,
46
+ },
47
+ price: {
48
+ type: DataTypes.DECIMAL(15, 2),
49
+ allowNull: false,
50
+ },
51
+ currency: {
52
+ type: DataTypes.STRING(3),
53
+ allowNull: false,
54
+ defaultValue: "NGN",
55
+ },
56
+ category: {
57
+ type: DataTypes.STRING(100),
58
+ allowNull: true,
59
+ comment: "Engine | Brake | Suspension etc.",
60
+ },
61
+ brand: {
62
+ type: DataTypes.STRING(100),
63
+ allowNull: true,
64
+ comment: "Toyota, Ford, Bosch etc.",
65
+ },
66
+ model: {
67
+ type: DataTypes.STRING(100),
68
+ allowNull: true,
69
+ comment: "Camry, F-150 etc.",
70
+ },
71
+ condition: {
72
+ type: DataTypes.ENUM(...Object.values(PRODUCT_CONDITION)),
73
+ allowNull: false,
74
+ },
75
+ stock: {
76
+ type: DataTypes.INTEGER,
77
+ allowNull: false,
78
+ defaultValue: 1,
79
+ },
80
+ status: {
81
+ type: DataTypes.ENUM(...Object.values(PRODUCT_STATUS)),
82
+ allowNull: false,
83
+ defaultValue: PRODUCT_STATUS.DRAFT,
84
+ },
85
+ },
86
+ {
87
+ sequelize,
88
+ modelName: "Product",
89
+ tableName: "products",
90
+ timestamps: true,
91
+ paranoid: true,
92
+ createdAt: "created_at",
93
+ updatedAt: "updated_at",
94
+ deletedAt: "deleted_at",
95
+ },
96
+ );
97
+
98
+ Product.removeAttribute("id");
99
+ return Product;
100
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+
5
+ module.exports = (sequelize) => {
6
+ class ProductImage extends Model {
7
+ static associate(models) {
8
+ ProductImage.belongsTo(models.Product, {
9
+ foreignKey: "product_id",
10
+ as: "product",
11
+ });
12
+ }
13
+ }
14
+
15
+ ProductImage.init(
16
+ {
17
+ product_image_id: {
18
+ type: DataTypes.INTEGER,
19
+ primaryKey: true,
20
+ autoIncrement: true,
21
+ },
22
+ product_id: {
23
+ type: DataTypes.INTEGER,
24
+ allowNull: false,
25
+ references: { model: "products", key: "product_id" },
26
+ onDelete: "CASCADE",
27
+ },
28
+ image_url: {
29
+ type: DataTypes.STRING(500),
30
+ allowNull: false,
31
+ comment: "AWS S3 URL",
32
+ },
33
+ position: {
34
+ type: DataTypes.INTEGER,
35
+ defaultValue: 0,
36
+ comment: "Display order",
37
+ },
38
+ ai_metadata: {
39
+ type: DataTypes.JSON,
40
+ allowNull: true,
41
+ comment: "Brand, model, condition extracted by AI analysis",
42
+ },
43
+ },
44
+ {
45
+ sequelize,
46
+ modelName: "ProductImage",
47
+ tableName: "product_images",
48
+ timestamps: false,
49
+ },
50
+ );
51
+
52
+ ProductImage.removeAttribute("id");
53
+ return ProductImage;
54
+ };
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+
5
+ module.exports = (sequelize) => {
6
+ class Rating extends Model {
7
+ static associate(models) {
8
+ Rating.belongsTo(models.Escrow, {
9
+ foreignKey: "escrow_id",
10
+ as: "escrow",
11
+ });
12
+
13
+ Rating.belongsTo(models.User, {
14
+ foreignKey: "buyer_id",
15
+ as: "buyer",
16
+ });
17
+
18
+ Rating.belongsTo(models.User, {
19
+ foreignKey: "seller_id",
20
+ as: "seller",
21
+ });
22
+ }
23
+ }
24
+
25
+ Rating.init(
26
+ {
27
+ rating_id: {
28
+ type: DataTypes.INTEGER,
29
+ primaryKey: true,
30
+ autoIncrement: true,
31
+ },
32
+ escrow_id: {
33
+ type: DataTypes.INTEGER,
34
+ allowNull: false,
35
+ unique: true,
36
+ references: { model: "escrows", key: "escrow_id" },
37
+ onDelete: "RESTRICT",
38
+ comment: "One rating per completed escrow",
39
+ },
40
+ buyer_id: {
41
+ type: DataTypes.INTEGER,
42
+ allowNull: false,
43
+ references: { model: "users", key: "user_id" },
44
+ onDelete: "RESTRICT",
45
+ },
46
+ seller_id: {
47
+ type: DataTypes.INTEGER,
48
+ allowNull: false,
49
+ references: { model: "users", key: "user_id" },
50
+ onDelete: "RESTRICT",
51
+ },
52
+ rating: {
53
+ type: DataTypes.TINYINT,
54
+ allowNull: false,
55
+ validate: { min: 1, max: 5 },
56
+ },
57
+ comment: {
58
+ type: DataTypes.TEXT,
59
+ allowNull: true,
60
+ },
61
+ },
62
+ {
63
+ sequelize,
64
+ modelName: "Rating",
65
+ tableName: "ratings",
66
+ timestamps: true,
67
+ createdAt: "created_at",
68
+ updatedAt: false,
69
+ },
70
+ );
71
+
72
+ Rating.removeAttribute("id");
73
+ return Rating;
74
+ };
package/models/Role.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+ const { ROLE_NAME } = require("../services/constants");
5
+
6
+ module.exports = (sequelize) => {
7
+ class Role extends Model {
8
+ static associate(models) {
9
+ Role.belongsToMany(models.User, {
10
+ through: models.UserRole,
11
+ foreignKey: "role_id",
12
+ otherKey: "user_id",
13
+ as: "users",
14
+ });
15
+ }
16
+ }
17
+
18
+ Role.init(
19
+ {
20
+ role_id: {
21
+ type: DataTypes.INTEGER,
22
+ primaryKey: true,
23
+ autoIncrement: true,
24
+ },
25
+ name: {
26
+ type: DataTypes.ENUM(...Object.values(ROLE_NAME)),
27
+ allowNull: false,
28
+ unique: true,
29
+ },
30
+ },
31
+ {
32
+ sequelize,
33
+ modelName: "Role",
34
+ tableName: "roles",
35
+ timestamps: true,
36
+ createdAt: "created_at",
37
+ updatedAt: "updated_at",
38
+ },
39
+ );
40
+
41
+ Role.removeAttribute("id");
42
+ return Role;
43
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+ const { SELLER_BADGE } = require("../services/constants");
5
+
6
+ module.exports = (sequelize) => {
7
+ class SellerBadge extends Model {
8
+ static associate(models) {
9
+ SellerBadge.belongsTo(models.SellerProfile, {
10
+ foreignKey: "seller_profile_id",
11
+ as: "sellerProfile",
12
+ });
13
+ }
14
+ }
15
+
16
+ SellerBadge.init(
17
+ {
18
+ seller_badge_id: {
19
+ type: DataTypes.INTEGER,
20
+ primaryKey: true,
21
+ autoIncrement: true,
22
+ },
23
+ seller_profile_id: {
24
+ type: DataTypes.INTEGER,
25
+ allowNull: false,
26
+ references: { model: "seller_profiles", key: "seller_profile_id" },
27
+ onDelete: "CASCADE",
28
+ },
29
+ badge: {
30
+ type: DataTypes.ENUM(...Object.values(SELLER_BADGE)),
31
+ allowNull: false,
32
+ },
33
+ },
34
+ {
35
+ sequelize,
36
+ modelName: "SellerBadge",
37
+ tableName: "seller_badges",
38
+ timestamps: true,
39
+ createdAt: "awarded_at",
40
+ updatedAt: false,
41
+ },
42
+ );
43
+
44
+ return SellerBadge;
45
+ };
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+ const {
5
+ SELLER_VERIFICATION_STATUS,
6
+ SELLER_TYPE,
7
+ } = require("../services/constants");
8
+
9
+ module.exports = (sequelize) => {
10
+ class SellerProfile extends Model {
11
+ static associate(models) {
12
+ SellerProfile.belongsTo(models.User, {
13
+ foreignKey: "user_id",
14
+ as: "user",
15
+ });
16
+
17
+ SellerProfile.hasMany(models.SellerBadge, {
18
+ foreignKey: "seller_profile_id",
19
+ as: "badges",
20
+ });
21
+ }
22
+ }
23
+
24
+ SellerProfile.init(
25
+ {
26
+ seller_profile_id: {
27
+ type: DataTypes.INTEGER,
28
+ primaryKey: true,
29
+ autoIncrement: true,
30
+ },
31
+ user_id: {
32
+ type: DataTypes.INTEGER,
33
+ allowNull: false,
34
+ unique: true,
35
+ references: { model: "users", key: "user_id" },
36
+ onDelete: "CASCADE",
37
+ },
38
+ user_type: {
39
+ type: DataTypes.ENUM(...Object.values(SELLER_TYPE)),
40
+ allowNull: false,
41
+ },
42
+ store_name: {
43
+ type: DataTypes.STRING(150),
44
+ allowNull: false,
45
+ },
46
+ store_slug: {
47
+ type: DataTypes.STRING(150),
48
+ allowNull: false,
49
+ unique: true,
50
+ comment: "URL-safe identifier",
51
+ },
52
+ description: {
53
+ type: DataTypes.TEXT,
54
+ allowNull: true,
55
+ },
56
+ logo_url: {
57
+ type: DataTypes.STRING(500),
58
+ allowNull: true,
59
+ comment: "AWS S3 URL",
60
+ },
61
+ avg_rating: {
62
+ type: DataTypes.DECIMAL(3, 2),
63
+ allowNull: true,
64
+ comment: "Computed rolling average",
65
+ },
66
+ total_sales: {
67
+ type: DataTypes.INTEGER,
68
+ defaultValue: 0,
69
+ },
70
+ dispute_count: {
71
+ type: DataTypes.INTEGER,
72
+ defaultValue: 0,
73
+ },
74
+ verification_status: {
75
+ type: DataTypes.ENUM(...Object.values(SELLER_VERIFICATION_STATUS)),
76
+ allowNull: false,
77
+ defaultValue: SELLER_VERIFICATION_STATUS.UNVERIFIED,
78
+ },
79
+ },
80
+ {
81
+ sequelize,
82
+ modelName: "SellerProfile",
83
+ tableName: "seller_profiles",
84
+ timestamps: true,
85
+ createdAt: "created_at",
86
+ updatedAt: "updated_at",
87
+ },
88
+ );
89
+
90
+ SellerProfile.removeAttribute("id");
91
+ return SellerProfile;
92
+ };
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ const { Model, DataTypes } = require("sequelize");
4
+
5
+ module.exports = (sequelize) => {
6
+ class Session extends Model {
7
+ static associate(models) {
8
+ Session.belongsTo(models.User, {
9
+ foreignKey: "user_id",
10
+ as: "user",
11
+ });
12
+
13
+ Session.belongsTo(models.Device, {
14
+ foreignKey: "device_id",
15
+ as: "device",
16
+ });
17
+ }
18
+ }
19
+
20
+ Session.init(
21
+ {
22
+ session_id: {
23
+ type: DataTypes.INTEGER,
24
+ primaryKey: true,
25
+ autoIncrement: true,
26
+ },
27
+ user_id: {
28
+ type: DataTypes.INTEGER,
29
+ allowNull: false,
30
+ references: { model: "users", key: "user_id" },
31
+ onDelete: "CASCADE",
32
+ },
33
+ device_id: {
34
+ type: DataTypes.INTEGER,
35
+ allowNull: true,
36
+ references: { model: "devices", key: "device_id" },
37
+ onDelete: "SET NULL",
38
+ },
39
+ refresh_token: {
40
+ type: DataTypes.TEXT,
41
+ allowNull: false,
42
+ comment: "Hashed before storage",
43
+ },
44
+ expires_at: {
45
+ type: DataTypes.DATE,
46
+ allowNull: false,
47
+ comment: "7 days from issuance",
48
+ },
49
+ revoked: {
50
+ type: DataTypes.BOOLEAN,
51
+ defaultValue: false,
52
+ comment: "Set true on logout",
53
+ },
54
+ },
55
+ {
56
+ sequelize,
57
+ modelName: "Session",
58
+ tableName: "sessions",
59
+ timestamps: true,
60
+ createdAt: "created_at",
61
+ updatedAt: false,
62
+ },
63
+ );
64
+
65
+ Session.removeAttribute("id");
66
+ return Session;
67
+ };