create-crm-tmp 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.
- package/bin/create-crm-tmp.js +93 -0
- package/package.json +25 -0
- package/template/.prettierignore +33 -0
- package/template/.prettierrc.json +25 -0
- package/template/README.md +173 -0
- package/template/eslint.config.mjs +18 -0
- package/template/exemple-contacts.csv +11 -0
- package/template/next.config.ts +8 -0
- package/template/package.json +64 -0
- package/template/postcss.config.mjs +7 -0
- package/template/prisma/migrations/20251126144728_init/migration.sql +78 -0
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +5 -0
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +19 -0
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +22 -0
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +23 -0
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +75 -0
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +2 -0
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +45 -0
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +2 -0
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +27 -0
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +20 -0
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +18 -0
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +32 -0
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +20 -0
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +12 -0
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +21 -0
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +11 -0
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +12 -0
- package/template/prisma/migrations/20251208094843_mg/migration.sql +14 -0
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +14 -0
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +26 -0
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +2 -0
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +2 -0
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +3 -0
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +21 -0
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +2 -0
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +10 -0
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +26 -0
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +24 -0
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +11 -0
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +12 -0
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +25 -0
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +8 -0
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +2 -0
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +80 -0
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +32 -0
- package/template/prisma/migrations/migration_lock.toml +3 -0
- package/template/prisma/schema.prisma +582 -0
- package/template/prisma.config.ts +14 -0
- package/template/src/app/(auth)/invite/[token]/page.tsx +200 -0
- package/template/src/app/(auth)/layout.tsx +3 -0
- package/template/src/app/(auth)/reset-password/complete/page.tsx +213 -0
- package/template/src/app/(auth)/reset-password/page.tsx +146 -0
- package/template/src/app/(auth)/reset-password/verify/page.tsx +183 -0
- package/template/src/app/(auth)/signin/page.tsx +166 -0
- package/template/src/app/(dashboard)/agenda/page.tsx +3051 -0
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +24 -0
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +905 -0
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +20 -0
- package/template/src/app/(dashboard)/automatisation/page.tsx +337 -0
- package/template/src/app/(dashboard)/closing/page.tsx +1052 -0
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6028 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +3713 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +186 -0
- package/template/src/app/(dashboard)/layout.tsx +30 -0
- package/template/src/app/(dashboard)/settings/page.tsx +4070 -0
- package/template/src/app/(dashboard)/templates/page.tsx +567 -0
- package/template/src/app/(dashboard)/users/list/page.tsx +507 -0
- package/template/src/app/(dashboard)/users/page.tsx +457 -0
- package/template/src/app/(dashboard)/users/permissions/page.tsx +181 -0
- package/template/src/app/(dashboard)/users/roles/page.tsx +434 -0
- package/template/src/app/api/audit-logs/route.ts +57 -0
- package/template/src/app/api/auth/[...all]/route.ts +4 -0
- package/template/src/app/api/auth/check-active/route.ts +31 -0
- package/template/src/app/api/auth/google/callback/route.ts +94 -0
- package/template/src/app/api/auth/google/disconnect/route.ts +32 -0
- package/template/src/app/api/auth/google/route.ts +34 -0
- package/template/src/app/api/auth/google/status/route.ts +32 -0
- package/template/src/app/api/closing-reasons/route.ts +27 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +94 -0
- package/template/src/app/api/contacts/[id]/files/route.ts +269 -0
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +91 -0
- package/template/src/app/api/contacts/[id]/interactions/route.ts +103 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +296 -0
- package/template/src/app/api/contacts/[id]/route.ts +322 -0
- package/template/src/app/api/contacts/[id]/send-email/route.ts +254 -0
- package/template/src/app/api/contacts/export/route.ts +270 -0
- package/template/src/app/api/contacts/import/route.ts +381 -0
- package/template/src/app/api/contacts/route.ts +283 -0
- package/template/src/app/api/dashboard/stats/route.ts +299 -0
- package/template/src/app/api/email/track/[id]/route.ts +68 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +526 -0
- package/template/src/app/api/invite/complete/route.ts +88 -0
- package/template/src/app/api/invite/validate/route.ts +55 -0
- package/template/src/app/api/reminders/route.ts +95 -0
- package/template/src/app/api/reset-password/complete/route.ts +73 -0
- package/template/src/app/api/reset-password/request/route.ts +84 -0
- package/template/src/app/api/reset-password/validate/route.ts +49 -0
- package/template/src/app/api/reset-password/verify/route.ts +74 -0
- package/template/src/app/api/roles/[id]/route.ts +183 -0
- package/template/src/app/api/roles/route.ts +140 -0
- package/template/src/app/api/send/route.ts +282 -0
- package/template/src/app/api/settings/change-password/route.ts +95 -0
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +84 -0
- package/template/src/app/api/settings/closing-reasons/route.ts +74 -0
- package/template/src/app/api/settings/company/route.ts +121 -0
- package/template/src/app/api/settings/google-ads/[id]/route.ts +117 -0
- package/template/src/app/api/settings/google-ads/route.ts +122 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +230 -0
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +196 -0
- package/template/src/app/api/settings/google-sheet/route.ts +254 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +123 -0
- package/template/src/app/api/settings/meta-leads/route.ts +132 -0
- package/template/src/app/api/settings/profile/route.ts +42 -0
- package/template/src/app/api/settings/smtp/route.ts +130 -0
- package/template/src/app/api/settings/smtp/test/route.ts +121 -0
- package/template/src/app/api/settings/statuses/[id]/route.ts +101 -0
- package/template/src/app/api/settings/statuses/route.ts +83 -0
- package/template/src/app/api/statuses/route.ts +25 -0
- package/template/src/app/api/tasks/[id]/attendees/route.ts +76 -0
- package/template/src/app/api/tasks/[id]/route.ts +728 -0
- package/template/src/app/api/tasks/meet/route.ts +240 -0
- package/template/src/app/api/tasks/route.ts +417 -0
- package/template/src/app/api/templates/[id]/route.ts +140 -0
- package/template/src/app/api/templates/route.ts +91 -0
- package/template/src/app/api/users/[id]/route.ts +168 -0
- package/template/src/app/api/users/list/route.ts +45 -0
- package/template/src/app/api/users/me/route.ts +48 -0
- package/template/src/app/api/users/route.ts +250 -0
- package/template/src/app/api/webhooks/google-ads/route.ts +208 -0
- package/template/src/app/api/webhooks/meta-leads/route.ts +258 -0
- package/template/src/app/api/workflows/[id]/route.ts +192 -0
- package/template/src/app/api/workflows/process/route.ts +293 -0
- package/template/src/app/api/workflows/route.ts +124 -0
- package/template/src/app/favicon.ico +0 -0
- package/template/src/app/globals.css +1416 -0
- package/template/src/app/layout.tsx +31 -0
- package/template/src/app/page.tsx +32 -0
- package/template/src/components/dashboard/activity-chart.tsx +67 -0
- package/template/src/components/dashboard/contacts-chart.tsx +63 -0
- package/template/src/components/dashboard/recent-activity.tsx +164 -0
- package/template/src/components/dashboard/sales-analytics-chart.tsx +81 -0
- package/template/src/components/dashboard/stat-card.tsx +61 -0
- package/template/src/components/dashboard/status-distribution-chart.tsx +45 -0
- package/template/src/components/dashboard/tasks-pie-chart.tsx +88 -0
- package/template/src/components/dashboard/top-contacts-list.tsx +129 -0
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +126 -0
- package/template/src/components/editor.tsx +856 -0
- package/template/src/components/email-template.tsx +35 -0
- package/template/src/components/header.tsx +320 -0
- package/template/src/components/invitation-email-template.tsx +79 -0
- package/template/src/components/meet-cancellation-email-template.tsx +120 -0
- package/template/src/components/meet-confirmation-email-template.tsx +156 -0
- package/template/src/components/meet-update-email-template.tsx +209 -0
- package/template/src/components/page-header.tsx +61 -0
- package/template/src/components/reset-password-email-template.tsx +79 -0
- package/template/src/components/sidebar.tsx +294 -0
- package/template/src/components/skeleton.tsx +380 -0
- package/template/src/components/ui/commands.tsx +396 -0
- package/template/src/components/ui/components.tsx +150 -0
- package/template/src/components/ui/theme.tsx +5 -0
- package/template/src/components/view-as-banner.tsx +45 -0
- package/template/src/components/view-as-modal.tsx +186 -0
- package/template/src/contexts/mobile-menu-context.tsx +31 -0
- package/template/src/contexts/sidebar-context.tsx +107 -0
- package/template/src/contexts/task-reminder-context.tsx +239 -0
- package/template/src/contexts/view-as-context.tsx +84 -0
- package/template/src/hooks/use-user-role.ts +82 -0
- package/template/src/lib/audit-log.ts +45 -0
- package/template/src/lib/auth-client.ts +16 -0
- package/template/src/lib/auth.ts +35 -0
- package/template/src/lib/check-permission.ts +193 -0
- package/template/src/lib/contact-duplicate.ts +112 -0
- package/template/src/lib/contact-interactions.ts +371 -0
- package/template/src/lib/encryption.ts +99 -0
- package/template/src/lib/google-calendar.ts +300 -0
- package/template/src/lib/google-drive.ts +372 -0
- package/template/src/lib/permissions.ts +412 -0
- package/template/src/lib/prisma.ts +32 -0
- package/template/src/lib/roles.ts +120 -0
- package/template/src/lib/template-variables.ts +76 -0
- package/template/src/lib/utils.ts +46 -0
- package/template/src/lib/workflow-executor.ts +482 -0
- package/template/src/proxy.ts +91 -0
- package/template/tsconfig.json +34 -0
- package/template/vercel.json +8 -0
package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "scheduled_workflow_action" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"workflowId" TEXT NOT NULL,
|
|
5
|
+
"actionId" TEXT,
|
|
6
|
+
"contactId" TEXT NOT NULL,
|
|
7
|
+
"actionType" TEXT NOT NULL,
|
|
8
|
+
"actionData" JSONB NOT NULL,
|
|
9
|
+
"executeAt" TIMESTAMP(3) NOT NULL,
|
|
10
|
+
"executed" BOOLEAN NOT NULL DEFAULT false,
|
|
11
|
+
"executedAt" TIMESTAMP(3),
|
|
12
|
+
"error" TEXT,
|
|
13
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
14
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
15
|
+
|
|
16
|
+
CONSTRAINT "scheduled_workflow_action_pkey" PRIMARY KEY ("id")
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- CreateIndex
|
|
20
|
+
CREATE INDEX "scheduled_workflow_action_executeAt_executed_idx" ON "scheduled_workflow_action"("executeAt", "executed");
|
|
21
|
+
|
|
22
|
+
-- CreateIndex
|
|
23
|
+
CREATE INDEX "scheduled_workflow_action_contactId_idx" ON "scheduled_workflow_action"("contactId");
|
|
24
|
+
|
|
25
|
+
-- CreateIndex
|
|
26
|
+
CREATE INDEX "scheduled_workflow_action_workflowId_idx" ON "scheduled_workflow_action"("workflowId");
|
|
27
|
+
|
|
28
|
+
-- AddForeignKey
|
|
29
|
+
ALTER TABLE "scheduled_workflow_action" ADD CONSTRAINT "scheduled_workflow_action_workflowId_fkey" FOREIGN KEY ("workflowId") REFERENCES "workflow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
30
|
+
|
|
31
|
+
-- AddForeignKey
|
|
32
|
+
ALTER TABLE "scheduled_workflow_action" ADD CONSTRAINT "scheduled_workflow_action_contactId_fkey" FOREIGN KEY ("contactId") REFERENCES "contact"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
// This is your Prisma schema file,
|
|
2
|
+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
3
|
+
|
|
4
|
+
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
5
|
+
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
6
|
+
|
|
7
|
+
generator client {
|
|
8
|
+
provider = "prisma-client"
|
|
9
|
+
output = "../generated/prisma"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
datasource db {
|
|
13
|
+
provider = "postgresql"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
enum Role {
|
|
17
|
+
USER
|
|
18
|
+
ADMIN
|
|
19
|
+
MANAGER
|
|
20
|
+
COMMERCIAL
|
|
21
|
+
TELEPRO
|
|
22
|
+
COMPTABLE
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
model CustomRole {
|
|
26
|
+
id String @id @default(cuid())
|
|
27
|
+
name String @unique
|
|
28
|
+
description String?
|
|
29
|
+
permissions Json // Tableau de codes de permissions
|
|
30
|
+
isSystem Boolean @default(false) // Profils système non modifiables
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
users User[]
|
|
34
|
+
|
|
35
|
+
@@map("custom_role")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
model User {
|
|
39
|
+
id String @id
|
|
40
|
+
name String
|
|
41
|
+
email String
|
|
42
|
+
emailVerified Boolean @default(false)
|
|
43
|
+
active Boolean @default(true)
|
|
44
|
+
image String?
|
|
45
|
+
role Role @default(USER)
|
|
46
|
+
customRoleId String? // Profil personnalisé optionnel
|
|
47
|
+
customRole CustomRole? @relation(fields: [customRoleId], references: [id], onDelete: SetNull)
|
|
48
|
+
createdAt DateTime @default(now())
|
|
49
|
+
updatedAt DateTime @updatedAt
|
|
50
|
+
sessions Session[]
|
|
51
|
+
accounts Account[]
|
|
52
|
+
smtpConfig SmtpConfig?
|
|
53
|
+
contactsCreated Contact[] @relation("ContactCreatedBy")
|
|
54
|
+
contactsAssignedAsCommercial Contact[] @relation("ContactAssignedCommercial")
|
|
55
|
+
contactsAssignedAsTelepro Contact[] @relation("ContactAssignedTelepro")
|
|
56
|
+
interactions Interaction[]
|
|
57
|
+
tasksAssigned Task[] @relation("TaskAssignedTo")
|
|
58
|
+
tasksCreated Task[] @relation("TaskCreatedBy")
|
|
59
|
+
googleAccount UserGoogleAccount?
|
|
60
|
+
metaLeadConfigs MetaLeadConfig[]
|
|
61
|
+
googleAdsLeadConfigs GoogleAdsLeadConfig[]
|
|
62
|
+
googleSheetSyncConfigsOwned GoogleSheetSyncConfig[] @relation("GoogleSheetOwner")
|
|
63
|
+
googleSheetSyncConfigsAssigned GoogleSheetSyncConfig[] @relation("GoogleSheetAssignedUser")
|
|
64
|
+
templates Template[] @relation("TemplateCreatedBy")
|
|
65
|
+
filesUploaded ContactFile[] @relation("ContactFileUploadedBy")
|
|
66
|
+
auditLogsAsActor AuditLog[] @relation("AuditActor")
|
|
67
|
+
auditLogsAsTargetUser AuditLog[] @relation("AuditTargetUser")
|
|
68
|
+
workflows Workflow[] @relation("WorkflowOwner")
|
|
69
|
+
|
|
70
|
+
@@unique([email])
|
|
71
|
+
@@index([customRoleId])
|
|
72
|
+
@@map("user")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
model AuditLog {
|
|
76
|
+
id String @id @default(cuid())
|
|
77
|
+
actorId String?
|
|
78
|
+
actor User? @relation("AuditActor", fields: [actorId], references: [id], onDelete: SetNull)
|
|
79
|
+
targetUserId String?
|
|
80
|
+
targetUser User? @relation("AuditTargetUser", fields: [targetUserId], references: [id], onDelete: SetNull)
|
|
81
|
+
action String
|
|
82
|
+
entityType String
|
|
83
|
+
entityId String?
|
|
84
|
+
metadata Json?
|
|
85
|
+
createdAt DateTime @default(now())
|
|
86
|
+
|
|
87
|
+
@@index([entityType, entityId])
|
|
88
|
+
@@index([createdAt])
|
|
89
|
+
@@map("audit_log")
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
model Session {
|
|
93
|
+
id String @id
|
|
94
|
+
expiresAt DateTime
|
|
95
|
+
token String
|
|
96
|
+
createdAt DateTime @default(now())
|
|
97
|
+
updatedAt DateTime @updatedAt
|
|
98
|
+
ipAddress String?
|
|
99
|
+
userAgent String?
|
|
100
|
+
userId String
|
|
101
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
102
|
+
|
|
103
|
+
@@unique([token])
|
|
104
|
+
@@index([userId])
|
|
105
|
+
@@map("session")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
model Account {
|
|
109
|
+
id String @id
|
|
110
|
+
accountId String
|
|
111
|
+
providerId String
|
|
112
|
+
userId String
|
|
113
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
114
|
+
accessToken String?
|
|
115
|
+
refreshToken String?
|
|
116
|
+
idToken String?
|
|
117
|
+
accessTokenExpiresAt DateTime?
|
|
118
|
+
refreshTokenExpiresAt DateTime?
|
|
119
|
+
scope String?
|
|
120
|
+
password String?
|
|
121
|
+
createdAt DateTime @default(now())
|
|
122
|
+
updatedAt DateTime @updatedAt
|
|
123
|
+
|
|
124
|
+
@@index([userId])
|
|
125
|
+
@@map("account")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
model Verification {
|
|
129
|
+
id String @id
|
|
130
|
+
identifier String
|
|
131
|
+
value String
|
|
132
|
+
expiresAt DateTime
|
|
133
|
+
createdAt DateTime @default(now())
|
|
134
|
+
updatedAt DateTime @updatedAt
|
|
135
|
+
|
|
136
|
+
@@index([identifier])
|
|
137
|
+
@@map("verification")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
model Company {
|
|
141
|
+
id String @id @default("company")
|
|
142
|
+
name String?
|
|
143
|
+
address String?
|
|
144
|
+
city String?
|
|
145
|
+
postalCode String?
|
|
146
|
+
country String?
|
|
147
|
+
phone String?
|
|
148
|
+
email String?
|
|
149
|
+
website String?
|
|
150
|
+
siret String?
|
|
151
|
+
vatNumber String?
|
|
152
|
+
logo String?
|
|
153
|
+
createdAt DateTime @default(now())
|
|
154
|
+
updatedAt DateTime @updatedAt
|
|
155
|
+
|
|
156
|
+
@@map("company")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
model SmtpConfig {
|
|
160
|
+
id String @id @default(cuid())
|
|
161
|
+
userId String @unique
|
|
162
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
163
|
+
host String
|
|
164
|
+
port Int
|
|
165
|
+
secure Boolean @default(false)
|
|
166
|
+
username String
|
|
167
|
+
password String
|
|
168
|
+
fromEmail String
|
|
169
|
+
fromName String?
|
|
170
|
+
signature String?
|
|
171
|
+
createdAt DateTime @default(now())
|
|
172
|
+
updatedAt DateTime @updatedAt
|
|
173
|
+
|
|
174
|
+
@@map("smtp_config")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
model Status {
|
|
178
|
+
id String @id @default(cuid())
|
|
179
|
+
name String
|
|
180
|
+
color String // Couleur au format hexadécimal (ex: #3B82F6)
|
|
181
|
+
order Int @default(0) // Ordre d'affichage
|
|
182
|
+
createdAt DateTime @default(now())
|
|
183
|
+
updatedAt DateTime @updatedAt
|
|
184
|
+
contacts Contact[]
|
|
185
|
+
metaLeadConfigs MetaLeadConfig[]
|
|
186
|
+
googleAdsLeadConfigs GoogleAdsLeadConfig[]
|
|
187
|
+
googleSheetSyncConfigs GoogleSheetSyncConfig[]
|
|
188
|
+
workflowTriggerFromStatus Workflow[] @relation("WorkflowTriggerFromStatus")
|
|
189
|
+
workflowTriggerToStatus Workflow[] @relation("WorkflowTriggerToStatus")
|
|
190
|
+
workflowActionNewStatus WorkflowAction[] @relation("WorkflowActionNewStatus")
|
|
191
|
+
workflowActionConditionStatus WorkflowAction[] @relation("WorkflowActionConditionStatus")
|
|
192
|
+
|
|
193
|
+
@@unique([name])
|
|
194
|
+
@@map("status")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
enum Civility {
|
|
198
|
+
M
|
|
199
|
+
MME
|
|
200
|
+
MLLE
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
enum InteractionType {
|
|
204
|
+
CALL
|
|
205
|
+
SMS
|
|
206
|
+
EMAIL
|
|
207
|
+
MEETING
|
|
208
|
+
NOTE
|
|
209
|
+
STATUS_CHANGE
|
|
210
|
+
CONTACT_UPDATE
|
|
211
|
+
APPOINTMENT_CREATED
|
|
212
|
+
APPOINTMENT_DELETED
|
|
213
|
+
APPOINTMENT_CHANGED
|
|
214
|
+
ASSIGNMENT_CHANGE
|
|
215
|
+
FILE_UPLOADED
|
|
216
|
+
FILE_REPLACED
|
|
217
|
+
FILE_DELETED
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
enum TaskType {
|
|
221
|
+
CALL
|
|
222
|
+
MEETING
|
|
223
|
+
EMAIL
|
|
224
|
+
VIDEO_CONFERENCE
|
|
225
|
+
OTHER
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
enum TaskPriority {
|
|
229
|
+
LOW
|
|
230
|
+
MEDIUM
|
|
231
|
+
HIGH
|
|
232
|
+
URGENT
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
model Contact {
|
|
236
|
+
id String @id @default(cuid())
|
|
237
|
+
civility Civility?
|
|
238
|
+
firstName String?
|
|
239
|
+
lastName String?
|
|
240
|
+
phone String // Obligatoire
|
|
241
|
+
secondaryPhone String?
|
|
242
|
+
email String?
|
|
243
|
+
address String?
|
|
244
|
+
city String?
|
|
245
|
+
postalCode String?
|
|
246
|
+
origin String? // Origine du contact
|
|
247
|
+
companyName String? // Nom de l'entreprise (texte brut)
|
|
248
|
+
isCompany Boolean @default(false) // Indique si le contact est une entreprise
|
|
249
|
+
companyId String? // ID de l'entreprise à laquelle ce contact est lié
|
|
250
|
+
companyRelation Contact? @relation("ContactCompany", fields: [companyId], references: [id], onDelete: SetNull)
|
|
251
|
+
contacts Contact[] @relation("ContactCompany") // Contacts liés à cette entreprise (via companyId)
|
|
252
|
+
statusId String?
|
|
253
|
+
status Status? @relation(fields: [statusId], references: [id], onDelete: SetNull)
|
|
254
|
+
closingReason String? // Motif de fermeture (si statut Fermé)
|
|
255
|
+
assignedCommercialId String? // Commercial assigné
|
|
256
|
+
assignedCommercial User? @relation("ContactAssignedCommercial", fields: [assignedCommercialId], references: [id], onDelete: SetNull)
|
|
257
|
+
assignedTeleproId String? // Télépro assigné
|
|
258
|
+
assignedTelepro User? @relation("ContactAssignedTelepro", fields: [assignedTeleproId], references: [id], onDelete: SetNull)
|
|
259
|
+
createdById String // Utilisateur qui a créé le contact
|
|
260
|
+
createdBy User @relation("ContactCreatedBy", fields: [createdById], references: [id], onDelete: Cascade)
|
|
261
|
+
createdAt DateTime @default(now())
|
|
262
|
+
updatedAt DateTime @updatedAt
|
|
263
|
+
interactions Interaction[]
|
|
264
|
+
tasks Task[]
|
|
265
|
+
files ContactFile[]
|
|
266
|
+
scheduledWorkflowActions ScheduledWorkflowAction[]
|
|
267
|
+
|
|
268
|
+
@@index([statusId])
|
|
269
|
+
@@index([assignedCommercialId])
|
|
270
|
+
@@index([assignedTeleproId])
|
|
271
|
+
@@index([createdById])
|
|
272
|
+
@@index([companyId])
|
|
273
|
+
@@index([isCompany])
|
|
274
|
+
@@map("contact")
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
model Interaction {
|
|
278
|
+
id String @id @default(cuid())
|
|
279
|
+
contactId String
|
|
280
|
+
contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
281
|
+
type InteractionType
|
|
282
|
+
title String?
|
|
283
|
+
content String // Contenu de l'interaction
|
|
284
|
+
metadata Json? // Métadonnées pour stocker les détails des changements (ancienne valeur, nouvelle valeur, etc.)
|
|
285
|
+
userId String // Utilisateur qui a créé l'interaction
|
|
286
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
287
|
+
date DateTime? // Date de l'interaction (pour RDV, appels, etc.)
|
|
288
|
+
createdAt DateTime @default(now())
|
|
289
|
+
updatedAt DateTime @updatedAt
|
|
290
|
+
emailTracking EmailTracking?
|
|
291
|
+
|
|
292
|
+
@@index([contactId])
|
|
293
|
+
@@index([userId])
|
|
294
|
+
@@map("interaction")
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
model EmailTracking {
|
|
298
|
+
id String @id @default(cuid())
|
|
299
|
+
interactionId String @unique
|
|
300
|
+
interaction Interaction @relation(fields: [interactionId], references: [id], onDelete: Cascade)
|
|
301
|
+
openCount Int @default(0) // Nombre d'ouvertures
|
|
302
|
+
firstOpenedAt DateTime? // Date de la première ouverture
|
|
303
|
+
lastOpenedAt DateTime? // Date de la dernière ouverture
|
|
304
|
+
createdAt DateTime @default(now())
|
|
305
|
+
updatedAt DateTime @updatedAt
|
|
306
|
+
|
|
307
|
+
@@index([interactionId])
|
|
308
|
+
@@map("email_tracking")
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
model Task {
|
|
312
|
+
id String @id @default(cuid())
|
|
313
|
+
contactId String? // Optionnel : peut être créée depuis un contact
|
|
314
|
+
contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull)
|
|
315
|
+
type TaskType
|
|
316
|
+
title String?
|
|
317
|
+
description String // Description HTML (avec Editor)
|
|
318
|
+
priority TaskPriority @default(MEDIUM)
|
|
319
|
+
scheduledAt DateTime // Date et heure de la tâche
|
|
320
|
+
reminderMinutesBefore Int? // Rappel en minutes avant l'heure prévue (ex: 15, 30, 60)
|
|
321
|
+
assignedUserId String // Utilisateur assigné
|
|
322
|
+
assignedUser User @relation("TaskAssignedTo", fields: [assignedUserId], references: [id], onDelete: Cascade)
|
|
323
|
+
createdById String // Utilisateur qui a créé la tâche
|
|
324
|
+
createdBy User @relation("TaskCreatedBy", fields: [createdById], references: [id], onDelete: Cascade)
|
|
325
|
+
completed Boolean @default(false) // Tâche terminée ou non
|
|
326
|
+
completedAt DateTime? // Date de complétion
|
|
327
|
+
googleEventId String? // ID de l'évènement Google Calendar
|
|
328
|
+
googleMeetLink String? // URL du Google Meet
|
|
329
|
+
durationMinutes Int? // Durée de la réunion en minutes (pour Google Meet)
|
|
330
|
+
internalNote String? // Note personnelle (non partagée dans les emails)
|
|
331
|
+
notifyContact Boolean? // Si le contact a été prévenu lors de la création
|
|
332
|
+
createdAt DateTime @default(now())
|
|
333
|
+
updatedAt DateTime @updatedAt
|
|
334
|
+
|
|
335
|
+
@@index([contactId])
|
|
336
|
+
@@index([assignedUserId])
|
|
337
|
+
@@index([createdById])
|
|
338
|
+
@@index([scheduledAt])
|
|
339
|
+
@@index([googleEventId])
|
|
340
|
+
@@map("task")
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
model UserGoogleAccount {
|
|
344
|
+
id String @id @default(cuid())
|
|
345
|
+
userId String @unique
|
|
346
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
347
|
+
accessToken String
|
|
348
|
+
refreshToken String
|
|
349
|
+
tokenExpiresAt DateTime
|
|
350
|
+
email String? // Email du compte Google connecté
|
|
351
|
+
createdAt DateTime @default(now())
|
|
352
|
+
updatedAt DateTime @updatedAt
|
|
353
|
+
|
|
354
|
+
@@map("user_google_account")
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
model ContactFile {
|
|
358
|
+
id String @id @default(cuid())
|
|
359
|
+
contactId String
|
|
360
|
+
contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
361
|
+
fileName String // Nom original du fichier
|
|
362
|
+
fileSize Int // Taille en octets
|
|
363
|
+
mimeType String // Type MIME du fichier
|
|
364
|
+
googleDriveFileId String // ID du fichier dans Google Drive
|
|
365
|
+
uploadedById String // Utilisateur qui a uploadé le fichier
|
|
366
|
+
uploadedBy User @relation("ContactFileUploadedBy", fields: [uploadedById], references: [id], onDelete: Cascade)
|
|
367
|
+
createdAt DateTime @default(now())
|
|
368
|
+
updatedAt DateTime @updatedAt
|
|
369
|
+
|
|
370
|
+
@@index([contactId])
|
|
371
|
+
@@index([uploadedById])
|
|
372
|
+
@@map("contact_file")
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
model MetaLeadConfig {
|
|
376
|
+
id String @id @default(cuid())
|
|
377
|
+
name String // Nom de la configuration (ex: "Campagne Facebook Q4")
|
|
378
|
+
pageId String
|
|
379
|
+
accessToken String // Jeton d'accès de la page ou du système (chiffré)
|
|
380
|
+
verifyToken String // Token de vérification pour le webhook
|
|
381
|
+
active Boolean @default(true)
|
|
382
|
+
defaultStatusId String?
|
|
383
|
+
defaultStatus Status? @relation(fields: [defaultStatusId], references: [id], onDelete: SetNull)
|
|
384
|
+
defaultAssignedUserId String?
|
|
385
|
+
defaultAssignedUser User? @relation(fields: [defaultAssignedUserId], references: [id], onDelete: SetNull)
|
|
386
|
+
createdAt DateTime @default(now())
|
|
387
|
+
updatedAt DateTime @updatedAt
|
|
388
|
+
|
|
389
|
+
@@map("meta_lead_config")
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
model GoogleAdsLeadConfig {
|
|
393
|
+
id String @id @default(cuid())
|
|
394
|
+
name String // Nom de la configuration (ex: "Campagne Google Ads Produits")
|
|
395
|
+
webhookKey String // Clé secrète partagée pour sécuriser le webhook
|
|
396
|
+
active Boolean @default(true)
|
|
397
|
+
defaultStatusId String?
|
|
398
|
+
defaultStatus Status? @relation(fields: [defaultStatusId], references: [id], onDelete: SetNull)
|
|
399
|
+
defaultAssignedUserId String?
|
|
400
|
+
defaultAssignedUser User? @relation(fields: [defaultAssignedUserId], references: [id], onDelete: SetNull)
|
|
401
|
+
createdAt DateTime @default(now())
|
|
402
|
+
updatedAt DateTime @updatedAt
|
|
403
|
+
|
|
404
|
+
@@map("google_ads_lead_config")
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
model GoogleSheetSyncConfig {
|
|
408
|
+
id String @id @default(cuid())
|
|
409
|
+
name String // Nom de la configuration (ex: "Contacts Ventes")
|
|
410
|
+
ownerUserId String
|
|
411
|
+
ownerUser User @relation("GoogleSheetOwner", fields: [ownerUserId], references: [id], onDelete: Cascade)
|
|
412
|
+
spreadsheetId String
|
|
413
|
+
sheetName String
|
|
414
|
+
headerRow Int
|
|
415
|
+
phoneColumn String // Conservé pour compatibilité
|
|
416
|
+
firstNameColumn String? // Conservé pour compatibilité
|
|
417
|
+
lastNameColumn String? // Conservé pour compatibilité
|
|
418
|
+
emailColumn String? // Conservé pour compatibilité
|
|
419
|
+
cityColumn String? // Conservé pour compatibilité
|
|
420
|
+
postalCodeColumn String? // Conservé pour compatibilité
|
|
421
|
+
originColumn String? // Conservé pour compatibilité
|
|
422
|
+
columnMappings Json? // Nouveau format de mapping dynamique
|
|
423
|
+
active Boolean @default(true)
|
|
424
|
+
lastSyncedRow Int?
|
|
425
|
+
defaultStatusId String?
|
|
426
|
+
defaultStatus Status? @relation(fields: [defaultStatusId], references: [id], onDelete: SetNull)
|
|
427
|
+
defaultAssignedUserId String?
|
|
428
|
+
defaultAssignedUser User? @relation("GoogleSheetAssignedUser", fields: [defaultAssignedUserId], references: [id], onDelete: SetNull)
|
|
429
|
+
createdAt DateTime @default(now())
|
|
430
|
+
updatedAt DateTime @updatedAt
|
|
431
|
+
|
|
432
|
+
@@map("google_sheet_sync_config")
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
model ClosingReason {
|
|
436
|
+
id String @id @default(cuid())
|
|
437
|
+
name String // Libellé du motif de fermeture (ex: Faux numéro, Pas intéressé, etc.)
|
|
438
|
+
createdAt DateTime @default(now())
|
|
439
|
+
updatedAt DateTime @updatedAt
|
|
440
|
+
|
|
441
|
+
@@map("closing_reason")
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
enum TemplateType {
|
|
445
|
+
EMAIL
|
|
446
|
+
SMS
|
|
447
|
+
NOTE
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
model Template {
|
|
451
|
+
id String @id @default(cuid())
|
|
452
|
+
name String // Nom du template
|
|
453
|
+
type TemplateType // Type de template (EMAIL, SMS, NOTE)
|
|
454
|
+
subject String? // Sujet (pour EMAIL uniquement)
|
|
455
|
+
content String // Contenu du template (HTML pour EMAIL, texte pour SMS et NOTE)
|
|
456
|
+
userId String // Utilisateur qui a créé le template
|
|
457
|
+
user User @relation("TemplateCreatedBy", fields: [userId], references: [id], onDelete: Cascade)
|
|
458
|
+
workflowActions WorkflowAction[] @relation("WorkflowActionEmailTemplate")
|
|
459
|
+
createdAt DateTime @default(now())
|
|
460
|
+
updatedAt DateTime @updatedAt
|
|
461
|
+
|
|
462
|
+
@@index([userId])
|
|
463
|
+
@@index([type])
|
|
464
|
+
@@map("template")
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
enum WorkflowTriggerType {
|
|
468
|
+
CONTACT_CREATED // Nouveau contact créé
|
|
469
|
+
STATUS_CHANGED // Changement de statut
|
|
470
|
+
TIME_BASED // Basé sur le temps
|
|
471
|
+
MANUAL // Déclencheur manuel
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
enum WorkflowActionType {
|
|
475
|
+
SEND_EMAIL // Envoyer un email
|
|
476
|
+
SEND_SMS // Envoyer un SMS
|
|
477
|
+
CHANGE_STATUS // Changer le statut
|
|
478
|
+
CREATE_TASK // Créer une tâche
|
|
479
|
+
WAIT // Attendre
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
enum WorkflowConditionOperator {
|
|
483
|
+
EQUALS // Est égal à
|
|
484
|
+
NOT_EQUALS // N'est pas égal à
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
model Workflow {
|
|
488
|
+
id String @id @default(cuid())
|
|
489
|
+
name String
|
|
490
|
+
description String?
|
|
491
|
+
active Boolean @default(true)
|
|
492
|
+
userId String // Utilisateur propriétaire du workflow
|
|
493
|
+
user User @relation("WorkflowOwner", fields: [userId], references: [id], onDelete: Cascade)
|
|
494
|
+
|
|
495
|
+
// Configuration du déclencheur
|
|
496
|
+
triggerType WorkflowTriggerType
|
|
497
|
+
|
|
498
|
+
// Pour STATUS_CHANGED
|
|
499
|
+
triggerFromStatusId String? // Statut source (optionnel, null = tous)
|
|
500
|
+
triggerToStatusId String? // Statut cible (optionnel, null = tous)
|
|
501
|
+
triggerStatus Status? @relation("WorkflowTriggerFromStatus", fields: [triggerFromStatusId], references: [id], onDelete: SetNull)
|
|
502
|
+
triggerToStatus Status? @relation("WorkflowTriggerToStatus", fields: [triggerToStatusId], references: [id], onDelete: SetNull)
|
|
503
|
+
|
|
504
|
+
// Pour TIME_BASED
|
|
505
|
+
triggerTimeDays Int? // Nombre de jours après un événement
|
|
506
|
+
triggerTimeHours Int? // Nombre d'heures après un événement
|
|
507
|
+
|
|
508
|
+
actions WorkflowAction[]
|
|
509
|
+
scheduledActions ScheduledWorkflowAction[]
|
|
510
|
+
createdAt DateTime @default(now())
|
|
511
|
+
updatedAt DateTime @updatedAt
|
|
512
|
+
|
|
513
|
+
@@index([userId])
|
|
514
|
+
@@index([active])
|
|
515
|
+
@@map("workflow")
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
model WorkflowAction {
|
|
519
|
+
id String @id @default(cuid())
|
|
520
|
+
workflowId String
|
|
521
|
+
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
|
|
522
|
+
|
|
523
|
+
// Type d'action
|
|
524
|
+
actionType WorkflowActionType
|
|
525
|
+
|
|
526
|
+
// Ordre d'exécution
|
|
527
|
+
order Int @default(0)
|
|
528
|
+
|
|
529
|
+
// Délai avant l'action (en jours et heures)
|
|
530
|
+
delayDays Int @default(0)
|
|
531
|
+
delayHours Int @default(0)
|
|
532
|
+
|
|
533
|
+
// Configuration spécifique selon le type d'action
|
|
534
|
+
// Pour SEND_EMAIL
|
|
535
|
+
emailTemplateId String? // Template email à utiliser
|
|
536
|
+
emailTemplate Template? @relation("WorkflowActionEmailTemplate", fields: [emailTemplateId], references: [id], onDelete: SetNull)
|
|
537
|
+
|
|
538
|
+
// Pour SEND_SMS
|
|
539
|
+
smsMessage String? // Message SMS
|
|
540
|
+
|
|
541
|
+
// Pour CHANGE_STATUS
|
|
542
|
+
newStatusId String? // Nouveau statut
|
|
543
|
+
newStatus Status? @relation("WorkflowActionNewStatus", fields: [newStatusId], references: [id], onDelete: SetNull)
|
|
544
|
+
|
|
545
|
+
// Pour CREATE_TASK
|
|
546
|
+
taskTitle String? // Titre de la tâche
|
|
547
|
+
taskDescription String? // Description de la tâche
|
|
548
|
+
|
|
549
|
+
// Condition (optionnelle)
|
|
550
|
+
conditionOperator WorkflowConditionOperator? // Opérateur de condition
|
|
551
|
+
conditionStatusId String? // Statut pour la condition
|
|
552
|
+
conditionStatus Status? @relation("WorkflowActionConditionStatus", fields: [conditionStatusId], references: [id], onDelete: SetNull)
|
|
553
|
+
|
|
554
|
+
createdAt DateTime @default(now())
|
|
555
|
+
updatedAt DateTime @updatedAt
|
|
556
|
+
|
|
557
|
+
@@index([workflowId])
|
|
558
|
+
@@index([order])
|
|
559
|
+
@@map("workflow_action")
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
model ScheduledWorkflowAction {
|
|
563
|
+
id String @id @default(cuid())
|
|
564
|
+
workflowId String
|
|
565
|
+
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
|
|
566
|
+
actionId String? // ID de l'action dans le workflow (optionnel, pour référence)
|
|
567
|
+
contactId String
|
|
568
|
+
contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
569
|
+
actionType String // SEND_EMAIL, SEND_SMS, CHANGE_STATUS, CREATE_TASK, WAIT
|
|
570
|
+
actionData Json // Données de l'action (template, message, status, etc.)
|
|
571
|
+
executeAt DateTime // Date d'exécution
|
|
572
|
+
executed Boolean @default(false)
|
|
573
|
+
executedAt DateTime? // Date d'exécution réelle
|
|
574
|
+
error String? // Message d'erreur si l'exécution a échoué
|
|
575
|
+
createdAt DateTime @default(now())
|
|
576
|
+
updatedAt DateTime @updatedAt
|
|
577
|
+
|
|
578
|
+
@@index([executeAt, executed])
|
|
579
|
+
@@index([contactId])
|
|
580
|
+
@@index([workflowId])
|
|
581
|
+
@@map("scheduled_workflow_action")
|
|
582
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// This file was generated by Prisma and assumes you have installed the following:
|
|
2
|
+
// npm install --save-dev prisma dotenv
|
|
3
|
+
import 'dotenv/config';
|
|
4
|
+
import { defineConfig, env } from 'prisma/config';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
schema: 'prisma/schema.prisma',
|
|
8
|
+
migrations: {
|
|
9
|
+
path: 'prisma/migrations',
|
|
10
|
+
},
|
|
11
|
+
datasource: {
|
|
12
|
+
url: env('DIRECT_URL'),
|
|
13
|
+
},
|
|
14
|
+
});
|