create-crm-tmp 1.0.2 → 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.
- package/bin/create-crm-tmp.js +7 -3
- package/package.json +1 -1
- package/template/README.md +70 -5
- package/template/WORKFLOWS_CRON.md +49 -27
- package/template/package.json +18 -16
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +20 -0
- package/template/prisma/schema.prisma +17 -0
- package/template/src/app/(dashboard)/agenda/page.tsx +279 -225
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +1 -5
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +20 -47
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +0 -2
- package/template/src/app/(dashboard)/closing/page.tsx +5 -57
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +60 -44
- package/template/src/app/(dashboard)/contacts/page.tsx +156 -210
- package/template/src/app/(dashboard)/dashboard/page.tsx +438 -91
- package/template/src/app/(dashboard)/settings/page.tsx +179 -77
- package/template/src/app/(dashboard)/users/layout.tsx +30 -0
- package/template/src/app/(dashboard)/users/list/page.tsx +213 -159
- package/template/src/app/(dashboard)/users/page.tsx +13 -46
- package/template/src/app/(dashboard)/users/permissions/page.tsx +0 -2
- package/template/src/app/(dashboard)/users/roles/page.tsx +0 -2
- package/template/src/app/api/audit-logs/route.ts +0 -2
- package/template/src/app/api/auth/google/status/route.ts +46 -7
- package/template/src/app/api/closing-reasons/route.ts +0 -2
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +2 -1
- package/template/src/app/api/contacts/[id]/files/route.ts +25 -20
- package/template/src/app/api/contacts/[id]/route.ts +2 -3
- package/template/src/app/api/contacts/export/route.ts +14 -11
- package/template/src/app/api/contacts/import/route.ts +2 -6
- package/template/src/app/api/contacts/route.ts +1 -1
- package/template/src/app/api/dashboard/stats/route.ts +7 -0
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +47 -0
- package/template/src/app/api/dashboard/widgets/route.ts +181 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +58 -28
- package/template/src/app/api/reminders/route.ts +4 -2
- package/template/src/app/api/roles/route.ts +1 -1
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +1 -6
- package/template/src/app/api/settings/closing-reasons/route.ts +0 -2
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +10 -5
- package/template/src/app/api/settings/google-sheet/route.ts +3 -3
- package/template/src/app/api/tasks/[id]/route.ts +4 -4
- package/template/src/app/api/tasks/meet/route.ts +1 -2
- package/template/src/app/api/tasks/route.ts +16 -18
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/workflows/[id]/route.ts +2 -9
- package/template/src/app/api/workflows/route.ts +0 -1
- package/template/src/app/globals.css +96 -0
- package/template/src/components/dashboard/activity-chart.tsx +37 -37
- package/template/src/components/dashboard/add-widget-dialog.tsx +161 -0
- package/template/src/components/dashboard/color-picker.tsx +65 -0
- package/template/src/components/dashboard/contacts-chart.tsx +36 -30
- package/template/src/components/dashboard/interactions-by-type-chart.tsx +121 -0
- package/template/src/components/dashboard/recent-activity.tsx +79 -86
- package/template/src/components/dashboard/sales-analytics-chart.tsx +4 -8
- package/template/src/components/dashboard/stat-card.tsx +42 -40
- package/template/src/components/dashboard/status-distribution-chart.tsx +64 -27
- package/template/src/components/dashboard/tasks-pie-chart.tsx +37 -34
- package/template/src/components/dashboard/top-contacts-list.tsx +41 -51
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +71 -78
- package/template/src/components/dashboard/widget-wrapper.tsx +39 -0
- package/template/src/components/header.tsx +21 -12
- package/template/src/components/page-header.tsx +14 -47
- package/template/src/components/sidebar.tsx +3 -4
- package/template/src/contexts/dashboard-theme-context.tsx +58 -0
- package/template/src/lib/audit-log.ts +0 -2
- package/template/src/lib/dashboard-themes.ts +140 -0
- package/template/src/lib/default-widgets.ts +14 -0
- package/template/src/lib/google-drive.ts +38 -30
- package/template/src/lib/permissions.ts +56 -1
- package/template/src/lib/prisma.ts +0 -1
- package/template/src/lib/widget-registry.ts +177 -0
- package/template/src/lib/workflow-executor.ts +7 -13
- package/README.md +0 -89
package/bin/create-crm-tmp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require("fs-extra");
|
|
4
|
-
const path = require("path");
|
|
4
|
+
const path = require("node:path");
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const prompts = require("prompts");
|
|
7
7
|
|
|
@@ -61,11 +61,14 @@ async function main() {
|
|
|
61
61
|
DATABASE_URL="" # Supabase Prod
|
|
62
62
|
DIRECT_URL="" # Supabase Migration
|
|
63
63
|
|
|
64
|
-
BETTER_AUTH_SECRET=""
|
|
64
|
+
BETTER_AUTH_SECRET="" # openssl rand -base64 32
|
|
65
65
|
BETTER_AUTH_URL="http://localhost:3000"
|
|
66
66
|
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
67
67
|
|
|
68
|
-
APP_NAME="${projectName
|
|
68
|
+
APP_NAME="${projectName
|
|
69
|
+
.replaceAll(/\s+/g, "")
|
|
70
|
+
.replaceAll(/([a-z])([A-Z])/g, "$1 $2")
|
|
71
|
+
.replaceAll(/(^\w|\s\w)/g, (m) => m.toUpperCase())}"
|
|
69
72
|
|
|
70
73
|
ENCRYPTION_KEY="" #openssl rand -base64 32
|
|
71
74
|
|
|
@@ -130,6 +133,7 @@ next-env.d.ts
|
|
|
130
133
|
|
|
131
134
|
scripts/
|
|
132
135
|
# vercel.json`;
|
|
136
|
+
fs.writeFileSync(gitIgnoreExemplePath, gitIgnore);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
console.log(chalk.green("✅ Projet créé avec succès !\n"));
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# 📊 CRM Template
|
|
2
2
|
|
|
3
|
-
Un CRM moderne, orienté **prospection & suivi commercial**, construit avec
|
|
4
|
-
**
|
|
3
|
+
Un CRM moderne, orienté **prospection & suivi commercial**, construit avec
|
|
4
|
+
**Next.js 16**,
|
|
5
|
+
**Better Auth**, **Prisma**, **PostgreSQL** et une UI inspirée d’un template CRM
|
|
6
|
+
pro.
|
|
5
7
|
|
|
6
8
|
## ✨ Fonctionnalités
|
|
7
9
|
|
|
@@ -31,7 +33,8 @@ Un CRM moderne, orienté **prospection & suivi commercial**, construit avec **Ne
|
|
|
31
33
|
- Paramètres généraux (profil, sécurité, informations d’entreprise)
|
|
32
34
|
- Configuration SMTP + signature email
|
|
33
35
|
- Gestion des statuts & motifs de fermeture
|
|
34
|
-
- Intégrations (Google Calendar & Drive, Google Sheets, Meta Lead Ads, Google
|
|
36
|
+
- Intégrations (Google Calendar & Drive, Google Sheets, Meta Lead Ads, Google
|
|
37
|
+
Ads…)
|
|
35
38
|
- 🤖 **Automatisations (Workflows)**
|
|
36
39
|
- Workflows avec actions chaînées
|
|
37
40
|
- Exécution planifiée via **Vercel Cron**
|
|
@@ -50,6 +53,66 @@ Un CRM moderne, orienté **prospection & suivi commercial**, construit avec **Ne
|
|
|
50
53
|
- **Langage**: TypeScript
|
|
51
54
|
- **Gestionnaire de paquets**: pnpm
|
|
52
55
|
|
|
56
|
+
## 🚀 Initialiser un projet via le package `create-crm-tmp`
|
|
57
|
+
|
|
58
|
+
Ce template est distribué sous forme de package `create-crm-tmp`.
|
|
59
|
+
Pour créer un nouveau projet basé sur ce CRM :
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pnpm create crm-tmp@latest mon-crm
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Puis :
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cd mon-crm
|
|
69
|
+
pnpm install
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
À partir de là, vous pouvez suivre les étapes de configuration ci‑dessous (variables d’environnement, base de données et migrations).
|
|
73
|
+
|
|
74
|
+
### 🔌 Utiliser Supabase comme base de données PostgreSQL
|
|
75
|
+
|
|
76
|
+
Vous pouvez utiliser **Supabase** uniquement comme **hébergeur PostgreSQL** (l’auth du projet reste gérée par Better Auth).
|
|
77
|
+
|
|
78
|
+
1. **Créer un projet Supabase**
|
|
79
|
+
- Allez sur le dashboard Supabase.
|
|
80
|
+
- Créez un nouveau projet.
|
|
81
|
+
- Attendez que la base de données soit provisionnée.
|
|
82
|
+
2. **Récupérer la connexion Postgres**
|
|
83
|
+
- Dans Supabase, ouvrez `Settings > Database`.
|
|
84
|
+
- Copiez la **connection string** en `postgresql://...` (par exemple, pour Node.js / server).
|
|
85
|
+
3. **Configurer `DATABASE_URL`**
|
|
86
|
+
- Dans votre projet généré (`mon-crm`), créez ou mettez à jour le fichier `.env` :
|
|
87
|
+
|
|
88
|
+
```env
|
|
89
|
+
# Database (Supabase)
|
|
90
|
+
DATABASE_URL="postgresql://<user>:<password>@<host>:<port>/<database>?sslmode=require"
|
|
91
|
+
|
|
92
|
+
# Better Auth
|
|
93
|
+
BETTER_AUTH_SECRET="votre-clé-secrète-minimum-32-caractères"
|
|
94
|
+
BETTER_AUTH_URL="http://localhost:3000"
|
|
95
|
+
|
|
96
|
+
# Application
|
|
97
|
+
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
98
|
+
NODE_ENV="development"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- Remplacez la valeur de `DATABASE_URL` par celle fournie par Supabase (en gardant les paramètres de sécurité recommandés).
|
|
102
|
+
4. **Appliquer les migrations Prisma sur Supabase**
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pnpm prisma migrate deploy
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
5. **Lancer l’application**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm dev
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
L’application utilisera désormais la base PostgreSQL hébergée sur Supabase.
|
|
115
|
+
|
|
53
116
|
## 🚀 Installation
|
|
54
117
|
|
|
55
118
|
1. **Cloner le projet**
|
|
@@ -142,8 +205,10 @@ src/
|
|
|
142
205
|
- Redirection vers le dashboard si déjà connecté sur les pages d’auth
|
|
143
206
|
- **Rôles & permissions** :
|
|
144
207
|
- Rôles techniques + rôles personnalisés configurables via l’interface
|
|
145
|
-
- Vérification des permissions côté API (ex : `users.view`,
|
|
146
|
-
|
|
208
|
+
- Vérification des permissions côté API (ex : `users.view`,
|
|
209
|
+
`users.manage_roles`, intégrations…)
|
|
210
|
+
- Certaines sections (informations d’entreprise, paramètres d’application /
|
|
211
|
+
système, intégrations, export contacts) sont réservées aux administrateurs
|
|
147
212
|
|
|
148
213
|
## 🎨 Personnalisation
|
|
149
214
|
|
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
# Configuration des Workflows avec Vercel Cron
|
|
2
2
|
|
|
3
|
-
Ce document explique comment fonctionne le système de planification des actions
|
|
3
|
+
Ce document explique comment fonctionne le système de planification des actions
|
|
4
|
+
de workflow avec Vercel Cron.
|
|
4
5
|
|
|
5
6
|
## Fonctionnement
|
|
6
7
|
|
|
7
|
-
Le système utilise une table `ScheduledWorkflowAction` dans la base de données
|
|
8
|
+
Le système utilise une table `ScheduledWorkflowAction` dans la base de données
|
|
9
|
+
pour stocker les actions à exécuter plus tard. Un cron job Vercel appelle
|
|
10
|
+
l'endpoint `/api/workflows/process` toutes les minutes pour traiter les actions
|
|
11
|
+
dont la date d'exécution est arrivée.
|
|
8
12
|
|
|
9
13
|
## Configuration
|
|
10
14
|
|
|
11
15
|
### 1. Variables d'environnement
|
|
12
16
|
|
|
13
|
-
Ajoutez cette variable dans votre fichier `.env` et dans les variables
|
|
17
|
+
Ajoutez cette variable dans votre fichier `.env` et dans les variables
|
|
18
|
+
d'environnement Vercel :
|
|
14
19
|
|
|
15
20
|
```env
|
|
16
21
|
CRON_SECRET=votre_secret_aleatoire_ici
|
|
17
22
|
```
|
|
18
23
|
|
|
19
|
-
**Important** : Utilisez un secret fort et aléatoire pour sécuriser l'endpoint
|
|
24
|
+
**Important** : Utilisez un secret fort et aléatoire pour sécuriser l'endpoint
|
|
25
|
+
cron. Vous pouvez générer un secret avec :
|
|
20
26
|
|
|
21
27
|
```bash
|
|
22
28
|
openssl rand -base64 32
|
|
@@ -24,19 +30,22 @@ openssl rand -base64 32
|
|
|
24
30
|
|
|
25
31
|
### 2. Configuration du service de cron (si plan Hobby)
|
|
26
32
|
|
|
27
|
-
Si vous êtes sur le plan Hobby de Vercel, vous devez utiliser un service externe
|
|
33
|
+
Si vous êtes sur le plan Hobby de Vercel, vous devez utiliser un service externe
|
|
34
|
+
comme cron-job.org.
|
|
28
35
|
|
|
29
36
|
#### Configuration cron-job.org
|
|
30
37
|
|
|
31
38
|
1. Créez un compte sur [cron-job.org](https://cron-job.org/)
|
|
32
39
|
2. Créez un nouveau cron job avec ces paramètres :
|
|
33
|
-
- **URL** :
|
|
40
|
+
- **URL** :
|
|
41
|
+
`https://votre-domaine.vercel.app/api/workflows/process?secret=VOTRE_CRON_SECRET`
|
|
34
42
|
- **Méthode** : `GET`
|
|
35
43
|
- **Schedule** : `Every minute` ou `*/1 * * * *`
|
|
36
44
|
- **Title** : "Workflow Actions Processor"
|
|
37
45
|
- **Active** : ✓
|
|
38
46
|
|
|
39
|
-
**Note** : Remplacez `VOTRE_CRON_SECRET` par la valeur de votre variable
|
|
47
|
+
**Note** : Remplacez `VOTRE_CRON_SECRET` par la valeur de votre variable
|
|
48
|
+
d'environnement `CRON_SECRET`.
|
|
40
49
|
|
|
41
50
|
#### Autres services compatibles
|
|
42
51
|
|
|
@@ -46,7 +55,8 @@ Si vous êtes sur le plan Hobby de Vercel, vous devez utiliser un service extern
|
|
|
46
55
|
|
|
47
56
|
### 3. Migration Prisma
|
|
48
57
|
|
|
49
|
-
Après avoir ajouté le modèle `ScheduledWorkflowAction` dans `schema.prisma`,
|
|
58
|
+
Après avoir ajouté le modèle `ScheduledWorkflowAction` dans `schema.prisma`,
|
|
59
|
+
créez et exécutez la migration :
|
|
50
60
|
|
|
51
61
|
```bash
|
|
52
62
|
pnpm prisma migrate dev --name add_scheduled_workflow_actions
|
|
@@ -54,7 +64,8 @@ pnpm prisma migrate dev --name add_scheduled_workflow_actions
|
|
|
54
64
|
|
|
55
65
|
### 4. Configuration Vercel (optionnel - plans Pro/Enterprise uniquement)
|
|
56
66
|
|
|
57
|
-
Le fichier `vercel.json` est configuré pour exécuter le cron toutes les minutes
|
|
67
|
+
Le fichier `vercel.json` est configuré pour exécuter le cron toutes les minutes
|
|
68
|
+
:
|
|
58
69
|
|
|
59
70
|
```json
|
|
60
71
|
{
|
|
@@ -67,20 +78,26 @@ Le fichier `vercel.json` est configuré pour exécuter le cron toutes les minute
|
|
|
67
78
|
}
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
**Note** : Vercel Cron est disponible uniquement sur les plans Pro et
|
|
81
|
+
**Note** : Vercel Cron est disponible uniquement sur les plans Pro et
|
|
82
|
+
Enterprise. Sur le plan Hobby, utilisez un service externe comme cron-job.org
|
|
83
|
+
(voir section 2).
|
|
71
84
|
|
|
72
85
|
### 5. Déploiement
|
|
73
86
|
|
|
74
87
|
1. Poussez vos changements sur votre repository
|
|
75
|
-
2. Si vous êtes sur plan Pro/Enterprise : Vercel détectera automatiquement le
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
2. Si vous êtes sur plan Pro/Enterprise : Vercel détectera automatiquement le
|
|
89
|
+
fichier `vercel.json` et configurera le cron
|
|
90
|
+
3. Si vous êtes sur plan Hobby : Configurez cron-job.org ou un autre service
|
|
91
|
+
externe (voir section 2)
|
|
92
|
+
4. Vérifiez que `CRON_SECRET` est bien configuré dans les variables
|
|
93
|
+
d'environnement Vercel
|
|
78
94
|
|
|
79
95
|
## Fonctionnement détaillé
|
|
80
96
|
|
|
81
97
|
### Planification d'une action
|
|
82
98
|
|
|
83
|
-
Quand un workflow est déclenché et qu'une action a un délai (jours/heures), le
|
|
99
|
+
Quand un workflow est déclenché et qu'une action a un délai (jours/heures), le
|
|
100
|
+
système :
|
|
84
101
|
|
|
85
102
|
1. Calcule la date d'exécution : `Date.now() + délai`
|
|
86
103
|
2. Sauvegarde l'action dans `ScheduledWorkflowAction` avec :
|
|
@@ -114,26 +131,29 @@ Vous pouvez surveiller les actions planifiées via la base de données :
|
|
|
114
131
|
|
|
115
132
|
```sql
|
|
116
133
|
-- Actions en attente
|
|
117
|
-
SELECT * FROM scheduled_workflow_action
|
|
118
|
-
WHERE executed = false
|
|
134
|
+
SELECT * FROM scheduled_workflow_action
|
|
135
|
+
WHERE executed = false
|
|
119
136
|
ORDER BY executeAt ASC;
|
|
120
137
|
|
|
121
138
|
-- Actions récemment exécutées
|
|
122
|
-
SELECT * FROM scheduled_workflow_action
|
|
123
|
-
WHERE executed = true
|
|
124
|
-
ORDER BY executedAt DESC
|
|
139
|
+
SELECT * FROM scheduled_workflow_action
|
|
140
|
+
WHERE executed = true
|
|
141
|
+
ORDER BY executedAt DESC
|
|
125
142
|
LIMIT 50;
|
|
126
143
|
|
|
127
144
|
-- Actions en erreur
|
|
128
|
-
SELECT * FROM scheduled_workflow_action
|
|
145
|
+
SELECT * FROM scheduled_workflow_action
|
|
129
146
|
WHERE executed = true AND error IS NOT NULL;
|
|
130
147
|
```
|
|
131
148
|
|
|
132
149
|
## Limitations
|
|
133
150
|
|
|
134
|
-
- **Précision** : Les actions sont exécutées avec une précision d'environ 1
|
|
135
|
-
|
|
136
|
-
- **
|
|
151
|
+
- **Précision** : Les actions sont exécutées avec une précision d'environ 1
|
|
152
|
+
minute (selon la fréquence du cron)
|
|
153
|
+
- **Limite par exécution** : Maximum 50 actions traitées par exécution du cron
|
|
154
|
+
(pour éviter les timeouts)
|
|
155
|
+
- **Retry** : Les actions échouées ne sont pas automatiquement réessayées (elles
|
|
156
|
+
sont marquées comme exécutées avec une erreur)
|
|
137
157
|
|
|
138
158
|
## Dépannage
|
|
139
159
|
|
|
@@ -141,14 +161,16 @@ WHERE executed = true AND error IS NOT NULL;
|
|
|
141
161
|
|
|
142
162
|
1. **Si vous utilisez Vercel Cron** :
|
|
143
163
|
- Vérifiez que vous êtes sur un plan Vercel Pro ou Enterprise
|
|
144
|
-
- Vérifiez dans le dashboard Vercel que le cron est bien configuré (Settings
|
|
164
|
+
- Vérifiez dans le dashboard Vercel que le cron est bien configuré (Settings
|
|
165
|
+
→ Cron Jobs)
|
|
145
166
|
- Vérifiez les logs Vercel pour voir les erreurs éventuelles
|
|
146
167
|
|
|
147
168
|
2. **Si vous utilisez un service externe (cron-job.org, etc.)** :
|
|
148
169
|
- Vérifiez que le job est actif dans votre service
|
|
149
170
|
- Vérifiez l'URL utilisée (doit inclure `?secret=VOTRE_CRON_SECRET`)
|
|
150
171
|
- Vérifiez les logs de votre service de cron
|
|
151
|
-
- Testez manuellement l'URL dans votre navigateur (avec le secret) pour voir
|
|
172
|
+
- Testez manuellement l'URL dans votre navigateur (avec le secret) pour voir
|
|
173
|
+
si elle répond
|
|
152
174
|
|
|
153
175
|
### Les actions ne s'exécutent pas
|
|
154
176
|
|
|
@@ -159,5 +181,5 @@ WHERE executed = true AND error IS NOT NULL;
|
|
|
159
181
|
|
|
160
182
|
### Erreurs d'exécution
|
|
161
183
|
|
|
162
|
-
Les erreurs sont enregistrées dans le champ `error` de
|
|
163
|
-
|
|
184
|
+
Les erreurs sont enregistrées dans le champ `error` de
|
|
185
|
+
`ScheduledWorkflowAction`. Consultez ce champ pour diagnostiquer les problèmes.
|
package/template/package.json
CHANGED
|
@@ -21,42 +21,44 @@
|
|
|
21
21
|
"@lexical/selection": "^0.38.2",
|
|
22
22
|
"@lexical/utils": "^0.38.2",
|
|
23
23
|
"@lexkit/editor": "^0.0.38",
|
|
24
|
-
"@prisma/adapter-pg": "^7.
|
|
25
|
-
"@prisma/client": "^7.
|
|
26
|
-
"@react-email/render": "^2.0.
|
|
24
|
+
"@prisma/adapter-pg": "^7.3.0",
|
|
25
|
+
"@prisma/client": "^7.3.0",
|
|
26
|
+
"@react-email/render": "^2.0.4",
|
|
27
27
|
"bcryptjs": "^3.0.3",
|
|
28
|
-
"better-auth": "^1.4.
|
|
28
|
+
"better-auth": "^1.4.18",
|
|
29
29
|
"clsx": "^2.1.1",
|
|
30
|
-
"dotenv": "^17.2.
|
|
30
|
+
"dotenv": "^17.2.4",
|
|
31
31
|
"iron-session": "^8.0.4",
|
|
32
32
|
"lexical": "^0.38.2",
|
|
33
33
|
"lucide-react": "^0.555.0",
|
|
34
34
|
"next": "16.0.10",
|
|
35
|
-
"nodemailer": "^7.0.
|
|
35
|
+
"nodemailer": "^7.0.13",
|
|
36
36
|
"papaparse": "^5.5.3",
|
|
37
|
-
"pg": "^8.
|
|
37
|
+
"pg": "^8.18.0",
|
|
38
38
|
"react": "19.2.3",
|
|
39
39
|
"react-dom": "19.2.3",
|
|
40
|
-
"react-
|
|
40
|
+
"react-grid-layout": "^2.2.2",
|
|
41
|
+
"react-hook-form": "^7.71.1",
|
|
41
42
|
"recharts": "^2.15.4",
|
|
42
43
|
"tailwind-merge": "^3.4.0",
|
|
43
44
|
"xlsx": "^0.18.5",
|
|
44
|
-
"zod": "^4.
|
|
45
|
+
"zod": "^4.3.6"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@tailwindcss/postcss": "^4.1.18",
|
|
48
|
-
"@types/node": "^20.19.
|
|
49
|
-
"@types/nodemailer": "^7.0.
|
|
50
|
-
"@types/papaparse": "^5.5.
|
|
49
|
+
"@types/node": "^20.19.33",
|
|
50
|
+
"@types/nodemailer": "^7.0.9",
|
|
51
|
+
"@types/papaparse": "^5.5.2",
|
|
51
52
|
"@types/pg": "^8.16.0",
|
|
52
|
-
"@types/react": "^19.2.
|
|
53
|
+
"@types/react": "^19.2.13",
|
|
53
54
|
"@types/react-dom": "^19.2.3",
|
|
55
|
+
"@types/react-grid-layout": "^2.1.0",
|
|
54
56
|
"babel-plugin-react-compiler": "1.0.0",
|
|
55
|
-
"eslint": "^9.39.
|
|
57
|
+
"eslint": "^9.39.2",
|
|
56
58
|
"eslint-config-next": "16.0.7",
|
|
57
|
-
"prettier": "^3.
|
|
59
|
+
"prettier": "^3.8.1",
|
|
58
60
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
59
|
-
"prisma": "^7.
|
|
61
|
+
"prisma": "^7.3.0",
|
|
60
62
|
"tailwindcss": "^4.1.18",
|
|
61
63
|
"tsx": "^4.21.0",
|
|
62
64
|
"typescript": "^5.9.3"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "dashboard_widget" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"userId" TEXT NOT NULL,
|
|
5
|
+
"type" TEXT NOT NULL,
|
|
6
|
+
"x" INTEGER NOT NULL DEFAULT 0,
|
|
7
|
+
"y" INTEGER NOT NULL DEFAULT 0,
|
|
8
|
+
"w" INTEGER NOT NULL DEFAULT 6,
|
|
9
|
+
"h" INTEGER NOT NULL DEFAULT 4,
|
|
10
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
11
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
12
|
+
|
|
13
|
+
CONSTRAINT "dashboard_widget_pkey" PRIMARY KEY ("id")
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
-- CreateIndex
|
|
17
|
+
CREATE INDEX "dashboard_widget_userId_idx" ON "dashboard_widget"("userId");
|
|
18
|
+
|
|
19
|
+
-- AddForeignKey
|
|
20
|
+
ALTER TABLE "dashboard_widget" ADD CONSTRAINT "dashboard_widget_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -67,6 +67,7 @@ model User {
|
|
|
67
67
|
auditLogsAsActor AuditLog[] @relation("AuditActor")
|
|
68
68
|
auditLogsAsTargetUser AuditLog[] @relation("AuditTargetUser")
|
|
69
69
|
workflows Workflow[] @relation("WorkflowOwner")
|
|
70
|
+
dashboardWidgets DashboardWidget[]
|
|
70
71
|
|
|
71
72
|
@@unique([email])
|
|
72
73
|
@@index([customRoleId])
|
|
@@ -583,3 +584,19 @@ model ScheduledWorkflowAction {
|
|
|
583
584
|
@@index([workflowId])
|
|
584
585
|
@@map("scheduled_workflow_action")
|
|
585
586
|
}
|
|
587
|
+
|
|
588
|
+
model DashboardWidget {
|
|
589
|
+
id String @id @default(cuid())
|
|
590
|
+
userId String
|
|
591
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
592
|
+
type String // Identifiant du type de widget (ex: stat_total_contacts, contacts_chart, etc.)
|
|
593
|
+
x Int @default(0)
|
|
594
|
+
y Int @default(0)
|
|
595
|
+
w Int @default(6) // Largeur sur grille de 12
|
|
596
|
+
h Int @default(4) // Hauteur en unités
|
|
597
|
+
createdAt DateTime @default(now())
|
|
598
|
+
updatedAt DateTime @updatedAt
|
|
599
|
+
|
|
600
|
+
@@index([userId])
|
|
601
|
+
@@map("dashboard_widget")
|
|
602
|
+
}
|