@avakado.ai/schemas 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ import { Schema } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+
4
+ const IntegrationSchema = new Schema({
5
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
6
+ metaData: {
7
+ name: String,
8
+ description: String,
9
+ icon: String,
10
+ color: String,
11
+ purpose: Schema.Types.Mixed,
12
+ type: { type: String, enum: ['zoho', 'twilio', 'exotel','tataTele','whatsapp'], required: true },
13
+ },
14
+ secrets: {
15
+ tokenType: String,
16
+ accessToken: String,
17
+ refreshToken: String,
18
+ apiKey: String,
19
+ apiToken: String,
20
+ },
21
+ config: {
22
+ AccountSid: String,
23
+ state: String,
24
+ apiDomainUrl: String,
25
+ domain: String,
26
+ scope: String,
27
+ expiresAt: Date,
28
+ region:String
29
+ },
30
+ accountDetails: Schema.Types.Mixed,
31
+ isActive: { type: Boolean, default: true },
32
+ createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
33
+ }, {
34
+ timestamps: true
35
+ });
36
+ export const Integration = defineModel('Integration', IntegrationSchema, "Integration");
@@ -0,0 +1,119 @@
1
+ import { Schema } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+ const jobStatusEnum = ["scheduled", "active", "completed", "failed", "canceled", "delayed", "waiting", "stalled"];
4
+ const backoff = new Schema({
5
+ type: { type: String, enum: ["exponential", "fixed"], required: true },
6
+ delay_ms: { type: Number, required: true },
7
+ attempts: { max: Number, made: Number, reason: String },
8
+ }, { _id: false })
9
+
10
+ const logEntry = new Schema({
11
+ level: { type: String, enum: ["info", "warn", "error", "debug"], required: true },
12
+ message: String,
13
+ timestamp: { type: Date, default: Date.now },
14
+ data: Schema.Types.Mixed
15
+ }, { _id: false });
16
+ /* ───────────────────────────── Base Job ───────────────────────────── */
17
+ const JobSchema = new Schema({
18
+ name: String,
19
+ campaign: { type: Schema.Types.ObjectId, ref: "Campaign" },
20
+ description: String,
21
+ bullMQJobId: String, // bullmq job id
22
+ status: { type: String, enum: jobStatusEnum, default: 'waiting' },
23
+ priority: Number, // 1 (highest) .. 10 (lowest)
24
+ schedule: {
25
+ type: { type: String, enum: ["once", "cron"], default: "once" },
26
+ run_at: Date, // for one-off
27
+ cron: String, // for recurring
28
+ timezone: String,
29
+ backoff: { type: backoff, default: undefined },
30
+ cancel_requested: { type: Boolean, default: false },
31
+ },
32
+ jobType: { type: String, enum: ["outboundCall"], default: "outboundCall" },
33
+ result_ref: Schema.Types.Mixed,
34
+ error_ref: Schema.Types.Mixed,
35
+ log: [logEntry],
36
+ tags: [String],
37
+ createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
38
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
39
+ }, {
40
+ discriminatorKey: 'jobType', timestamps: true, index: [
41
+ { status: 1, 'schedule.run_at': 1 },
42
+ { business: 1, status: 1 },
43
+ { 'schedule.type': 1, 'schedule.run_at': 1 },
44
+ { bullMQJobId: 1 }
45
+ ]
46
+ });
47
+ // Pre-save middleware for validation
48
+ JobSchema.pre('save', function (next) {
49
+ // Validate schedule based on type
50
+ if (this.schedule.type === 'once' && !this.schedule.run_at) {
51
+ return next(new Error('run_at is required for one-time jobs'));
52
+ }
53
+
54
+ if (this.schedule.type === 'cron' && !this.schedule.cron) {
55
+ return next(new Error('cron expression is required for recurring jobs'));
56
+ }
57
+
58
+ // Validate priority
59
+ if (this.priority < 1 || this.priority > 10) {
60
+ return next(new Error('Priority must be between 1 and 10'));
61
+ }
62
+
63
+ next();
64
+ });
65
+
66
+ // Instance methods
67
+ JobSchema.methods.addLog = function (level, message, data = {}) {
68
+ this.log.push({
69
+ level,
70
+ message,
71
+ data,
72
+ timestamp: new Date()
73
+ });
74
+ return this.save();
75
+ };
76
+ JobSchema.methods.markAsStarted = function () {
77
+ this.status = 'active';
78
+ this.lastExecutedAt = new Date();
79
+ this.executionCount += 1;
80
+ return this.save();
81
+ };
82
+
83
+ JobSchema.methods.markAsCompleted = function (result = null, duration = null) {
84
+ this.status = 'completed';
85
+ this.result_ref = result;
86
+ if (duration) this.actualDuration = duration;
87
+ return this.save();
88
+ };
89
+
90
+ JobSchema.methods.markAsFailed = function (error, duration = null) {
91
+ this.status = 'failed';
92
+ this.error_ref = {
93
+ message: error.message,
94
+ stack: error.stack,
95
+ timestamp: new Date()
96
+ };
97
+ if (duration) this.actualDuration = duration;
98
+ return this.save();
99
+ };
100
+
101
+ // if schedule is updated then trigger sync
102
+
103
+ // channelId, to, agentId, PreContext
104
+
105
+ export const Job = defineModel('Job', JobSchema, 'Job');
106
+ const outboundCallPayload = new Schema({
107
+ channel: { type: Schema.Types.ObjectId, ref: "Channel" },
108
+ agent: { type: Schema.Types.ObjectId, ref: "Agent" },
109
+ to: { type: String, required: true },
110
+ accessToken: { type: String, required: true },
111
+ PreContext: String,
112
+ expectedDuration: Number,
113
+ maxRetries: { type: Number, default: 3 },
114
+ callbackUrl: String,
115
+ cps: Number,
116
+ conversationId: { type: Schema.Types.ObjectId, ref: 'conversation' }
117
+ }, { _id: false })
118
+ /* ───────────────────────────── Outbound Call Job ──────────────────────────── */
119
+ Job.discriminator('outboundCall', new Schema({ payload: outboundCallPayload }, { timestamps: true, discriminatorKey: 'jobType' }));
@@ -0,0 +1,84 @@
1
+ import { Schema } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+ const leadStatusEnum = ["new", "contacted", "qualified", "converted", "lost"];
4
+ const platformEntrySchema = new Schema({
5
+ platform: { type: String, required: true }, // Phone,'Twitter', 'Instagram', 'Whatsapp', etc.
6
+ handle: { type: String, trim: true },
7
+ label: { type: String, trim: true }, // 'work', 'personal', 'brand'
8
+ isPrimary: { type: Boolean, default: false },
9
+ metadata: { type: Schema.Types.Mixed, default: {} }
10
+ }, { _id: false });
11
+ const contactDetailsSchema = new Schema({
12
+ whatsapp: [platformEntrySchema],
13
+ telegram: [platformEntrySchema],
14
+ email: [platformEntrySchema], // multiple emails (work, personal)
15
+ phone: [platformEntrySchema],
16
+ twitter: [platformEntrySchema],
17
+ instagram: [platformEntrySchema],
18
+ facebook: [platformEntrySchema],
19
+ // tiktok: [platformEntrySchema],
20
+ // youtube: [platformEntrySchema],
21
+ // snapchat: [platformEntrySchema],
22
+ // pinterest: [platformEntrySchema],
23
+ // reddit: [platformEntrySchema],
24
+ // threads: [platformEntrySchema],
25
+ // bluesky: [platformEntrySchema],
26
+ // signal: [platformEntrySchema],
27
+ // wechat: [platformEntrySchema],
28
+ // line: [platformEntrySchema],
29
+ // viber: [platformEntrySchema],
30
+ // discord: [platformEntrySchema],
31
+ // slack: [platformEntrySchema],
32
+ // linkedin: [platformEntrySchema],
33
+ // github: [platformEntrySchema],
34
+ // behance: [platformEntrySchema],
35
+ // dribbble: [platformEntrySchema],
36
+ // medium: [platformEntrySchema],
37
+ // substack: [platformEntrySchema],
38
+ // producthunt: [platformEntrySchema]
39
+ }, { _id: false });
40
+ /* ───────────────────────────── Lead ───────────────────────────── */
41
+ const LeadSchema = new Schema({
42
+ template: { type: Schema.Types.ObjectId, ref: 'LeadTemplate' },
43
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses', required: true },
44
+ createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
45
+ //identity
46
+ name: { type: String, trim: true },
47
+ contactDetails: { type: contactDetailsSchema, default: () => ({}) },
48
+ source: String, // Whatsapp-Inbound
49
+ tags: [String],
50
+ //evaluation
51
+ leadScore: { type: Number, default: 0 },
52
+ status: { type: String, enum: leadStatusEnum, default: 'new' },
53
+ notes: { type: [String], trim: true },
54
+ // operations
55
+ lastInteractedAt: Date,
56
+ nextFollowUpAt: Date,
57
+ pendingTasks: Schema.Types.Mixed,
58
+ data: { type: Schema.Types.Mixed, default: () => ({}) },
59
+ }, { timestamps: true });
60
+
61
+ /* ───────────────────────────── Lead Template ───────────────────────────── */
62
+ // const leadTemplateFieldTypeEnum = ["string", "number", "email", "phone", "date", "boolean", "url", "text"];
63
+ // const fieldSchema = new Schema({
64
+ // name: { type: String, required: true, trim: true },
65
+ // type: { type: String, enum: leadTemplateFieldTypeEnum, required: true },
66
+ // required: { type: Boolean, default: false },
67
+ // defaultValue: { type: Schema.Types.Mixed, default: null },
68
+ // validation: { minLength: Number, maxLength: Number, min: Number, max: Number, pattern: String },
69
+ // label: { type: String, required: true },
70
+ // placeholder: { type: String, trim: true },
71
+ // description: { type: String, trim: true }
72
+ // }, { _id: false });
73
+
74
+ const LeadTemplateSchema = new Schema({
75
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses', required: true },
76
+ createdBy: { type: Schema.Types.ObjectId, ref: 'Users', required: true },
77
+ name: { type: String, required: true, trim: true, unique: true },
78
+ description: { type: String, trim: true },
79
+ fields: Schema.Types.Mixed,
80
+ isActive: { type: Boolean, default: true }
81
+ }, { timestamps: true });
82
+
83
+ export const Lead = defineModel('Lead', LeadSchema, 'Leads');
84
+ export const LeadTemplate = defineModel('LeadTemplate', LeadTemplateSchema, 'LeadTemplates');
@@ -0,0 +1,32 @@
1
+ // mongodb schema for all types of logs
2
+ import { Schema } from "mongoose";
3
+ import { defineModel } from "../runtime.js";
4
+ const LogSchema = new Schema({
5
+ user: { type: Schema.Types.ObjectId, ref: 'User' },
6
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
7
+ level: { type: String, enum: ['warn', 'error', 'info', 'debug'] },
8
+ event: { type: String },
9
+ category: { type: String, enum: ['AUTHENTICATION', 'PAYMENT', 'CREDIT', 'SUBSCRIPTION', 'API_ACCESS', 'WEBHOOK', 'ERROR', 'OTHER',] },
10
+ status: { type: String, enum: ['SUCCESS', 'FAILURE', 'PENDING'], default: 'SUCCESS', },
11
+ message: String,
12
+ service: { type: String }, // Identifies which microservice or backend component produced the log
13
+ environment: { type: String, enum: ['dev', 'staging', 'prod'] },
14
+ requestId: String,
15
+ meta: Schema.Types.Mixed, // ipAddress, userAgent, etc.
16
+ data: Schema.Types.Mixed,
17
+ error: Schema.Types.Mixed,
18
+ response: Schema.Types.Mixed,
19
+ }, {
20
+ timestamps: true
21
+ });
22
+ // add index to the log schema
23
+ LogSchema.index({ user: 1, createdAt: -1 });
24
+ LogSchema.index({ event: 1, createdAt: -1 });
25
+ LogSchema.index({ category: 1, createdAt: -1 });
26
+ LogSchema.index({ status: 1, createdAt: -1 });
27
+ LogSchema.index({ service: 1, createdAt: -1 });
28
+ LogSchema.index({ environment: 1, createdAt: -1 });
29
+ LogSchema.index({ requestId: 1, createdAt: -1 });
30
+ LogSchema.index({ createdAt: 1 }, { expireAfterSeconds: 60 * 60 * 24 * 30 }); // 30 days
31
+ LogSchema.index({ 'data.platformMessageId': 1 }, { unique: true, sparse: true });
32
+ export const Log = defineModel('Log', LogSchema, 'Logs');
@@ -0,0 +1,46 @@
1
+ import { Schema } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+ const MessageSessionSchema = new Schema({
4
+ campaign: { type: Schema.Types.ObjectId, ref: 'Campaign' },
5
+ firstMessage: { type: Schema.Types.ObjectId, ref: 'Message' },
6
+ lastMessage: { type: Schema.Types.ObjectId, ref: 'Message' },
7
+ conversation: { type: Schema.Types.ObjectId, ref: 'Conversation' },
8
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
9
+ })
10
+ const MessagesSchema = new Schema({
11
+ conversation: { type: Schema.Types.ObjectId, ref: 'Conversation' },
12
+ campaign: { type: Schema.Types.ObjectId, ref: 'Campaign' },
13
+ business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
14
+ externalMessageId: String,
15
+ direction: String,
16
+ sender: {
17
+ type: { type: String, enum: ["Lead", "agent", "user", "system", "unknown"], default: "Lead" },
18
+ id: String,
19
+ name: String,
20
+ ref: { type: Schema.Types.ObjectId, refPath: "sender.refModel" },
21
+ refModel: { type: String, enum: ["Lead", "Agent", "Users"] },
22
+ },
23
+ type: {
24
+ type: String,
25
+ enum: ["text", "image", "audio", "voice", "video", "document", "file", "sticker",
26
+ "location", "contacts", "interactive", "button", "order", "unknown", "template"],
27
+ default: "text",
28
+ },
29
+ kind: { type: String, enum: ["message", "postback", "system"], default: "message" },
30
+ content: { type: Schema.Types.Mixed, default: {} }, // { body } | location | interactive | …
31
+ repliedTo: { type: Schema.Types.ObjectId, ref: "Message" },
32
+ reactions: { type: [{ emoji: String, by: String, at: Date }], default: [], _id: false },
33
+ statusTimeline: {
34
+ scheduled: Date, initiated: Date, sent: Date, delivered: Date, read: Date, failed: Date, stopped: Date
35
+ },
36
+ usage: { type: Schema.Types.Mixed, default: {} },
37
+ misc: { type: Schema.Types.Mixed, default: {} },
38
+ errors: [{ type: Schema.Types.Mixed, default: [] }],
39
+ isInternalNote: { type: Boolean, default: false },
40
+ isSummarized: { type: Boolean, default: false },
41
+ // readByContact: { type: Boolean, default: We false }
42
+ }, {
43
+ timestamps: true
44
+ });
45
+ export const Message = defineModel('Message', MessagesSchema, "Messages");
46
+ export const MessageSession = defineModel('MessageSession', MessageSessionSchema, "MessageSessions");
@@ -0,0 +1,37 @@
1
+ import { Schema } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+ // const CreditSchema = new Schema(
4
+ // {
5
+ // llm: { type: , min: 0, default: 0 },
6
+ // knowledge: { type: Number, min: 0, default: 0 },
7
+ // miscellaneous: { type: Number, min: 0, default: 0 },
8
+ // },
9
+ // { _id: false }
10
+ // );
11
+ const AmountSchema = new Schema({
12
+ value: { type: Number, required: true }, // eg: 22000
13
+ currency: { type: String, default: "INR" }
14
+ }, { _id: false });
15
+ const PlanSchema = new Schema({
16
+ business: { type: Schema.Types.ObjectId, ref: "Businesses" },
17
+ code: { type: String, unique: true }, // ['FREE', 'BASE', 'GROWTH', 'BASE_TOPUP', 'GROWTH_TOPUP'],
18
+ public: { type: Boolean, default: false },
19
+ name: { type: String, required: true },
20
+ description: String,
21
+ amount: AmountSchema,
22
+ type: { type: String, enum: ['FREE', 'BASE', 'TOPUP', 'ENTERPRISE', 'TEST'], required: true, index: true, },
23
+ validity: { type: Number, default: 30 },// in days
24
+ credits: Number,
25
+ spendRatio: { type: Number, enum: [1080, 1666, 1583], default: 1583 },
26
+ status: { type: String, enum: ['active', 'inactive'], default: 'active' },
27
+ features: [String],
28
+ allowedTopUps: [{ type: Schema.Types.ObjectId, ref: 'Plans' }],
29
+ autoRenew: { type: Boolean, default: false },
30
+ paymentGateWay: {
31
+ razorpay: {
32
+ plan_id: String,
33
+ }
34
+ },
35
+ }, { timestamps: true });
36
+ export const Plan = defineModel('Plans', PlanSchema, "Plans");
37
+
@@ -0,0 +1,50 @@
1
+ import { Schema, Types } from "mongoose";
2
+ import { defineModel } from "../runtime.js";
3
+ import { Notification } from "./notifications.js";
4
+
5
+ const TicketSchema = new Schema(
6
+ {
7
+ business: { type: Types.ObjectId, ref: 'Businesses' },
8
+ issueSummary: { type: String, required: true },
9
+ channel: { type: String, enum: ['telegram', 'whatsapp', 'web', 'phone', 'instagram', 'sms', 'email'], required: true, },
10
+ priority: { type: String, enum: ['low', 'medium', 'high'], default: 'medium', },
11
+ status: { type: String, enum: ['pending', 'responded', 'resolved'], default: 'pending' },
12
+ contactDetails: {
13
+ email: { type: String },
14
+ phone: { type: String },
15
+ telegramId: { type: String },
16
+ whatsappId: { type: String },
17
+ instagramId: { type: String },
18
+ },
19
+ notifierEmail: { type: String, required: true },
20
+ response: {
21
+ channelId: { type: Schema.Types.ObjectId, ref: "Channel" },
22
+ from: { type: String },
23
+ to: { type: String },
24
+ cc: { type: String },
25
+ subject: { type: String },
26
+ bcc: { type: String },
27
+ text: { type: String },
28
+ html: { type: String },
29
+ updatedAt: { type: Date },
30
+ sentAt: { type: Date },
31
+ resolvedAt: { type: Date },
32
+ },
33
+ },
34
+ { timestamps: true }
35
+ );
36
+ TicketSchema.methods.markSent = function (response) {
37
+ this.status = 'responded';
38
+ this.response = response;
39
+ return this.save();
40
+ };
41
+ TicketSchema.methods.markResolved = function () {
42
+ this.status = 'resolved';
43
+ this.response.resolvedAt = new Date();
44
+ return this.save();
45
+ };
46
+ // on ticket creation, create a notification
47
+ TicketSchema.post('save', async function (doc) {
48
+ if (this.isNew) await Notification.create({ business: doc.business, head: `${doc.priority} Priority Ticket Created on ${doc.channel}`, body: doc.issueSummary, type: "ticket", attachments: { ticketId: doc._id } });
49
+ });
50
+ export const Ticket = defineModel('Ticket', TicketSchema, 'Ticket');