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.
Files changed (187) hide show
  1. package/bin/create-crm-tmp.js +93 -0
  2. package/package.json +25 -0
  3. package/template/.prettierignore +33 -0
  4. package/template/.prettierrc.json +25 -0
  5. package/template/README.md +173 -0
  6. package/template/eslint.config.mjs +18 -0
  7. package/template/exemple-contacts.csv +11 -0
  8. package/template/next.config.ts +8 -0
  9. package/template/package.json +64 -0
  10. package/template/postcss.config.mjs +7 -0
  11. package/template/prisma/migrations/20251126144728_init/migration.sql +78 -0
  12. package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +5 -0
  13. package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +19 -0
  14. package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +22 -0
  15. package/template/prisma/migrations/20251128132303_add_status/migration.sql +23 -0
  16. package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +75 -0
  17. package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +2 -0
  18. package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +45 -0
  19. package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +2 -0
  20. package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +27 -0
  21. package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +20 -0
  22. package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +18 -0
  23. package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +32 -0
  24. package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +20 -0
  25. package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +12 -0
  26. package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +21 -0
  27. package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +11 -0
  28. package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +12 -0
  29. package/template/prisma/migrations/20251208094843_mg/migration.sql +14 -0
  30. package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +14 -0
  31. package/template/prisma/migrations/20251208110000_add_templates/migration.sql +26 -0
  32. package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +2 -0
  33. package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +2 -0
  34. package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +2 -0
  35. package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +3 -0
  36. package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +21 -0
  37. package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +2 -0
  38. package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +10 -0
  39. package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +26 -0
  40. package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +24 -0
  41. package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +11 -0
  42. package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +12 -0
  43. package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +25 -0
  44. package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +8 -0
  45. package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +2 -0
  46. package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +80 -0
  47. package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +32 -0
  48. package/template/prisma/migrations/migration_lock.toml +3 -0
  49. package/template/prisma/schema.prisma +582 -0
  50. package/template/prisma.config.ts +14 -0
  51. package/template/src/app/(auth)/invite/[token]/page.tsx +200 -0
  52. package/template/src/app/(auth)/layout.tsx +3 -0
  53. package/template/src/app/(auth)/reset-password/complete/page.tsx +213 -0
  54. package/template/src/app/(auth)/reset-password/page.tsx +146 -0
  55. package/template/src/app/(auth)/reset-password/verify/page.tsx +183 -0
  56. package/template/src/app/(auth)/signin/page.tsx +166 -0
  57. package/template/src/app/(dashboard)/agenda/page.tsx +3051 -0
  58. package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +24 -0
  59. package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +905 -0
  60. package/template/src/app/(dashboard)/automatisation/new/page.tsx +20 -0
  61. package/template/src/app/(dashboard)/automatisation/page.tsx +337 -0
  62. package/template/src/app/(dashboard)/closing/page.tsx +1052 -0
  63. package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6028 -0
  64. package/template/src/app/(dashboard)/contacts/page.tsx +3713 -0
  65. package/template/src/app/(dashboard)/dashboard/page.tsx +186 -0
  66. package/template/src/app/(dashboard)/layout.tsx +30 -0
  67. package/template/src/app/(dashboard)/settings/page.tsx +4070 -0
  68. package/template/src/app/(dashboard)/templates/page.tsx +567 -0
  69. package/template/src/app/(dashboard)/users/list/page.tsx +507 -0
  70. package/template/src/app/(dashboard)/users/page.tsx +457 -0
  71. package/template/src/app/(dashboard)/users/permissions/page.tsx +181 -0
  72. package/template/src/app/(dashboard)/users/roles/page.tsx +434 -0
  73. package/template/src/app/api/audit-logs/route.ts +57 -0
  74. package/template/src/app/api/auth/[...all]/route.ts +4 -0
  75. package/template/src/app/api/auth/check-active/route.ts +31 -0
  76. package/template/src/app/api/auth/google/callback/route.ts +94 -0
  77. package/template/src/app/api/auth/google/disconnect/route.ts +32 -0
  78. package/template/src/app/api/auth/google/route.ts +34 -0
  79. package/template/src/app/api/auth/google/status/route.ts +32 -0
  80. package/template/src/app/api/closing-reasons/route.ts +27 -0
  81. package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +94 -0
  82. package/template/src/app/api/contacts/[id]/files/route.ts +269 -0
  83. package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +91 -0
  84. package/template/src/app/api/contacts/[id]/interactions/route.ts +103 -0
  85. package/template/src/app/api/contacts/[id]/meet/route.ts +296 -0
  86. package/template/src/app/api/contacts/[id]/route.ts +322 -0
  87. package/template/src/app/api/contacts/[id]/send-email/route.ts +254 -0
  88. package/template/src/app/api/contacts/export/route.ts +270 -0
  89. package/template/src/app/api/contacts/import/route.ts +381 -0
  90. package/template/src/app/api/contacts/route.ts +283 -0
  91. package/template/src/app/api/dashboard/stats/route.ts +299 -0
  92. package/template/src/app/api/email/track/[id]/route.ts +68 -0
  93. package/template/src/app/api/integrations/google-sheet/sync/route.ts +526 -0
  94. package/template/src/app/api/invite/complete/route.ts +88 -0
  95. package/template/src/app/api/invite/validate/route.ts +55 -0
  96. package/template/src/app/api/reminders/route.ts +95 -0
  97. package/template/src/app/api/reset-password/complete/route.ts +73 -0
  98. package/template/src/app/api/reset-password/request/route.ts +84 -0
  99. package/template/src/app/api/reset-password/validate/route.ts +49 -0
  100. package/template/src/app/api/reset-password/verify/route.ts +74 -0
  101. package/template/src/app/api/roles/[id]/route.ts +183 -0
  102. package/template/src/app/api/roles/route.ts +140 -0
  103. package/template/src/app/api/send/route.ts +282 -0
  104. package/template/src/app/api/settings/change-password/route.ts +95 -0
  105. package/template/src/app/api/settings/closing-reasons/[id]/route.ts +84 -0
  106. package/template/src/app/api/settings/closing-reasons/route.ts +74 -0
  107. package/template/src/app/api/settings/company/route.ts +121 -0
  108. package/template/src/app/api/settings/google-ads/[id]/route.ts +117 -0
  109. package/template/src/app/api/settings/google-ads/route.ts +122 -0
  110. package/template/src/app/api/settings/google-sheet/[id]/route.ts +230 -0
  111. package/template/src/app/api/settings/google-sheet/auto-map/route.ts +196 -0
  112. package/template/src/app/api/settings/google-sheet/route.ts +254 -0
  113. package/template/src/app/api/settings/meta-leads/[id]/route.ts +123 -0
  114. package/template/src/app/api/settings/meta-leads/route.ts +132 -0
  115. package/template/src/app/api/settings/profile/route.ts +42 -0
  116. package/template/src/app/api/settings/smtp/route.ts +130 -0
  117. package/template/src/app/api/settings/smtp/test/route.ts +121 -0
  118. package/template/src/app/api/settings/statuses/[id]/route.ts +101 -0
  119. package/template/src/app/api/settings/statuses/route.ts +83 -0
  120. package/template/src/app/api/statuses/route.ts +25 -0
  121. package/template/src/app/api/tasks/[id]/attendees/route.ts +76 -0
  122. package/template/src/app/api/tasks/[id]/route.ts +728 -0
  123. package/template/src/app/api/tasks/meet/route.ts +240 -0
  124. package/template/src/app/api/tasks/route.ts +417 -0
  125. package/template/src/app/api/templates/[id]/route.ts +140 -0
  126. package/template/src/app/api/templates/route.ts +91 -0
  127. package/template/src/app/api/users/[id]/route.ts +168 -0
  128. package/template/src/app/api/users/list/route.ts +45 -0
  129. package/template/src/app/api/users/me/route.ts +48 -0
  130. package/template/src/app/api/users/route.ts +250 -0
  131. package/template/src/app/api/webhooks/google-ads/route.ts +208 -0
  132. package/template/src/app/api/webhooks/meta-leads/route.ts +258 -0
  133. package/template/src/app/api/workflows/[id]/route.ts +192 -0
  134. package/template/src/app/api/workflows/process/route.ts +293 -0
  135. package/template/src/app/api/workflows/route.ts +124 -0
  136. package/template/src/app/favicon.ico +0 -0
  137. package/template/src/app/globals.css +1416 -0
  138. package/template/src/app/layout.tsx +31 -0
  139. package/template/src/app/page.tsx +32 -0
  140. package/template/src/components/dashboard/activity-chart.tsx +67 -0
  141. package/template/src/components/dashboard/contacts-chart.tsx +63 -0
  142. package/template/src/components/dashboard/recent-activity.tsx +164 -0
  143. package/template/src/components/dashboard/sales-analytics-chart.tsx +81 -0
  144. package/template/src/components/dashboard/stat-card.tsx +61 -0
  145. package/template/src/components/dashboard/status-distribution-chart.tsx +45 -0
  146. package/template/src/components/dashboard/tasks-pie-chart.tsx +88 -0
  147. package/template/src/components/dashboard/top-contacts-list.tsx +129 -0
  148. package/template/src/components/dashboard/upcoming-tasks-list.tsx +126 -0
  149. package/template/src/components/editor.tsx +856 -0
  150. package/template/src/components/email-template.tsx +35 -0
  151. package/template/src/components/header.tsx +320 -0
  152. package/template/src/components/invitation-email-template.tsx +79 -0
  153. package/template/src/components/meet-cancellation-email-template.tsx +120 -0
  154. package/template/src/components/meet-confirmation-email-template.tsx +156 -0
  155. package/template/src/components/meet-update-email-template.tsx +209 -0
  156. package/template/src/components/page-header.tsx +61 -0
  157. package/template/src/components/reset-password-email-template.tsx +79 -0
  158. package/template/src/components/sidebar.tsx +294 -0
  159. package/template/src/components/skeleton.tsx +380 -0
  160. package/template/src/components/ui/commands.tsx +396 -0
  161. package/template/src/components/ui/components.tsx +150 -0
  162. package/template/src/components/ui/theme.tsx +5 -0
  163. package/template/src/components/view-as-banner.tsx +45 -0
  164. package/template/src/components/view-as-modal.tsx +186 -0
  165. package/template/src/contexts/mobile-menu-context.tsx +31 -0
  166. package/template/src/contexts/sidebar-context.tsx +107 -0
  167. package/template/src/contexts/task-reminder-context.tsx +239 -0
  168. package/template/src/contexts/view-as-context.tsx +84 -0
  169. package/template/src/hooks/use-user-role.ts +82 -0
  170. package/template/src/lib/audit-log.ts +45 -0
  171. package/template/src/lib/auth-client.ts +16 -0
  172. package/template/src/lib/auth.ts +35 -0
  173. package/template/src/lib/check-permission.ts +193 -0
  174. package/template/src/lib/contact-duplicate.ts +112 -0
  175. package/template/src/lib/contact-interactions.ts +371 -0
  176. package/template/src/lib/encryption.ts +99 -0
  177. package/template/src/lib/google-calendar.ts +300 -0
  178. package/template/src/lib/google-drive.ts +372 -0
  179. package/template/src/lib/permissions.ts +412 -0
  180. package/template/src/lib/prisma.ts +32 -0
  181. package/template/src/lib/roles.ts +120 -0
  182. package/template/src/lib/template-variables.ts +76 -0
  183. package/template/src/lib/utils.ts +46 -0
  184. package/template/src/lib/workflow-executor.ts +482 -0
  185. package/template/src/proxy.ts +91 -0
  186. package/template/tsconfig.json +34 -0
  187. package/template/vercel.json +8 -0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs-extra");
4
+ const path = require("path");
5
+ const chalk = require("chalk");
6
+ const prompts = require("prompts");
7
+
8
+ async function main() {
9
+ const args = process.argv.slice(2);
10
+ const projectName = args[0];
11
+
12
+ if (!projectName) {
13
+ console.error(chalk.red("❌ Veuillez spécifier un nom de projet"));
14
+ console.log(chalk.yellow("\nUsage: pnpm create crm-tmp@latest mon-crm\n"));
15
+ process.exit(1);
16
+ }
17
+
18
+ const targetDir = path.resolve(process.cwd(), projectName);
19
+
20
+ // Vérifier si le dossier existe déjà
21
+ if (fs.existsSync(targetDir)) {
22
+ const { overwrite } = await prompts({
23
+ type: "confirm",
24
+ name: "overwrite",
25
+ message: `Le dossier "${projectName}" existe déjà. Voulez-vous le remplacer ?`,
26
+ initial: false,
27
+ });
28
+
29
+ if (!overwrite) {
30
+ console.log(chalk.yellow("❌ Opération annulée"));
31
+ process.exit(1);
32
+ }
33
+
34
+ fs.removeSync(targetDir);
35
+ }
36
+
37
+ console.log(chalk.blue(`\n🚀 Création du projet CRM "${projectName}"...\n`));
38
+
39
+ // Copier le template
40
+ const templateDir = path.join(__dirname, "..", "template");
41
+ fs.copySync(templateDir, targetDir);
42
+
43
+ // Lire le package.json du template
44
+ const packageJsonPath = path.join(targetDir, "package.json");
45
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
46
+
47
+ // Mettre à jour le nom du projet
48
+ packageJson.name = projectName;
49
+ packageJson.version = "0.1.0";
50
+
51
+ // Écrire le package.json modifié
52
+ fs.writeFileSync(
53
+ packageJsonPath,
54
+ JSON.stringify(packageJson, null, 2) + "\n"
55
+ );
56
+
57
+ // Créer un fichier .env
58
+ const envExamplePath = path.join(targetDir, ".env");
59
+ if (!fs.existsSync(envExamplePath)) {
60
+ const envExample = `# Database
61
+ DATABASE_URL="" # Supabase Prod
62
+ DIRECT_URL="" # Supabase Migration
63
+
64
+ BETTER_AUTH_SECRET=""
65
+ BETTER_AUTH_URL="http://localhost:3000"
66
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
67
+
68
+ APP_NAME="${projectName}"
69
+
70
+ ENCRYPTION_KEY="" #openssl rand -base64 32
71
+
72
+ GOOGLE_CLIENT_ID=""
73
+ GOOGLE_CLIENT_SECRET=""
74
+ GOOGLE_REDIRECT_URI=""
75
+
76
+ CRON_SECRET="" #openssl rand -base64 32
77
+ `;
78
+ fs.writeFileSync(envExamplePath, envExample);
79
+ }
80
+
81
+ console.log(chalk.green("✅ Projet créé avec succès !\n"));
82
+ console.log(chalk.yellow("📝 Prochaines étapes :\n"));
83
+ console.log(chalk.white(` cd ${projectName}`));
84
+ console.log(chalk.white(" pnpm install"));
85
+ console.log(chalk.white(" # Configurez votre fichier .env"));
86
+ console.log(chalk.white(" # Migrer la base de données et générer le schéma Prisma"));
87
+ console.log(chalk.white(" pnpm dev\n"));
88
+ }
89
+
90
+ main().catch((error) => {
91
+ console.error(chalk.red("❌ Erreur :"), error);
92
+ process.exit(1);
93
+ });
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "create-crm-tmp",
3
+ "version": "1.0.0",
4
+ "description": "Créer un nouveau projet CRM basé sur le template",
5
+ "bin": {
6
+ "create-crm-tmp": "./bin/create-crm-tmp.js"
7
+ },
8
+ "files": [
9
+ "bin",
10
+ "template"
11
+ ],
12
+ "keywords": [
13
+ "crm",
14
+ "template",
15
+ "nextjs",
16
+ "prisma"
17
+ ],
18
+ "author": "Younes – HALL-IA",
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "fs-extra": "^11.2.0",
22
+ "chalk": "^4.1.2",
23
+ "prompts": "^2.4.2"
24
+ }
25
+ }
@@ -0,0 +1,33 @@
1
+ # Dependencies
2
+ node_modules
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Production
7
+ build
8
+ dist
9
+ .next
10
+ out
11
+
12
+ # Misc
13
+ .DS_Store
14
+ *.pem
15
+
16
+ # Debug
17
+ npm-debug.log*
18
+ yarn-debug.log*
19
+ yarn-error.log*
20
+ pnpm-debug.log*
21
+
22
+ # Local env files
23
+ .env*.local
24
+ .env
25
+
26
+ # Vercel
27
+ .vercel
28
+
29
+ # Lock files
30
+ package-lock.json
31
+ pnpm-lock.yaml
32
+ yarn.lock
33
+
@@ -0,0 +1,25 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 100,
6
+ "tabWidth": 2,
7
+ "useTabs": false,
8
+ "arrowParens": "always",
9
+ "bracketSpacing": true,
10
+ "bracketSameLine": false,
11
+ "endOfLine": "lf",
12
+ "proseWrap": "preserve",
13
+ "htmlWhitespaceSensitivity": "ignore",
14
+ "embeddedLanguageFormatting": "auto",
15
+ "plugins": ["prettier-plugin-tailwindcss"],
16
+ "overrides": [
17
+ {
18
+ "files": ["*.md", "*.mdx"],
19
+ "options": {
20
+ "printWidth": 80,
21
+ "proseWrap": "always"
22
+ }
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,173 @@
1
+ # 📊 CRM Template
2
+
3
+ Un CRM moderne, orienté **prospection & suivi commercial**, construit avec **Next.js 16**,
4
+ **Better Auth**, **Prisma**, **PostgreSQL** et une UI inspirée d’un template CRM pro.
5
+
6
+ ## ✨ Fonctionnalités
7
+
8
+ - 🔐 **Authentification sécurisée** avec Better Auth
9
+ - Connexion par email / mot de passe
10
+ - Sessions sécurisées côté serveur
11
+ - Protection des routes via proxy Next.js
12
+ - 👥 **Rôles & permissions**
13
+ - Rôles natifs : USER, ADMIN, MANAGER, COMMERCIAL, TELEPRO, COMPTABLE
14
+ - Rôles personnalisés avec permissions granulaires
15
+ - Gestion des utilisateurs (activation / désactivation, invitation par email)
16
+ - 📊 **Tableau de bord**
17
+ - Vue synthétique de l’activité (contacts, tâches, rendez-vous, etc.)
18
+ - 📇 **Contacts**
19
+ - Vue tableau et cartes façon CRM moderne
20
+ - Recherche, filtres (statut, origine, commercial, télépro…)
21
+ - Tri (statut, commerciaux, dates de création / mise à jour)
22
+ - Import CSV / Excel avec mapping intelligent
23
+ - Export CSV / Excel (contacts + notes + fichiers liés, réservé aux admins)
24
+ - Gestion des statuts & motifs de fermeture
25
+ - 📆 **Agenda**
26
+ - Vues **Mois / Semaine / Jour**
27
+ - Barre temporelle en temps réel
28
+ - Différenciation visuelle des types (tâches, rendez-vous, visio)
29
+ - Filtres par type et priorité
30
+ - ⚙️ **Paramètres**
31
+ - Paramètres généraux (profil, sécurité, informations d’entreprise)
32
+ - Configuration SMTP + signature email
33
+ - Gestion des statuts & motifs de fermeture
34
+ - Intégrations (Google Calendar & Drive, Google Sheets, Meta Lead Ads, Google Ads…)
35
+ - 🤖 **Automatisations (Workflows)**
36
+ - Workflows avec actions chaînées
37
+ - Exécution planifiée via **Vercel Cron**
38
+ - 🎨 **UI moderne**
39
+ - Design type CRM (fond `bg-crms-bg`, cartes blanches, headers structurés)
40
+ - Tailwind CSS v4
41
+ - 📱 Design entièrement responsive
42
+
43
+ ## 🛠️ Stack technique
44
+
45
+ - **Framework**: Next.js 16 (App Router)
46
+ - **React**: React 19
47
+ - **Base de données**: PostgreSQL avec Prisma ORM
48
+ - **Authentification**: Better Auth
49
+ - **Styling**: Tailwind CSS v4
50
+ - **Langage**: TypeScript
51
+ - **Gestionnaire de paquets**: pnpm
52
+
53
+ ## 🚀 Installation
54
+
55
+ 1. **Cloner le projet**
56
+
57
+ ```bash
58
+ git clone <votre-repo>
59
+ cd crm-template
60
+ ```
61
+
62
+ 2. **Installer les dépendances**
63
+
64
+ ```bash
65
+ pnpm install
66
+ ```
67
+
68
+ 3. **Configurer les variables d'environnement**
69
+
70
+ Créez un fichier `.env` à la racine du projet :
71
+
72
+ ```env
73
+ # Database
74
+ DATABASE_URL="postgresql://postgres:password@localhost:5432/crm_db"
75
+
76
+ # Better Auth (générer avec: openssl rand -base64 32)
77
+ BETTER_AUTH_SECRET="votre-clé-secrète-minimum-32-caractères"
78
+ BETTER_AUTH_URL="http://localhost:3000"
79
+
80
+ # Application
81
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
82
+ NODE_ENV="development"
83
+ ```
84
+
85
+ 4. **Créer la base de données**
86
+
87
+ ```bash
88
+ createdb crm_db
89
+ # Ou: psql -U postgres -c "CREATE DATABASE crm_db;"
90
+ ```
91
+
92
+ 5. **Appliquer les migrations**
93
+
94
+ ```bash
95
+ pnpm prisma migrate deploy
96
+ ```
97
+
98
+ 6. **Lancer le serveur de développement**
99
+
100
+ ```bash
101
+ pnpm dev
102
+ ```
103
+
104
+ Ouvrez [http://localhost:3000](http://localhost:3000) pour voir l'application.
105
+
106
+ 7. **Créer votre premier admin**
107
+
108
+ ```bash
109
+ # Ouvrir Prisma Studio
110
+ pnpm prisma studio
111
+
112
+ # Modifier le champ "role" de votre utilisateur en "ADMIN"
113
+ ```
114
+
115
+ ## 📁 Structure du projet
116
+
117
+ ```
118
+ src/
119
+ ├── app/
120
+ │ ├── (auth)/ # Groupe de routes d'authentification
121
+ │ ├── (dashboard)/ # Espace connecté (protégé)
122
+ │ │ ├── dashboard/ # Tableau de bord
123
+ │ │ ├── contacts/ # Gestion des contacts
124
+ │ │ ├── agenda/ # Agenda (mois / semaine / jour)
125
+ │ │ ├── automatisation/ # Workflows / automatisations
126
+ │ │ ├── templates/ # Templates d’emails
127
+ │ │ ├── settings/ # Paramètres (profil, entreprise, intégrations…)
128
+ │ │ ├── users/ # Gestion des utilisateurs & rôles (admin)
129
+ │ │ └── layout.tsx # Layout avec sidebar
130
+ │ ├── api/ # API (contacts, workflows, intégrations, users, etc.)
131
+ │ └── page.tsx # Page d'accueil (redirection)
132
+ ├── components/ # Composants UI (sidebar, headers, skeletons…)
133
+ ├── lib/ # Auth, Prisma, rôles, intégrations Google, workflows…
134
+ └── proxy.ts # Protection des routes (proxy)
135
+ ```
136
+
137
+ ## 🔒 Protection & rôles
138
+
139
+ - **Proxy Next.js** (`src/proxy.ts`) pour protéger les routes côté serveur :
140
+ - Pages dans `(dashboard)/` automatiquement protégées
141
+ - Redirection vers `/signin` si non authentifié
142
+ - Redirection vers le dashboard si déjà connecté sur les pages d’auth
143
+ - **Rôles & permissions** :
144
+ - Rôles techniques + rôles personnalisés configurables via l’interface
145
+ - Vérification des permissions côté API (ex : `users.view`, `users.manage_roles`, intégrations…)
146
+ - Certaines sections (informations d’entreprise, paramètres d’application / système, intégrations, export contacts) sont réservées aux administrateurs
147
+
148
+ ## 🎨 Personnalisation
149
+
150
+ ### Ajouter une nouvelle page protégée
151
+
152
+ 1. Créez votre page dans `src/app/(dashboard)/ma-page/page.tsx`
153
+ 2. Ajoutez-la dans la navigation (`src/components/sidebar.tsx`)
154
+ 3. (Optionnel) Protégez-la par rôle dans `src/proxy.ts`
155
+
156
+ ### Modifier le thème
157
+
158
+ Les couleurs principales sont configurées avec Tailwind. Modifiez les classes
159
+ dans les composants pour personnaliser le thème.
160
+
161
+ ## 📝 Scripts disponibles
162
+
163
+ ```bash
164
+ pnpm dev # Lancer le serveur de développement
165
+ pnpm build # Build de production
166
+ pnpm start # Lancer le serveur de production
167
+ pnpm lint # Linter le code
168
+ pnpm format # Formater le code avec Prettier
169
+ ```
170
+
171
+ ## 📄 Licence
172
+
173
+ MIT
@@ -0,0 +1,18 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ const eslintConfig = defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+ // Override default ignores of eslint-config-next.
9
+ globalIgnores([
10
+ // Default ignores of eslint-config-next:
11
+ ".next/**",
12
+ "out/**",
13
+ "build/**",
14
+ "next-env.d.ts",
15
+ ]),
16
+ ]);
17
+
18
+ export default eslintConfig;
@@ -0,0 +1,11 @@
1
+ Civilité,Prénom,Nom,Téléphone,Téléphone secondaire,Email,Adresse,Ville,Code postal,Origine
2
+ M,Jean,Dupont,0612345678,0698765432,jean.dupont@example.com,123 Rue de la République,Paris,75001,Google Ads
3
+ MME,Marie,Martin,0623456789,,marie.martin@example.com,45 Avenue des Champs,Paris,75008,Facebook
4
+ M,Pierre,Bernard,0634567890,0645678901,pierre.bernard@example.com,78 Boulevard Saint-Germain,Lyon,69001,LinkedIn
5
+ MME,Sophie,Dubois,0645678901,,sophie.dubois@example.com,12 Place Bellecour,Lyon,69002,Recommandation
6
+ M,Thomas,Moreau,0656789012,0667890123,thomas.moreau@example.com,56 Rue de la Paix,Marseille,13001,Google Ads
7
+ MME,Julie,Lefebvre,0667890123,,julie.lefebvre@example.com,89 Cours Mirabeau,Marseille,13002,Facebook
8
+ M,Michel,Petit,0678901234,,michel.petit@example.com,34 Rue du Commerce,Toulouse,31000,LinkedIn
9
+ MME,Isabelle,Roux,0689012345,0690123456,isabelle.roux@example.com,67 Avenue Jean Jaurès,Toulouse,31001,Recommandation
10
+ M,David,Simon,0690123456,,david.simon@example.com,23 Place du Capitole,Bordeaux,33000,Google Ads
11
+ MME,Claire,Laurent,0612345679,,claire.laurent@example.com,45 Rue Sainte-Catherine,Bordeaux,33001,Facebook
@@ -0,0 +1,8 @@
1
+ import type { NextConfig } from 'next';
2
+
3
+ const nextConfig: NextConfig = {
4
+ /* config options here */
5
+ reactCompiler: true,
6
+ };
7
+
8
+ export default nextConfig;
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "crm-template",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "postinstall": "prisma generate",
10
+ "lint": "eslint",
11
+ "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,md}\"",
12
+ "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,css,md}\""
13
+ },
14
+ "dependencies": {
15
+ "@hookform/resolvers": "^5.2.2",
16
+ "@lexical/html": "^0.38.2",
17
+ "@lexical/list": "^0.38.2",
18
+ "@lexical/markdown": "^0.38.2",
19
+ "@lexical/react": "^0.38.2",
20
+ "@lexical/rich-text": "^0.38.2",
21
+ "@lexical/selection": "^0.38.2",
22
+ "@lexical/utils": "^0.38.2",
23
+ "@lexkit/editor": "^0.0.38",
24
+ "@prisma/adapter-pg": "^7.1.0",
25
+ "@prisma/client": "^7.1.0",
26
+ "@react-email/render": "^2.0.0",
27
+ "bcryptjs": "^3.0.3",
28
+ "better-auth": "^1.4.6",
29
+ "clsx": "^2.1.1",
30
+ "dotenv": "^17.2.3",
31
+ "iron-session": "^8.0.4",
32
+ "lexical": "^0.38.2",
33
+ "lucide-react": "^0.555.0",
34
+ "next": "16.0.10",
35
+ "nodemailer": "^7.0.11",
36
+ "papaparse": "^5.5.3",
37
+ "pg": "^8.16.3",
38
+ "react": "19.2.3",
39
+ "react-dom": "19.2.3",
40
+ "react-hook-form": "^7.68.0",
41
+ "recharts": "^2.15.4",
42
+ "tailwind-merge": "^3.4.0",
43
+ "xlsx": "^0.18.5",
44
+ "zod": "^4.1.13"
45
+ },
46
+ "devDependencies": {
47
+ "@tailwindcss/postcss": "^4.1.18",
48
+ "@types/node": "^20.19.26",
49
+ "@types/nodemailer": "^7.0.4",
50
+ "@types/papaparse": "^5.5.1",
51
+ "@types/pg": "^8.16.0",
52
+ "@types/react": "^19.2.7",
53
+ "@types/react-dom": "^19.2.3",
54
+ "babel-plugin-react-compiler": "1.0.0",
55
+ "eslint": "^9.39.1",
56
+ "eslint-config-next": "16.0.7",
57
+ "prettier": "^3.7.4",
58
+ "prettier-plugin-tailwindcss": "^0.7.2",
59
+ "prisma": "^7.1.0",
60
+ "tailwindcss": "^4.1.18",
61
+ "tsx": "^4.21.0",
62
+ "typescript": "^5.9.3"
63
+ }
64
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,78 @@
1
+ -- CreateTable
2
+ CREATE TABLE "user" (
3
+ "id" TEXT NOT NULL,
4
+ "name" TEXT NOT NULL,
5
+ "email" TEXT NOT NULL,
6
+ "emailVerified" BOOLEAN NOT NULL DEFAULT false,
7
+ "image" TEXT,
8
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ "updatedAt" TIMESTAMP(3) NOT NULL,
10
+
11
+ CONSTRAINT "user_pkey" PRIMARY KEY ("id")
12
+ );
13
+
14
+ -- CreateTable
15
+ CREATE TABLE "session" (
16
+ "id" TEXT NOT NULL,
17
+ "expiresAt" TIMESTAMP(3) NOT NULL,
18
+ "token" TEXT NOT NULL,
19
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
20
+ "updatedAt" TIMESTAMP(3) NOT NULL,
21
+ "ipAddress" TEXT,
22
+ "userAgent" TEXT,
23
+ "userId" TEXT NOT NULL,
24
+
25
+ CONSTRAINT "session_pkey" PRIMARY KEY ("id")
26
+ );
27
+
28
+ -- CreateTable
29
+ CREATE TABLE "account" (
30
+ "id" TEXT NOT NULL,
31
+ "accountId" TEXT NOT NULL,
32
+ "providerId" TEXT NOT NULL,
33
+ "userId" TEXT NOT NULL,
34
+ "accessToken" TEXT,
35
+ "refreshToken" TEXT,
36
+ "idToken" TEXT,
37
+ "accessTokenExpiresAt" TIMESTAMP(3),
38
+ "refreshTokenExpiresAt" TIMESTAMP(3),
39
+ "scope" TEXT,
40
+ "password" TEXT,
41
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
42
+ "updatedAt" TIMESTAMP(3) NOT NULL,
43
+
44
+ CONSTRAINT "account_pkey" PRIMARY KEY ("id")
45
+ );
46
+
47
+ -- CreateTable
48
+ CREATE TABLE "verification" (
49
+ "id" TEXT NOT NULL,
50
+ "identifier" TEXT NOT NULL,
51
+ "value" TEXT NOT NULL,
52
+ "expiresAt" TIMESTAMP(3) NOT NULL,
53
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
54
+ "updatedAt" TIMESTAMP(3) NOT NULL,
55
+
56
+ CONSTRAINT "verification_pkey" PRIMARY KEY ("id")
57
+ );
58
+
59
+ -- CreateIndex
60
+ CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
61
+
62
+ -- CreateIndex
63
+ CREATE INDEX "session_userId_idx" ON "session"("userId");
64
+
65
+ -- CreateIndex
66
+ CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
67
+
68
+ -- CreateIndex
69
+ CREATE INDEX "account_userId_idx" ON "account"("userId");
70
+
71
+ -- CreateIndex
72
+ CREATE INDEX "verification_identifier_idx" ON "verification"("identifier");
73
+
74
+ -- AddForeignKey
75
+ ALTER TABLE "session" ADD CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
76
+
77
+ -- AddForeignKey
78
+ ALTER TABLE "account" ADD CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
1
+ -- CreateEnum
2
+ CREATE TYPE "Role" AS ENUM ('USER', 'ADMIN');
3
+
4
+ -- AlterTable
5
+ ALTER TABLE "user" ADD COLUMN "role" "Role" NOT NULL DEFAULT 'USER';
@@ -0,0 +1,19 @@
1
+ -- CreateTable
2
+ CREATE TABLE "company" (
3
+ "id" TEXT NOT NULL DEFAULT 'company',
4
+ "name" TEXT,
5
+ "address" TEXT,
6
+ "city" TEXT,
7
+ "postalCode" TEXT,
8
+ "country" TEXT,
9
+ "phone" TEXT,
10
+ "email" TEXT,
11
+ "website" TEXT,
12
+ "siret" TEXT,
13
+ "vatNumber" TEXT,
14
+ "logo" TEXT,
15
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
16
+ "updatedAt" TIMESTAMP(3) NOT NULL,
17
+
18
+ CONSTRAINT "company_pkey" PRIMARY KEY ("id")
19
+ );
@@ -0,0 +1,22 @@
1
+ -- CreateTable
2
+ CREATE TABLE "smtp_config" (
3
+ "id" TEXT NOT NULL,
4
+ "userId" TEXT NOT NULL,
5
+ "host" TEXT NOT NULL,
6
+ "port" INTEGER NOT NULL,
7
+ "secure" BOOLEAN NOT NULL DEFAULT false,
8
+ "username" TEXT NOT NULL,
9
+ "password" TEXT NOT NULL,
10
+ "fromEmail" TEXT NOT NULL,
11
+ "fromName" TEXT,
12
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ "updatedAt" TIMESTAMP(3) NOT NULL,
14
+
15
+ CONSTRAINT "smtp_config_pkey" PRIMARY KEY ("id")
16
+ );
17
+
18
+ -- CreateIndex
19
+ CREATE UNIQUE INDEX "smtp_config_userId_key" ON "smtp_config"("userId");
20
+
21
+ -- AddForeignKey
22
+ ALTER TABLE "smtp_config" ADD CONSTRAINT "smtp_config_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,23 @@
1
+ -- CreateTable
2
+ CREATE TABLE "status" (
3
+ "id" TEXT NOT NULL,
4
+ "name" TEXT NOT NULL,
5
+ "color" TEXT NOT NULL,
6
+ "order" INTEGER NOT NULL DEFAULT 0,
7
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8
+ "updatedAt" TIMESTAMP(3) NOT NULL,
9
+
10
+ CONSTRAINT "status_pkey" PRIMARY KEY ("id")
11
+ );
12
+
13
+ -- CreateIndex
14
+ CREATE UNIQUE INDEX "status_name_key" ON "status"("name");
15
+
16
+ -- Insert default statuses (ignore if already exist)
17
+ INSERT INTO "status" ("id", "name", "color", "order", "createdAt", "updatedAt") VALUES
18
+ (gen_random_uuid()::text, 'Nouveau', '#3B82F6', 1, NOW(), NOW()),
19
+ (gen_random_uuid()::text, 'À rappeler', '#F59E0B', 2, NOW(), NOW()),
20
+ (gen_random_uuid()::text, 'RDV pris', '#8B5CF6', 3, NOW(), NOW()),
21
+ (gen_random_uuid()::text, 'Converti (contrat signé)', '#10B981', 4, NOW(), NOW()),
22
+ (gen_random_uuid()::text, 'Perdu', '#EF4444', 5, NOW(), NOW())
23
+ ON CONFLICT ("name") DO NOTHING;