@lead-routing/cli 0.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.
- package/dist/index.js +1916 -0
- package/dist/prisma/migrations/20260101000000_init/migration.sql +276 -0
- package/dist/prisma/migrations/20260223000000_add_routing_log_dismissed/migration.sql +2 -0
- package/dist/prisma/migrations/20260224000000_add_org_notification_webhook/migration.sql +2 -0
- package/dist/prisma/migrations/20260227000000_self_hosted_schema_updates/migration.sql +68 -0
- package/dist/prisma/schema.prisma +315 -0
- package/dist/sfdc-package/force-app/main/default/applications/Lead_Router_Setup.app-meta.xml +12 -0
- package/dist/sfdc-package/force-app/main/default/classes/AccountTriggerTest.cls +58 -0
- package/dist/sfdc-package/force-app/main/default/classes/AccountTriggerTest.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/ContactTriggerTest.cls +62 -0
- package/dist/sfdc-package/force-app/main/default/classes/ContactTriggerTest.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/LeadTriggerTest.cls +95 -0
- package/dist/sfdc-package/force-app/main/default/classes/LeadTriggerTest.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/OnboardingController.cls +183 -0
- package/dist/sfdc-package/force-app/main/default/classes/OnboardingController.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingEngineCallout.cls +96 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingEngineCallout.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingEngineMock.cls +28 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingEngineMock.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingPayloadBuilder.cls +50 -0
- package/dist/sfdc-package/force-app/main/default/classes/RoutingPayloadBuilder.cls-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/lwc/onboardingWizard/onboardingWizard.html +230 -0
- package/dist/sfdc-package/force-app/main/default/lwc/onboardingWizard/onboardingWizard.js +222 -0
- package/dist/sfdc-package/force-app/main/default/lwc/onboardingWizard/onboardingWizard.js-meta.xml +11 -0
- package/dist/sfdc-package/force-app/main/default/namedCredentials/RoutingEngine.namedCredential-meta.xml +10 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Error_Log__c/Routing_Error_Log__c.object-meta.xml +21 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Error_Log__c/fields/Created_At__c.field-meta.xml +6 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Error_Log__c/fields/Payload__c.field-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Error_Log__c/fields/Response_Body__c.field-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Error_Log__c/fields/Status_Code__c.field-meta.xml +9 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/Routing_Settings__c.object-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Account_Insert_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Account_Routing_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Account_Update_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/App_Url__c.field-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Contact_Insert_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Contact_Routing_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Contact_Update_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Engine_Endpoint__c.field-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Lead_Insert_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Lead_Routing_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Lead_Update_Enabled__c.field-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/objects/Routing_Settings__c/fields/Webhook_Secret__c.field-meta.xml +8 -0
- package/dist/sfdc-package/force-app/main/default/permissionsets/LeadRouterAdmin.permissionset-meta.xml +14 -0
- package/dist/sfdc-package/force-app/main/default/remoteSiteSettings/LeadRouterEngine.remoteSite-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/tabs/Lead_Router_Setup.tab-meta.xml +7 -0
- package/dist/sfdc-package/force-app/main/default/triggers/AccountTrigger.trigger +28 -0
- package/dist/sfdc-package/force-app/main/default/triggers/AccountTrigger.trigger-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/triggers/ContactTrigger.trigger +28 -0
- package/dist/sfdc-package/force-app/main/default/triggers/ContactTrigger.trigger-meta.xml +5 -0
- package/dist/sfdc-package/force-app/main/default/triggers/LeadTrigger.trigger +28 -0
- package/dist/sfdc-package/force-app/main/default/triggers/LeadTrigger.trigger-meta.xml +5 -0
- package/dist/sfdc-package/sfdx-project.json +14 -0
- package/package.json +41 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
-- CreateEnum
|
|
2
|
+
CREATE TYPE "SfdcObjectType" AS ENUM ('LEAD', 'CONTACT', 'ACCOUNT');
|
|
3
|
+
|
|
4
|
+
-- CreateEnum
|
|
5
|
+
CREATE TYPE "TriggerEvent" AS ENUM ('INSERT', 'UPDATE', 'BOTH');
|
|
6
|
+
|
|
7
|
+
-- CreateEnum
|
|
8
|
+
CREATE TYPE "RuleStatus" AS ENUM ('ACTIVE', 'INACTIVE');
|
|
9
|
+
|
|
10
|
+
-- CreateEnum
|
|
11
|
+
CREATE TYPE "AssignmentType" AS ENUM ('USER', 'ROUND_ROBIN', 'QUEUE');
|
|
12
|
+
|
|
13
|
+
-- CreateEnum
|
|
14
|
+
CREATE TYPE "TeamMemberStatus" AS ENUM ('ACTIVE', 'PAUSED');
|
|
15
|
+
|
|
16
|
+
-- CreateEnum
|
|
17
|
+
CREATE TYPE "RoutingStatus" AS ENUM ('SUCCESS', 'FAILED', 'UNMATCHED', 'RETRY');
|
|
18
|
+
|
|
19
|
+
-- CreateTable
|
|
20
|
+
CREATE TABLE "organizations" (
|
|
21
|
+
"id" TEXT NOT NULL,
|
|
22
|
+
"sfdcOrgId" TEXT NOT NULL,
|
|
23
|
+
"sfdcInstanceUrl" TEXT NOT NULL,
|
|
24
|
+
"oauthAccessToken" TEXT NOT NULL,
|
|
25
|
+
"oauthRefreshToken" TEXT NOT NULL,
|
|
26
|
+
"webhookSecret" TEXT NOT NULL,
|
|
27
|
+
"seatsPurchased" INTEGER NOT NULL DEFAULT 5,
|
|
28
|
+
"seatsUsed" INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
"onboardingDone" BOOLEAN NOT NULL DEFAULT false,
|
|
30
|
+
"notificationWebhookUrl" TEXT,
|
|
31
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
32
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
33
|
+
|
|
34
|
+
CONSTRAINT "organizations_pkey" PRIMARY KEY ("id")
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
-- CreateTable
|
|
38
|
+
CREATE TABLE "users" (
|
|
39
|
+
"id" TEXT NOT NULL,
|
|
40
|
+
"orgId" TEXT NOT NULL,
|
|
41
|
+
"sfdcUserId" TEXT NOT NULL,
|
|
42
|
+
"name" TEXT NOT NULL,
|
|
43
|
+
"email" TEXT NOT NULL,
|
|
44
|
+
"role" TEXT,
|
|
45
|
+
"profile" TEXT,
|
|
46
|
+
"department" TEXT,
|
|
47
|
+
"isLicensed" BOOLEAN NOT NULL DEFAULT false,
|
|
48
|
+
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
49
|
+
"lastRoutedAt" TIMESTAMP(3),
|
|
50
|
+
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
51
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
52
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
53
|
+
|
|
54
|
+
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
-- CreateTable
|
|
58
|
+
CREATE TABLE "round_robin_teams" (
|
|
59
|
+
"id" TEXT NOT NULL,
|
|
60
|
+
"orgId" TEXT NOT NULL,
|
|
61
|
+
"name" TEXT NOT NULL,
|
|
62
|
+
"description" TEXT,
|
|
63
|
+
"pointerIndex" INTEGER NOT NULL DEFAULT 0,
|
|
64
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
65
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
66
|
+
|
|
67
|
+
CONSTRAINT "round_robin_teams_pkey" PRIMARY KEY ("id")
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
-- CreateTable
|
|
71
|
+
CREATE TABLE "team_members" (
|
|
72
|
+
"id" TEXT NOT NULL,
|
|
73
|
+
"teamId" TEXT NOT NULL,
|
|
74
|
+
"userId" TEXT NOT NULL,
|
|
75
|
+
"status" "TeamMemberStatus" NOT NULL DEFAULT 'ACTIVE',
|
|
76
|
+
"weight" INTEGER NOT NULL DEFAULT 1,
|
|
77
|
+
"assignmentCount" INTEGER NOT NULL DEFAULT 0,
|
|
78
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
79
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
80
|
+
|
|
81
|
+
CONSTRAINT "team_members_pkey" PRIMARY KEY ("id")
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
-- CreateTable
|
|
85
|
+
CREATE TABLE "routing_rules" (
|
|
86
|
+
"id" TEXT NOT NULL,
|
|
87
|
+
"orgId" TEXT NOT NULL,
|
|
88
|
+
"objectType" "SfdcObjectType" NOT NULL,
|
|
89
|
+
"triggerEvent" "TriggerEvent" NOT NULL,
|
|
90
|
+
"name" TEXT NOT NULL,
|
|
91
|
+
"priority" INTEGER NOT NULL,
|
|
92
|
+
"status" "RuleStatus" NOT NULL DEFAULT 'ACTIVE',
|
|
93
|
+
"assignmentType" "AssignmentType" NOT NULL,
|
|
94
|
+
"assigneeUserId" TEXT,
|
|
95
|
+
"assigneeTeamId" TEXT,
|
|
96
|
+
"assigneeQueueId" TEXT,
|
|
97
|
+
"isDryRun" BOOLEAN NOT NULL DEFAULT false,
|
|
98
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
99
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
100
|
+
|
|
101
|
+
CONSTRAINT "routing_rules_pkey" PRIMARY KEY ("id")
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
-- CreateTable
|
|
105
|
+
CREATE TABLE "rule_conditions" (
|
|
106
|
+
"id" TEXT NOT NULL,
|
|
107
|
+
"ruleId" TEXT NOT NULL,
|
|
108
|
+
"groupId" TEXT NOT NULL,
|
|
109
|
+
"fieldName" TEXT NOT NULL,
|
|
110
|
+
"operator" TEXT NOT NULL,
|
|
111
|
+
"value" TEXT,
|
|
112
|
+
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
|
113
|
+
|
|
114
|
+
CONSTRAINT "rule_conditions_pkey" PRIMARY KEY ("id")
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
-- CreateTable
|
|
118
|
+
CREATE TABLE "routing_logs" (
|
|
119
|
+
"id" TEXT NOT NULL,
|
|
120
|
+
"orgId" TEXT NOT NULL,
|
|
121
|
+
"sfdcRecordId" TEXT NOT NULL,
|
|
122
|
+
"objectType" "SfdcObjectType" NOT NULL,
|
|
123
|
+
"eventType" "TriggerEvent" NOT NULL,
|
|
124
|
+
"ruleId" TEXT,
|
|
125
|
+
"ruleName" TEXT,
|
|
126
|
+
"assigneeId" TEXT,
|
|
127
|
+
"assigneeName" TEXT,
|
|
128
|
+
"assignmentType" "AssignmentType",
|
|
129
|
+
"isDryRun" BOOLEAN NOT NULL DEFAULT false,
|
|
130
|
+
"status" "RoutingStatus" NOT NULL,
|
|
131
|
+
"errorMessage" TEXT,
|
|
132
|
+
"retryCount" INTEGER NOT NULL DEFAULT 0,
|
|
133
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
134
|
+
|
|
135
|
+
CONSTRAINT "routing_logs_pkey" PRIMARY KEY ("id")
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
-- CreateTable
|
|
139
|
+
CREATE TABLE "audit_logs" (
|
|
140
|
+
"id" TEXT NOT NULL,
|
|
141
|
+
"orgId" TEXT NOT NULL,
|
|
142
|
+
"actorId" TEXT NOT NULL,
|
|
143
|
+
"actorName" TEXT NOT NULL,
|
|
144
|
+
"action" TEXT NOT NULL,
|
|
145
|
+
"entityType" TEXT NOT NULL,
|
|
146
|
+
"entityId" TEXT NOT NULL,
|
|
147
|
+
"beforeState" JSONB,
|
|
148
|
+
"afterState" JSONB,
|
|
149
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
150
|
+
|
|
151
|
+
CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id")
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
-- CreateTable
|
|
155
|
+
CREATE TABLE "sfdc_queues" (
|
|
156
|
+
"id" TEXT NOT NULL,
|
|
157
|
+
"orgId" TEXT NOT NULL,
|
|
158
|
+
"sfdcQueueId" TEXT NOT NULL,
|
|
159
|
+
"name" TEXT NOT NULL,
|
|
160
|
+
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
161
|
+
|
|
162
|
+
CONSTRAINT "sfdc_queues_pkey" PRIMARY KEY ("id")
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
-- CreateTable
|
|
166
|
+
CREATE TABLE "field_schemas" (
|
|
167
|
+
"id" TEXT NOT NULL,
|
|
168
|
+
"orgId" TEXT NOT NULL,
|
|
169
|
+
"objectType" "SfdcObjectType" NOT NULL,
|
|
170
|
+
"fieldApiName" TEXT NOT NULL,
|
|
171
|
+
"fieldLabel" TEXT NOT NULL,
|
|
172
|
+
"fieldType" TEXT NOT NULL,
|
|
173
|
+
"picklistValues" JSONB,
|
|
174
|
+
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
175
|
+
|
|
176
|
+
CONSTRAINT "field_schemas_pkey" PRIMARY KEY ("id")
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
-- CreateTable
|
|
180
|
+
CREATE TABLE "billing_info" (
|
|
181
|
+
"id" TEXT NOT NULL,
|
|
182
|
+
"orgId" TEXT NOT NULL,
|
|
183
|
+
"entityName" TEXT,
|
|
184
|
+
"gstin" TEXT,
|
|
185
|
+
"addressLine1" TEXT,
|
|
186
|
+
"addressLine2" TEXT,
|
|
187
|
+
"city" TEXT,
|
|
188
|
+
"state" TEXT,
|
|
189
|
+
"pinCode" TEXT,
|
|
190
|
+
"invoiceEmail" TEXT,
|
|
191
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
192
|
+
|
|
193
|
+
CONSTRAINT "billing_info_pkey" PRIMARY KEY ("id")
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
-- CreateTable
|
|
197
|
+
CREATE TABLE "sessions" (
|
|
198
|
+
"id" TEXT NOT NULL,
|
|
199
|
+
"orgId" TEXT NOT NULL,
|
|
200
|
+
"userId" TEXT NOT NULL,
|
|
201
|
+
"userName" TEXT NOT NULL,
|
|
202
|
+
"userEmail" TEXT NOT NULL,
|
|
203
|
+
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
204
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
205
|
+
|
|
206
|
+
CONSTRAINT "sessions_pkey" PRIMARY KEY ("id")
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
-- CreateIndex
|
|
210
|
+
CREATE UNIQUE INDEX "organizations_sfdcOrgId_key" ON "organizations"("sfdcOrgId");
|
|
211
|
+
|
|
212
|
+
-- CreateIndex
|
|
213
|
+
CREATE UNIQUE INDEX "users_orgId_sfdcUserId_key" ON "users"("orgId", "sfdcUserId");
|
|
214
|
+
|
|
215
|
+
-- CreateIndex
|
|
216
|
+
CREATE UNIQUE INDEX "team_members_teamId_userId_key" ON "team_members"("teamId", "userId");
|
|
217
|
+
|
|
218
|
+
-- CreateIndex
|
|
219
|
+
CREATE INDEX "routing_logs_orgId_createdAt_idx" ON "routing_logs"("orgId", "createdAt");
|
|
220
|
+
|
|
221
|
+
-- CreateIndex
|
|
222
|
+
CREATE INDEX "routing_logs_orgId_status_idx" ON "routing_logs"("orgId", "status");
|
|
223
|
+
|
|
224
|
+
-- CreateIndex
|
|
225
|
+
CREATE INDEX "audit_logs_orgId_createdAt_idx" ON "audit_logs"("orgId", "createdAt");
|
|
226
|
+
|
|
227
|
+
-- CreateIndex
|
|
228
|
+
CREATE UNIQUE INDEX "sfdc_queues_orgId_sfdcQueueId_key" ON "sfdc_queues"("orgId", "sfdcQueueId");
|
|
229
|
+
|
|
230
|
+
-- CreateIndex
|
|
231
|
+
CREATE UNIQUE INDEX "field_schemas_orgId_objectType_fieldApiName_key" ON "field_schemas"("orgId", "objectType", "fieldApiName");
|
|
232
|
+
|
|
233
|
+
-- CreateIndex
|
|
234
|
+
CREATE UNIQUE INDEX "billing_info_orgId_key" ON "billing_info"("orgId");
|
|
235
|
+
|
|
236
|
+
-- CreateIndex
|
|
237
|
+
CREATE INDEX "sessions_orgId_idx" ON "sessions"("orgId");
|
|
238
|
+
|
|
239
|
+
-- AddForeignKey
|
|
240
|
+
ALTER TABLE "users" ADD CONSTRAINT "users_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
241
|
+
|
|
242
|
+
-- AddForeignKey
|
|
243
|
+
ALTER TABLE "round_robin_teams" ADD CONSTRAINT "round_robin_teams_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
244
|
+
|
|
245
|
+
-- AddForeignKey
|
|
246
|
+
ALTER TABLE "team_members" ADD CONSTRAINT "team_members_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "round_robin_teams"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
247
|
+
|
|
248
|
+
-- AddForeignKey
|
|
249
|
+
ALTER TABLE "team_members" ADD CONSTRAINT "team_members_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
250
|
+
|
|
251
|
+
-- AddForeignKey
|
|
252
|
+
ALTER TABLE "routing_rules" ADD CONSTRAINT "routing_rules_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
253
|
+
|
|
254
|
+
-- AddForeignKey
|
|
255
|
+
ALTER TABLE "routing_rules" ADD CONSTRAINT "routing_rules_assigneeTeamId_fkey" FOREIGN KEY ("assigneeTeamId") REFERENCES "round_robin_teams"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
256
|
+
|
|
257
|
+
-- AddForeignKey
|
|
258
|
+
ALTER TABLE "routing_rules" ADD CONSTRAINT "routing_rules_assigneeQueueId_fkey" FOREIGN KEY ("assigneeQueueId") REFERENCES "sfdc_queues"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
259
|
+
|
|
260
|
+
-- AddForeignKey
|
|
261
|
+
ALTER TABLE "rule_conditions" ADD CONSTRAINT "rule_conditions_ruleId_fkey" FOREIGN KEY ("ruleId") REFERENCES "routing_rules"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
262
|
+
|
|
263
|
+
-- AddForeignKey
|
|
264
|
+
ALTER TABLE "routing_logs" ADD CONSTRAINT "routing_logs_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
265
|
+
|
|
266
|
+
-- AddForeignKey
|
|
267
|
+
ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
268
|
+
|
|
269
|
+
-- AddForeignKey
|
|
270
|
+
ALTER TABLE "sfdc_queues" ADD CONSTRAINT "sfdc_queues_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
271
|
+
|
|
272
|
+
-- AddForeignKey
|
|
273
|
+
ALTER TABLE "field_schemas" ADD CONSTRAINT "field_schemas_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
274
|
+
|
|
275
|
+
-- AddForeignKey
|
|
276
|
+
ALTER TABLE "billing_info" ADD CONSTRAINT "billing_info_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
-- ============================================================
|
|
2
|
+
-- Self-hosted schema updates
|
|
3
|
+
-- Brings the DB in sync with the current Prisma schema:
|
|
4
|
+
-- 1. Make SFDC credential columns nullable (populated during onboarding)
|
|
5
|
+
-- 2. Add Plan enum + new org columns (plan, isActive, quotas)
|
|
6
|
+
-- 3. Create app_users table (CLI-managed admin users)
|
|
7
|
+
-- 4. Create invites table
|
|
8
|
+
-- 5. Add recordSnapshot to routing_logs
|
|
9
|
+
-- ============================================================
|
|
10
|
+
|
|
11
|
+
-- 1. Make SFDC credential columns nullable
|
|
12
|
+
ALTER TABLE "organizations" ALTER COLUMN "sfdcOrgId" DROP NOT NULL;
|
|
13
|
+
ALTER TABLE "organizations" ALTER COLUMN "sfdcInstanceUrl" DROP NOT NULL;
|
|
14
|
+
ALTER TABLE "organizations" ALTER COLUMN "oauthAccessToken" DROP NOT NULL;
|
|
15
|
+
ALTER TABLE "organizations" ALTER COLUMN "oauthRefreshToken" DROP NOT NULL;
|
|
16
|
+
|
|
17
|
+
-- 2. Plan enum + new org columns
|
|
18
|
+
CREATE TYPE "Plan" AS ENUM ('FREE', 'PAID');
|
|
19
|
+
|
|
20
|
+
ALTER TABLE "organizations"
|
|
21
|
+
ADD COLUMN IF NOT EXISTS "plan" "Plan" NOT NULL DEFAULT 'FREE',
|
|
22
|
+
ADD COLUMN IF NOT EXISTS "isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
23
|
+
ADD COLUMN IF NOT EXISTS "routingQuotaUsed" INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
ADD COLUMN IF NOT EXISTS "quotaResetAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
|
25
|
+
|
|
26
|
+
-- 3. app_users table
|
|
27
|
+
CREATE TABLE "app_users" (
|
|
28
|
+
"id" TEXT NOT NULL,
|
|
29
|
+
"orgId" TEXT NOT NULL,
|
|
30
|
+
"email" TEXT NOT NULL,
|
|
31
|
+
"name" TEXT NOT NULL,
|
|
32
|
+
"passwordHash" TEXT NOT NULL,
|
|
33
|
+
"role" TEXT NOT NULL DEFAULT 'ADMIN',
|
|
34
|
+
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
35
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
36
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
37
|
+
|
|
38
|
+
CONSTRAINT "app_users_pkey" PRIMARY KEY ("id")
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE UNIQUE INDEX "app_users_orgId_email_key" ON "app_users"("orgId", "email");
|
|
42
|
+
|
|
43
|
+
ALTER TABLE "app_users"
|
|
44
|
+
ADD CONSTRAINT "app_users_orgId_fkey"
|
|
45
|
+
FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
46
|
+
|
|
47
|
+
-- 4. invites table
|
|
48
|
+
CREATE TABLE "invites" (
|
|
49
|
+
"id" TEXT NOT NULL,
|
|
50
|
+
"orgId" TEXT NOT NULL,
|
|
51
|
+
"email" TEXT NOT NULL,
|
|
52
|
+
"token" TEXT NOT NULL,
|
|
53
|
+
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
54
|
+
"acceptedAt" TIMESTAMP(3),
|
|
55
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
56
|
+
|
|
57
|
+
CONSTRAINT "invites_pkey" PRIMARY KEY ("id")
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE UNIQUE INDEX "invites_token_key" ON "invites"("token");
|
|
61
|
+
|
|
62
|
+
ALTER TABLE "invites"
|
|
63
|
+
ADD CONSTRAINT "invites_orgId_fkey"
|
|
64
|
+
FOREIGN KEY ("orgId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
65
|
+
|
|
66
|
+
-- 5. recordSnapshot column in routing_logs
|
|
67
|
+
ALTER TABLE "routing_logs"
|
|
68
|
+
ADD COLUMN IF NOT EXISTS "recordSnapshot" JSONB;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
output = "../../../node_modules/.prisma/client"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
datasource db {
|
|
7
|
+
provider = "postgresql"
|
|
8
|
+
url = env("DATABASE_URL")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// ─── Enums ────────────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
enum SfdcObjectType {
|
|
14
|
+
LEAD
|
|
15
|
+
CONTACT
|
|
16
|
+
ACCOUNT
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
enum TriggerEvent {
|
|
20
|
+
INSERT
|
|
21
|
+
UPDATE
|
|
22
|
+
BOTH
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum RuleStatus {
|
|
26
|
+
ACTIVE
|
|
27
|
+
INACTIVE
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
enum AssignmentType {
|
|
31
|
+
USER
|
|
32
|
+
ROUND_ROBIN
|
|
33
|
+
QUEUE
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
enum TeamMemberStatus {
|
|
37
|
+
ACTIVE
|
|
38
|
+
PAUSED
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
enum RoutingStatus {
|
|
42
|
+
SUCCESS
|
|
43
|
+
FAILED
|
|
44
|
+
UNMATCHED
|
|
45
|
+
RETRY
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
enum Plan {
|
|
49
|
+
FREE
|
|
50
|
+
PAID
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ─── Models ───────────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
model Organization {
|
|
56
|
+
id String @id @default(cuid())
|
|
57
|
+
sfdcOrgId String? @unique // null until CRM is connected in onboarding
|
|
58
|
+
sfdcInstanceUrl String? // null until CRM is connected
|
|
59
|
+
oauthAccessToken String? // null until CRM is connected
|
|
60
|
+
oauthRefreshToken String? // null until CRM is connected
|
|
61
|
+
webhookSecret String // HMAC secret for verifying Apex trigger payloads
|
|
62
|
+
plan Plan @default(FREE)
|
|
63
|
+
isActive Boolean @default(true)
|
|
64
|
+
seatsPurchased Int @default(5)
|
|
65
|
+
seatsUsed Int @default(0)
|
|
66
|
+
routingQuotaUsed Int @default(0)
|
|
67
|
+
quotaResetAt DateTime @default(now())
|
|
68
|
+
onboardingDone Boolean @default(false)
|
|
69
|
+
notificationWebhookUrl String?
|
|
70
|
+
createdAt DateTime @default(now())
|
|
71
|
+
updatedAt DateTime @updatedAt
|
|
72
|
+
|
|
73
|
+
users User[]
|
|
74
|
+
appUsers AppUser[]
|
|
75
|
+
invites Invite[]
|
|
76
|
+
teams RoundRobinTeam[]
|
|
77
|
+
routingRules RoutingRule[]
|
|
78
|
+
routingLogs RoutingLog[]
|
|
79
|
+
auditLogs AuditLog[]
|
|
80
|
+
sfdcQueues SfdcQueue[]
|
|
81
|
+
fieldSchemas FieldSchema[]
|
|
82
|
+
billingInfo BillingInfo?
|
|
83
|
+
|
|
84
|
+
@@map("organizations")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
model AppUser {
|
|
88
|
+
id String @id @default(cuid())
|
|
89
|
+
orgId String
|
|
90
|
+
email String
|
|
91
|
+
name String
|
|
92
|
+
passwordHash String // PBKDF2: "salt:hash" (salt=16-byte hex, 310000 iterations, sha256)
|
|
93
|
+
role String @default("ADMIN") // ADMIN | MEMBER
|
|
94
|
+
isActive Boolean @default(true)
|
|
95
|
+
createdAt DateTime @default(now())
|
|
96
|
+
updatedAt DateTime @updatedAt
|
|
97
|
+
|
|
98
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
99
|
+
|
|
100
|
+
@@unique([orgId, email])
|
|
101
|
+
@@map("app_users")
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
model Invite {
|
|
105
|
+
id String @id @default(cuid())
|
|
106
|
+
orgId String
|
|
107
|
+
email String
|
|
108
|
+
token String @unique // 48-char hex (crypto.randomBytes(24))
|
|
109
|
+
expiresAt DateTime // 72 hours from creation
|
|
110
|
+
acceptedAt DateTime? // null until invite is used
|
|
111
|
+
createdAt DateTime @default(now())
|
|
112
|
+
|
|
113
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
114
|
+
|
|
115
|
+
@@map("invites")
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
model User {
|
|
119
|
+
id String @id @default(cuid())
|
|
120
|
+
orgId String
|
|
121
|
+
sfdcUserId String
|
|
122
|
+
name String
|
|
123
|
+
email String
|
|
124
|
+
role String?
|
|
125
|
+
profile String?
|
|
126
|
+
department String?
|
|
127
|
+
isLicensed Boolean @default(false)
|
|
128
|
+
isActive Boolean @default(true) // false if no longer in SFDC
|
|
129
|
+
lastRoutedAt DateTime?
|
|
130
|
+
syncedAt DateTime @default(now())
|
|
131
|
+
createdAt DateTime @default(now())
|
|
132
|
+
updatedAt DateTime @updatedAt
|
|
133
|
+
|
|
134
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
135
|
+
teamMemberships TeamMember[]
|
|
136
|
+
|
|
137
|
+
@@unique([orgId, sfdcUserId])
|
|
138
|
+
@@map("users")
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
model RoundRobinTeam {
|
|
142
|
+
id String @id @default(cuid())
|
|
143
|
+
orgId String
|
|
144
|
+
name String
|
|
145
|
+
description String?
|
|
146
|
+
pointerIndex Int @default(0) // kept in sync with Redis; Redis is authoritative
|
|
147
|
+
createdAt DateTime @default(now())
|
|
148
|
+
updatedAt DateTime @updatedAt
|
|
149
|
+
|
|
150
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
151
|
+
members TeamMember[]
|
|
152
|
+
routingRules RoutingRule[] @relation("TeamRules")
|
|
153
|
+
|
|
154
|
+
@@map("round_robin_teams")
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
model TeamMember {
|
|
158
|
+
id String @id @default(cuid())
|
|
159
|
+
teamId String
|
|
160
|
+
userId String
|
|
161
|
+
status TeamMemberStatus @default(ACTIVE)
|
|
162
|
+
weight Int @default(1) // P2 weighted round robin
|
|
163
|
+
assignmentCount Int @default(0)
|
|
164
|
+
createdAt DateTime @default(now())
|
|
165
|
+
updatedAt DateTime @updatedAt
|
|
166
|
+
|
|
167
|
+
team RoundRobinTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
168
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
169
|
+
|
|
170
|
+
@@unique([teamId, userId])
|
|
171
|
+
@@map("team_members")
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
model RoutingRule {
|
|
175
|
+
id String @id @default(cuid())
|
|
176
|
+
orgId String
|
|
177
|
+
objectType SfdcObjectType
|
|
178
|
+
triggerEvent TriggerEvent
|
|
179
|
+
name String
|
|
180
|
+
priority Int
|
|
181
|
+
status RuleStatus @default(ACTIVE)
|
|
182
|
+
assignmentType AssignmentType
|
|
183
|
+
assigneeUserId String? // references User.id (individual user)
|
|
184
|
+
assigneeTeamId String? // references RoundRobinTeam.id
|
|
185
|
+
assigneeQueueId String? // references SfdcQueue.id
|
|
186
|
+
isDryRun Boolean @default(false)
|
|
187
|
+
createdAt DateTime @default(now())
|
|
188
|
+
updatedAt DateTime @updatedAt
|
|
189
|
+
|
|
190
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
191
|
+
team RoundRobinTeam? @relation("TeamRules", fields: [assigneeTeamId], references: [id])
|
|
192
|
+
queue SfdcQueue? @relation(fields: [assigneeQueueId], references: [id])
|
|
193
|
+
conditions RuleCondition[]
|
|
194
|
+
|
|
195
|
+
@@map("routing_rules")
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
model RuleCondition {
|
|
199
|
+
id String @id @default(cuid())
|
|
200
|
+
ruleId String
|
|
201
|
+
groupId String // conditions in same group share AND logic; groups are joined with OR
|
|
202
|
+
fieldName String // SFDC field API name (e.g., "LeadSource")
|
|
203
|
+
operator String // e.g., "equals", "contains", "gt"
|
|
204
|
+
value String? // null for is_blank / is_not_blank / is_true / is_false
|
|
205
|
+
sortOrder Int @default(0)
|
|
206
|
+
|
|
207
|
+
rule RoutingRule @relation(fields: [ruleId], references: [id], onDelete: Cascade)
|
|
208
|
+
|
|
209
|
+
@@map("rule_conditions")
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
model RoutingLog {
|
|
213
|
+
id String @id @default(cuid())
|
|
214
|
+
orgId String
|
|
215
|
+
sfdcRecordId String
|
|
216
|
+
objectType SfdcObjectType
|
|
217
|
+
eventType TriggerEvent
|
|
218
|
+
ruleId String?
|
|
219
|
+
ruleName String?
|
|
220
|
+
assigneeId String? // SFDC user/queue ID
|
|
221
|
+
assigneeName String?
|
|
222
|
+
assignmentType AssignmentType?
|
|
223
|
+
isDryRun Boolean @default(false)
|
|
224
|
+
status RoutingStatus
|
|
225
|
+
errorMessage String?
|
|
226
|
+
retryCount Int @default(0)
|
|
227
|
+
dismissed Boolean @default(false)
|
|
228
|
+
recordSnapshot Json? // full field payload from SFDC at time of routing
|
|
229
|
+
createdAt DateTime @default(now())
|
|
230
|
+
|
|
231
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
232
|
+
|
|
233
|
+
@@index([orgId, createdAt])
|
|
234
|
+
@@index([orgId, status])
|
|
235
|
+
@@map("routing_logs")
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
model AuditLog {
|
|
239
|
+
id String @id @default(cuid())
|
|
240
|
+
orgId String
|
|
241
|
+
actorId String // User.id
|
|
242
|
+
actorName String
|
|
243
|
+
action String // e.g., "USER_LICENSED", "RULE_CREATED"
|
|
244
|
+
entityType String // e.g., "User", "RoutingRule"
|
|
245
|
+
entityId String
|
|
246
|
+
beforeState Json?
|
|
247
|
+
afterState Json?
|
|
248
|
+
createdAt DateTime @default(now())
|
|
249
|
+
|
|
250
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
251
|
+
|
|
252
|
+
@@index([orgId, createdAt])
|
|
253
|
+
@@map("audit_logs")
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
model SfdcQueue {
|
|
257
|
+
id String @id @default(cuid())
|
|
258
|
+
orgId String
|
|
259
|
+
sfdcQueueId String // SFDC Queue ID (00G...)
|
|
260
|
+
name String
|
|
261
|
+
syncedAt DateTime @default(now())
|
|
262
|
+
|
|
263
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
264
|
+
routingRules RoutingRule[]
|
|
265
|
+
|
|
266
|
+
@@unique([orgId, sfdcQueueId])
|
|
267
|
+
@@map("sfdc_queues")
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
model FieldSchema {
|
|
271
|
+
id String @id @default(cuid())
|
|
272
|
+
orgId String
|
|
273
|
+
objectType SfdcObjectType
|
|
274
|
+
fieldApiName String
|
|
275
|
+
fieldLabel String
|
|
276
|
+
fieldType String // TEXT | NUMBER | DATE | DATETIME | BOOLEAN | PICKLIST | MULTI_PICKLIST | LOOKUP
|
|
277
|
+
picklistValues Json? // string[] for picklist/multi-picklist fields
|
|
278
|
+
syncedAt DateTime @default(now())
|
|
279
|
+
|
|
280
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
281
|
+
|
|
282
|
+
@@unique([orgId, objectType, fieldApiName])
|
|
283
|
+
@@map("field_schemas")
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
model BillingInfo {
|
|
287
|
+
id String @id @default(cuid())
|
|
288
|
+
orgId String @unique
|
|
289
|
+
entityName String?
|
|
290
|
+
gstin String?
|
|
291
|
+
addressLine1 String?
|
|
292
|
+
addressLine2 String?
|
|
293
|
+
city String?
|
|
294
|
+
state String?
|
|
295
|
+
pinCode String?
|
|
296
|
+
invoiceEmail String?
|
|
297
|
+
updatedAt DateTime @updatedAt
|
|
298
|
+
|
|
299
|
+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
|
300
|
+
|
|
301
|
+
@@map("billing_info")
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
model Session {
|
|
305
|
+
id String @id @default(cuid())
|
|
306
|
+
orgId String
|
|
307
|
+
userId String // SFDC User ID of the logged-in admin
|
|
308
|
+
userName String
|
|
309
|
+
userEmail String
|
|
310
|
+
expiresAt DateTime
|
|
311
|
+
createdAt DateTime @default(now())
|
|
312
|
+
|
|
313
|
+
@@index([orgId])
|
|
314
|
+
@@map("sessions")
|
|
315
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
3
|
+
<defaultLandingTab>Lead_Router_Setup</defaultLandingTab>
|
|
4
|
+
<description>Lead Router Setup Wizard</description>
|
|
5
|
+
<formFactors>Large</formFactors>
|
|
6
|
+
<isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>
|
|
7
|
+
<isNavPersonalizationDisabled>true</isNavPersonalizationDisabled>
|
|
8
|
+
<label>Lead Router Setup</label>
|
|
9
|
+
<navType>Standard</navType>
|
|
10
|
+
<tabs>Lead_Router_Setup</tabs>
|
|
11
|
+
<uiType>Lightning</uiType>
|
|
12
|
+
</CustomApplication>
|