create-crm-tmp 1.1.3 → 2.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 +56 -35
- package/package.json +1 -1
- package/template/.prettierignore +2 -0
- package/template/README.md +230 -115
- package/template/components.json +22 -0
- package/template/eslint.config.mjs +13 -0
- package/template/exemple-contacts.csv +54 -0
- package/template/next.config.ts +41 -1
- package/template/package.json +63 -15
- package/template/prisma/migrations/20260318095700_init_db/migration.sql +978 -0
- package/template/prisma/schema.prisma +311 -67
- package/template/src/app/(auth)/invite/[token]/page.tsx +28 -29
- package/template/src/app/(auth)/layout.tsx +1 -1
- package/template/src/app/(auth)/reset-password/complete/page.tsx +21 -27
- package/template/src/app/(auth)/reset-password/page.tsx +14 -10
- package/template/src/app/(auth)/reset-password/verify/page.tsx +14 -10
- package/template/src/app/(auth)/signin/page.tsx +34 -23
- package/template/src/app/(dashboard)/agenda/page.tsx +3655 -2357
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +609 -338
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
- package/template/src/app/(dashboard)/automatisation/page.tsx +463 -186
- package/template/src/app/(dashboard)/closing/page.tsx +517 -469
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6151 -4210
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1702 -0
- package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +4124 -2130
- package/template/src/app/(dashboard)/dashboard/page.tsx +119 -105
- package/template/src/app/(dashboard)/dev/page.tsx +1291 -0
- package/template/src/app/(dashboard)/error.tsx +37 -0
- package/template/src/app/(dashboard)/layout.tsx +6 -2
- package/template/src/app/(dashboard)/loading.tsx +5 -0
- package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
- package/template/src/app/(dashboard)/settings/page.tsx +1773 -3362
- package/template/src/app/(dashboard)/templates/page.tsx +504 -303
- package/template/src/app/(dashboard)/users/list/page.tsx +364 -355
- package/template/src/app/(dashboard)/users/page.tsx +279 -310
- package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
- package/template/src/app/(dashboard)/users/roles/page.tsx +169 -140
- package/template/src/app/api/agenda/google-events/route.ts +92 -0
- package/template/src/app/api/audit-logs/route.ts +1 -1
- package/template/src/app/api/auth/check-active/route.ts +3 -2
- package/template/src/app/api/auth/google/callback/route.ts +8 -5
- package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
- package/template/src/app/api/auth/google/route.ts +2 -1
- package/template/src/app/api/auth/google/status/route.ts +7 -31
- package/template/src/app/api/companies/[id]/activities/route.ts +129 -0
- package/template/src/app/api/companies/[id]/route.ts +194 -0
- package/template/src/app/api/companies/export/route.ts +206 -0
- package/template/src/app/api/companies/route.ts +196 -0
- package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
- package/template/src/app/api/contact-views/[id]/route.ts +197 -0
- package/template/src/app/api/contact-views/route.ts +146 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +55 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +20 -48
- package/template/src/app/api/contacts/[id]/files/route.ts +125 -186
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +27 -1
- package/template/src/app/api/contacts/[id]/interactions/route.ts +45 -8
- package/template/src/app/api/contacts/[id]/kyc/route.ts +81 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +55 -29
- package/template/src/app/api/contacts/[id]/route.ts +184 -21
- package/template/src/app/api/contacts/[id]/send-email/route.ts +33 -11
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +67 -0
- package/template/src/app/api/contacts/export/route.ts +22 -31
- package/template/src/app/api/contacts/import/route.ts +77 -44
- package/template/src/app/api/contacts/import-preview/route.ts +139 -0
- package/template/src/app/api/contacts/origins/route.ts +63 -0
- package/template/src/app/api/contacts/route.ts +322 -57
- package/template/src/app/api/cron/cleanup-editor-images/route.ts +166 -0
- package/template/src/app/api/dashboard/stats/route.ts +9 -292
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -3
- package/template/src/app/api/dashboard/widgets/route.ts +19 -19
- package/template/src/app/api/dev/reminders/test/route.ts +114 -0
- package/template/src/app/api/editor/upload-image/route.ts +61 -0
- package/template/src/app/api/integrations/google-sheet/jobs/[jobId]/route.ts +47 -0
- package/template/src/app/api/integrations/google-sheet/jobs/usage/route.ts +50 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +28 -542
- package/template/src/app/api/invite/complete/route.ts +20 -23
- package/template/src/app/api/jobs/google-sheet/process/route.ts +84 -0
- package/template/src/app/api/jobs/google-sheet/schedule/route.ts +50 -0
- package/template/src/app/api/reminders/clear/route.ts +120 -0
- package/template/src/app/api/reminders/clear/undo/route.ts +112 -0
- package/template/src/app/api/reminders/route.ts +165 -39
- package/template/src/app/api/reminders/state/route.ts +164 -0
- package/template/src/app/api/reset-password/complete/route.ts +11 -13
- package/template/src/app/api/reset-password/request/route.ts +1 -1
- package/template/src/app/api/reset-password/verify/route.ts +1 -1
- package/template/src/app/api/send/route.ts +25 -47
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
- package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
- package/template/src/app/api/settings/company/route.ts +19 -26
- package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-ads/route.ts +34 -23
- package/template/src/app/api/settings/google-calendar/calendars/route.ts +97 -0
- package/template/src/app/api/settings/google-calendar/route.ts +124 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +48 -23
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +56 -32
- package/template/src/app/api/settings/google-sheet/preview/route.ts +110 -0
- package/template/src/app/api/settings/google-sheet/route.ts +34 -23
- package/template/src/app/api/settings/integrations/logs/route.ts +93 -0
- package/template/src/app/api/settings/integrations/notifications/route.ts +67 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -24
- package/template/src/app/api/settings/meta-leads/route.ts +34 -25
- package/template/src/app/api/settings/smtp/route.ts +53 -6
- package/template/src/app/api/settings/statuses/[id]/route.ts +29 -32
- package/template/src/app/api/settings/statuses/route.ts +24 -22
- package/template/src/app/api/statuses/route.ts +2 -5
- package/template/src/app/api/tasks/[id]/attendees/route.ts +36 -13
- package/template/src/app/api/tasks/[id]/route.ts +357 -145
- package/template/src/app/api/tasks/meet/route.ts +37 -26
- package/template/src/app/api/tasks/route.ts +201 -96
- package/template/src/app/api/templates/[id]/route.ts +22 -13
- package/template/src/app/api/templates/route.ts +22 -5
- package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
- package/template/src/app/api/users/[id]/route.ts +22 -16
- package/template/src/app/api/users/commercials/route.ts +38 -0
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/users/list/route.ts +57 -19
- package/template/src/app/api/users/route.ts +89 -34
- package/template/src/app/api/webhooks/google-ads/route.ts +40 -1
- package/template/src/app/api/webhooks/meta-leads/route.ts +38 -1
- package/template/src/app/api/workflows/[id]/route.ts +29 -6
- package/template/src/app/api/workflows/process/route.ts +505 -170
- package/template/src/app/api/workflows/route.ts +42 -4
- package/template/src/app/globals.css +512 -32
- package/template/src/app/layout.tsx +28 -9
- package/template/src/app/page.tsx +37 -7
- package/template/src/components/address-autocomplete.tsx +233 -0
- package/template/src/components/config-error-alert.tsx +46 -0
- package/template/src/components/contacts/filter-bar.tsx +190 -0
- package/template/src/components/contacts/filter-builder.tsx +574 -0
- package/template/src/components/contacts/save-view-dialog.tsx +160 -0
- package/template/src/components/contacts/views-tab-bar.tsx +449 -0
- package/template/src/components/dashboard/activity-chart.tsx +6 -1
- package/template/src/components/dashboard/add-widget-dialog.tsx +13 -17
- package/template/src/components/dashboard/color-picker.tsx +7 -8
- package/template/src/components/dashboard/recent-activity.tsx +2 -5
- package/template/src/components/dashboard/stat-card.tsx +1 -3
- package/template/src/components/dashboard/status-distribution-chart.tsx +0 -1
- package/template/src/components/dashboard/top-contacts-list.tsx +7 -13
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +2 -5
- package/template/src/components/dashboard/widget-wrapper.tsx +3 -6
- package/template/src/components/date-picker.tsx +399 -0
- package/template/src/components/editor/upload-editor-image.ts +42 -0
- package/template/src/components/editor.tsx +188 -35
- package/template/src/components/email-template.tsx +4 -2
- package/template/src/components/global-search.tsx +360 -0
- package/template/src/components/header.tsx +200 -107
- package/template/src/components/inactive-account-guard.tsx +58 -0
- package/template/src/components/integration-notifications-listener.tsx +12 -0
- package/template/src/components/invitation-email-template.tsx +4 -2
- package/template/src/components/lazy-editor.tsx +11 -0
- package/template/src/components/meet-cancellation-email-template.tsx +11 -3
- package/template/src/components/meet-confirmation-email-template.tsx +10 -3
- package/template/src/components/meet-update-email-template.tsx +10 -3
- package/template/src/components/page-header.tsx +19 -15
- package/template/src/components/protected-page.tsx +94 -0
- package/template/src/components/reset-password-email-template.tsx +4 -2
- package/template/src/components/settings/integrations/GoogleAdsIntegration.tsx +428 -0
- package/template/src/components/settings/integrations/GoogleSheetConfigMonitoringModal.tsx +680 -0
- package/template/src/components/settings/integrations/GoogleSheetIntegration.tsx +809 -0
- package/template/src/components/settings/integrations/ImportResultDialog.tsx +124 -0
- package/template/src/components/settings/integrations/IntegrationLogPanel.tsx +57 -0
- package/template/src/components/settings/integrations/IntegrationLogsTable.tsx +186 -0
- package/template/src/components/settings/integrations/MetaLeadIntegration.tsx +451 -0
- package/template/src/components/sidebar.tsx +117 -100
- package/template/src/components/skeleton.tsx +128 -45
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +139 -0
- package/template/src/components/ui/button.tsx +71 -0
- package/template/src/components/ui/components.tsx +1 -1
- package/template/src/components/ui/date-picker.tsx +422 -0
- package/template/src/components/ui/datetime-picker.tsx +338 -0
- package/template/src/components/ui/status-select.tsx +271 -0
- package/template/src/components/ui/tooltip.tsx +37 -0
- package/template/src/components/view-as-banner.tsx +1 -1
- package/template/src/components/view-as-modal.tsx +30 -19
- package/template/src/config/nav-pages.ts +108 -0
- package/template/src/contexts/app-toast-context.tsx +362 -0
- package/template/src/contexts/dashboard-theme-context.tsx +2 -7
- package/template/src/contexts/sidebar-context.tsx +27 -53
- package/template/src/contexts/task-reminder-context.tsx +134 -160
- package/template/src/contexts/view-as-context.tsx +32 -10
- package/template/src/hooks/use-alert.tsx +65 -0
- package/template/src/hooks/use-confirm.tsx +87 -0
- package/template/src/hooks/use-contact-views.ts +140 -0
- package/template/src/hooks/use-contacts.ts +69 -0
- package/template/src/hooks/use-fetch.ts +17 -0
- package/template/src/hooks/use-focus-trap.ts +73 -0
- package/template/src/hooks/use-statuses.ts +22 -0
- package/template/src/hooks/useIntegrationNotifications.ts +49 -0
- package/template/src/lib/address-api.ts +155 -0
- package/template/src/lib/auth.ts +8 -1
- package/template/src/lib/cache.ts +73 -0
- package/template/src/lib/check-permission.ts +12 -177
- package/template/src/lib/config-links.ts +14 -0
- package/template/src/lib/contact-duplicate.ts +79 -61
- package/template/src/lib/contact-interactions.ts +24 -22
- package/template/src/lib/contact-view-filters.ts +301 -0
- package/template/src/lib/contacts-list-url.ts +190 -0
- package/template/src/lib/dashboard-stats.ts +282 -0
- package/template/src/lib/dashboard-themes.ts +0 -5
- package/template/src/lib/date-utils.ts +176 -0
- package/template/src/lib/default-widgets.ts +0 -2
- package/template/src/lib/editor-html-image-dimensions.ts +172 -0
- package/template/src/lib/editor-image-limits.ts +19 -0
- package/template/src/lib/email-html-sanitize.ts +19 -0
- package/template/src/lib/encryption.ts +9 -6
- package/template/src/lib/fr-geography.ts +192 -0
- package/template/src/lib/get-auth-user.ts +25 -0
- package/template/src/lib/google-calendar-agenda.ts +201 -0
- package/template/src/lib/google-calendar.ts +309 -17
- package/template/src/lib/google-fetch.ts +63 -0
- package/template/src/lib/google-sheet-sync-jobs.ts +96 -0
- package/template/src/lib/google-sheet-sync-runner.ts +514 -0
- package/template/src/lib/integration-import-log.ts +21 -0
- package/template/src/lib/local-storage.ts +34 -0
- package/template/src/lib/permissions.ts +268 -40
- package/template/src/lib/prisma.ts +15 -12
- package/template/src/lib/qstash.ts +65 -0
- package/template/src/lib/reminder-state-server.ts +80 -0
- package/template/src/lib/reminder-state.ts +29 -0
- package/template/src/lib/roles.ts +12 -15
- package/template/src/lib/supabase-storage.ts +113 -0
- package/template/src/lib/template-variables.ts +204 -29
- package/template/src/lib/utils.ts +71 -11
- package/template/src/lib/widget-registry.ts +0 -4
- package/template/src/lib/workflow-executor.ts +391 -228
- package/template/src/proxy.ts +35 -73
- package/template/src/types/contact-views.ts +351 -0
- package/template/vercel.json +5 -0
- package/template/WORKFLOWS_CRON.md +0 -185
- package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
- package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
- package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
- package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
- package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
- package/template/prisma/migrations/20260226093949_fix_cascade_on_user_delete/migration.sql +0 -69
- package/template/src/app/(dashboard)/users/layout.tsx +0 -30
- package/template/src/lib/google-drive.ts +0 -380
package/bin/create-crm-tmp.js
CHANGED
|
@@ -10,7 +10,7 @@ async function main() {
|
|
|
10
10
|
const projectName = args[0];
|
|
11
11
|
|
|
12
12
|
if (!projectName) {
|
|
13
|
-
console.error(chalk.red("
|
|
13
|
+
console.error(chalk.red("Veuillez spécifier un nom de projet"));
|
|
14
14
|
console.log(chalk.yellow("\nUsage: pnpm create crm-tmp@latest mon-crm\n"));
|
|
15
15
|
process.exit(1);
|
|
16
16
|
}
|
|
@@ -27,14 +27,14 @@ async function main() {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
if (!overwrite) {
|
|
30
|
-
console.log(chalk.yellow("
|
|
30
|
+
console.log(chalk.yellow("Opération annulée"));
|
|
31
31
|
process.exit(1);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
fs.removeSync(targetDir);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
console.log(chalk.blue(`\
|
|
37
|
+
console.log(chalk.blue(`\nCréation du projet CRM "${projectName}"...\n`));
|
|
38
38
|
|
|
39
39
|
// Copier le template
|
|
40
40
|
const templateDir = path.join(__dirname, "..", "template");
|
|
@@ -54,39 +54,57 @@ async function main() {
|
|
|
54
54
|
JSON.stringify(packageJson, null, 2) + "\n"
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
+
// Formater le nom du projet pour APP_NAME
|
|
58
|
+
const appName = projectName
|
|
59
|
+
.replace(/[-_]+/g, " ")
|
|
60
|
+
.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase())
|
|
61
|
+
.trim();
|
|
62
|
+
|
|
57
63
|
// Créer un fichier .env
|
|
58
|
-
const
|
|
59
|
-
if (!fs.existsSync(
|
|
60
|
-
const
|
|
61
|
-
DATABASE_URL="" # Supabase
|
|
62
|
-
DIRECT_URL="" # Supabase
|
|
64
|
+
const envPath = path.join(targetDir, ".env");
|
|
65
|
+
if (!fs.existsSync(envPath)) {
|
|
66
|
+
const envContent = `# Database (Supabase PostgreSQL)
|
|
67
|
+
DATABASE_URL="" # Supabase pooled connection string (Transaction mode)
|
|
68
|
+
DIRECT_URL="" # Supabase direct connection string (pour les migrations Prisma)
|
|
63
69
|
|
|
70
|
+
# Authentification (Better Auth)
|
|
64
71
|
BETTER_AUTH_SECRET="" # openssl rand -base64 32
|
|
65
72
|
BETTER_AUTH_URL="http://localhost:3000"
|
|
66
73
|
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
67
74
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.replaceAll(/([a-z])([A-Z])/g, "$1 $2")
|
|
71
|
-
.replaceAll(/(^\w|\s\w)/g, (m) => m.toUpperCase())}"
|
|
75
|
+
# Application
|
|
76
|
+
APP_NAME="${appName}"
|
|
72
77
|
|
|
78
|
+
# Chiffrement (SMTP passwords, etc.)
|
|
73
79
|
ENCRYPTION_KEY="" # openssl rand -base64 32
|
|
74
80
|
|
|
75
|
-
#
|
|
81
|
+
# Google Cloud APIs (Calendar, Sheets, Drive)
|
|
82
|
+
# Voir README.md > Guide Google Cloud pour la configuration
|
|
76
83
|
GOOGLE_CLIENT_ID=""
|
|
77
84
|
GOOGLE_CLIENT_SECRET=""
|
|
78
85
|
GOOGLE_REDIRECT_URI="http://localhost:3000/api/auth/google/callback"
|
|
79
86
|
|
|
87
|
+
# Vercel Cron (authentification des jobs planifiés)
|
|
80
88
|
CRON_SECRET="" # openssl rand -base64 32
|
|
89
|
+
|
|
90
|
+
# QStash (Upstash) - Traitement asynchrone des jobs (Google Sheets sync)
|
|
91
|
+
# Voir README.md > Guide QStash pour la configuration
|
|
92
|
+
QSTASH_TOKEN=""
|
|
93
|
+
QSTASH_CURRENT_SIGNING_KEY=""
|
|
94
|
+
QSTASH_NEXT_SIGNING_KEY=""
|
|
95
|
+
|
|
96
|
+
# Supabase Storage - Upload de fichiers (contacts, images éditeur)
|
|
97
|
+
# Voir README.md > Guide Supabase Storage pour la configuration
|
|
98
|
+
NEXT_PUBLIC_SUPABASE_URL=""
|
|
99
|
+
SUPABASE_SERVICE_ROLE_KEY=""
|
|
81
100
|
`;
|
|
82
|
-
fs.writeFileSync(
|
|
101
|
+
fs.writeFileSync(envPath, envContent);
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# dependencies
|
|
104
|
+
// Créer un fichier .gitignore
|
|
105
|
+
const gitIgnorePath = path.join(targetDir, ".gitignore");
|
|
106
|
+
if (!fs.existsSync(gitIgnorePath)) {
|
|
107
|
+
const gitIgnore = `# dependencies
|
|
90
108
|
/node_modules
|
|
91
109
|
/.pnp
|
|
92
110
|
.pnp.*
|
|
@@ -116,7 +134,7 @@ yarn-debug.log*
|
|
|
116
134
|
yarn-error.log*
|
|
117
135
|
.pnpm-debug.log*
|
|
118
136
|
|
|
119
|
-
# env files
|
|
137
|
+
# env files
|
|
120
138
|
.env*
|
|
121
139
|
|
|
122
140
|
# vercel
|
|
@@ -126,29 +144,32 @@ yarn-error.log*
|
|
|
126
144
|
*.tsbuildinfo
|
|
127
145
|
next-env.d.ts
|
|
128
146
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/src/generated/prisma
|
|
132
|
-
|
|
147
|
+
# prisma generated client
|
|
133
148
|
/generated/prisma
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
fs.writeFileSync(gitIgnoreExemplePath, gitIgnore);
|
|
149
|
+
/src/generated/prisma
|
|
150
|
+
`;
|
|
151
|
+
fs.writeFileSync(gitIgnorePath, gitIgnore);
|
|
138
152
|
}
|
|
139
153
|
|
|
140
|
-
console.log(chalk.green("
|
|
141
|
-
console.log(chalk.yellow("
|
|
154
|
+
console.log(chalk.green("Projet créé avec succès !\n"));
|
|
155
|
+
console.log(chalk.yellow("Prochaines étapes :\n"));
|
|
142
156
|
console.log(chalk.white(` cd ${projectName}`));
|
|
143
157
|
console.log(chalk.white(" pnpm install"));
|
|
144
|
-
console.log(chalk.white("
|
|
145
|
-
console.log(
|
|
146
|
-
|
|
147
|
-
);
|
|
158
|
+
console.log(chalk.white(""));
|
|
159
|
+
console.log(chalk.white(" # Configurez votre fichier .env (voir README.md)"));
|
|
160
|
+
console.log(chalk.white(" # Services à configurer :"));
|
|
161
|
+
console.log(chalk.white(" # - Supabase (base de données + storage)"));
|
|
162
|
+
console.log(chalk.white(" # - Google Cloud (Calendar, Sheets, Drive APIs)"));
|
|
163
|
+
console.log(chalk.white(" # - Upstash QStash (jobs asynchrones)"));
|
|
164
|
+
console.log(chalk.white(""));
|
|
165
|
+
console.log(chalk.white(" # Migrer la base de données"));
|
|
166
|
+
console.log(chalk.white(" pnpm db:migrate"));
|
|
167
|
+
console.log(chalk.white(""));
|
|
168
|
+
console.log(chalk.white(" # Lancer le serveur de développement"));
|
|
148
169
|
console.log(chalk.white(" pnpm dev\n"));
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
main().catch((error) => {
|
|
152
|
-
console.error(chalk.red("
|
|
173
|
+
console.error(chalk.red("Erreur :"), error);
|
|
153
174
|
process.exit(1);
|
|
154
175
|
});
|
package/package.json
CHANGED
package/template/.prettierignore
CHANGED
package/template/README.md
CHANGED
|
@@ -1,178 +1,293 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CRM Template
|
|
2
2
|
|
|
3
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.
|
|
4
|
+
**Next.js 16**, **Better Auth**, **Prisma**, **PostgreSQL** et une UI inspirée d'un template CRM pro.
|
|
7
5
|
|
|
8
|
-
##
|
|
6
|
+
## Fonctionnalités
|
|
9
7
|
|
|
10
|
-
-
|
|
8
|
+
- **Authentification sécurisée** avec Better Auth
|
|
11
9
|
- Connexion par email / mot de passe
|
|
12
10
|
- Sessions sécurisées côté serveur
|
|
13
11
|
- Protection des routes via proxy Next.js
|
|
14
|
-
-
|
|
12
|
+
- **Rôles & permissions**
|
|
15
13
|
- Rôles natifs : USER, ADMIN, MANAGER, COMMERCIAL, TELEPRO, COMPTABLE
|
|
16
|
-
- Rôles personnalisés avec permissions granulaires
|
|
14
|
+
- Rôles personnalisés avec permissions granulaires (40+ permissions)
|
|
17
15
|
- Gestion des utilisateurs (activation / désactivation, invitation par email)
|
|
18
|
-
-
|
|
19
|
-
- Vue synthétique de l
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
16
|
+
- **Tableau de bord**
|
|
17
|
+
- Vue synthétique de l'activité (contacts, tâches, rendez-vous)
|
|
18
|
+
- Widgets personnalisables
|
|
19
|
+
- **Contacts**
|
|
20
|
+
- Vue tableau et cartes
|
|
21
|
+
- Recherche, filtres (statut, origine, commercial, télépro)
|
|
24
22
|
- Import CSV / Excel avec mapping intelligent
|
|
25
|
-
- Export CSV / Excel (
|
|
23
|
+
- Export CSV / Excel (réservé aux admins)
|
|
26
24
|
- Gestion des statuts & motifs de fermeture
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
25
|
+
- KYC : pièce d'identité, date de naissance, etc.
|
|
26
|
+
- Fichiers attachés (Supabase Storage)
|
|
27
|
+
- **Entreprises**
|
|
28
|
+
- Gestion de sociétés avec contacts rattachés
|
|
29
|
+
- Journal d'activité par entreprise
|
|
30
|
+
- **Agenda**
|
|
31
|
+
- Vues Mois / Semaine / Jour
|
|
32
|
+
- Synchronisation Google Calendar
|
|
33
|
+
- Création de liens Google Meet
|
|
34
|
+
- Différenciation visuelle des types de tâches
|
|
35
|
+
- **Automatisations (Workflows)**
|
|
36
|
+
- Déclencheurs : création contact, changement statut, tâche terminée, etc.
|
|
37
|
+
- Actions : email, SMS, changement statut, création tâche, notification, etc.
|
|
38
|
+
- Délais configurables entre actions
|
|
39
|
+
- Exécution planifiée via Vercel Cron (toutes les minutes)
|
|
40
|
+
- **Intégrations**
|
|
41
|
+
- Google Calendar / Sheets / Drive
|
|
42
|
+
- Meta Lead Ads (webhook)
|
|
43
|
+
- Google Ads Lead Forms (webhook)
|
|
44
|
+
- SMTP par utilisateur avec signature
|
|
45
|
+
- Suivi d'ouverture des emails
|
|
46
|
+
- **Templates**
|
|
47
|
+
- Templates email / SMS / note avec variables dynamiques
|
|
48
|
+
- **Paramètres**
|
|
49
|
+
- Profil, sécurité, informations d'entreprise
|
|
34
50
|
- Configuration SMTP + signature email
|
|
35
51
|
- Gestion des statuts & motifs de fermeture
|
|
36
|
-
-
|
|
37
|
-
Ads…)
|
|
38
|
-
- 🤖 **Automatisations (Workflows)**
|
|
39
|
-
- Workflows avec actions chaînées
|
|
40
|
-
- Exécution planifiée via **Vercel Cron**
|
|
41
|
-
- 🎨 **UI moderne**
|
|
42
|
-
- Design type CRM (fond `bg-crms-bg`, cartes blanches, headers structurés)
|
|
43
|
-
- Tailwind CSS v4
|
|
44
|
-
- 📱 Design entièrement responsive
|
|
45
|
-
|
|
46
|
-
## 🛠️ Stack technique
|
|
47
|
-
|
|
48
|
-
- **Framework**: Next.js 16 (App Router)
|
|
49
|
-
- **React**: React 19
|
|
50
|
-
- **Base de données**: PostgreSQL avec Prisma ORM
|
|
51
|
-
- **Authentification**: Better Auth
|
|
52
|
-
- **Styling**: Tailwind CSS v4
|
|
53
|
-
- **Langage**: TypeScript
|
|
54
|
-
- **Gestionnaire de paquets**: pnpm
|
|
55
|
-
|
|
56
|
-
## 🚀 Installation
|
|
57
|
-
|
|
58
|
-
1. **Cloner le projet**
|
|
52
|
+
- Configuration des intégrations
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
## Stack technique
|
|
55
|
+
|
|
56
|
+
| Technologie | Version |
|
|
57
|
+
|-------------|---------|
|
|
58
|
+
| Next.js | 16 (App Router) |
|
|
59
|
+
| React | 19 |
|
|
60
|
+
| PostgreSQL | via Supabase |
|
|
61
|
+
| ORM | Prisma 7 |
|
|
62
|
+
| Authentification | Better Auth |
|
|
63
|
+
| Styling | Tailwind CSS v4 + Radix UI |
|
|
64
|
+
| Formulaires | react-hook-form + Zod |
|
|
65
|
+
| Data fetching | SWR |
|
|
66
|
+
| Éditeur texte | Lexical |
|
|
67
|
+
| Jobs async | Upstash QStash |
|
|
68
|
+
| Stockage fichiers | Supabase Storage |
|
|
69
|
+
| Package manager | pnpm |
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Installation rapide
|
|
66
74
|
|
|
67
75
|
```bash
|
|
68
76
|
pnpm install
|
|
77
|
+
# Configurer .env (voir sections ci-dessous)
|
|
78
|
+
pnpm db:migrate
|
|
79
|
+
pnpm dev
|
|
69
80
|
```
|
|
70
81
|
|
|
71
|
-
|
|
82
|
+
---
|
|
72
83
|
|
|
73
|
-
|
|
84
|
+
## Configuration des services
|
|
74
85
|
|
|
75
|
-
|
|
76
|
-
# Database
|
|
77
|
-
DATABASE_URL="postgresql://postgres:password@localhost:5432/crm_db"
|
|
86
|
+
### 1. Supabase (Base de données + Storage)
|
|
78
87
|
|
|
79
|
-
|
|
80
|
-
BETTER_AUTH_SECRET="votre-clé-secrète-minimum-32-caractères"
|
|
81
|
-
BETTER_AUTH_URL="http://localhost:3000"
|
|
88
|
+
#### Base de données
|
|
82
89
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
1. Créez un projet sur [supabase.com](https://supabase.com)
|
|
91
|
+
2. Allez dans **Settings > Database**
|
|
92
|
+
3. Copiez les connection strings :
|
|
93
|
+
- **Transaction mode (port 6543)** → `DATABASE_URL`
|
|
94
|
+
- **Session mode / Direct (port 5432)** → `DIRECT_URL`
|
|
95
|
+
|
|
96
|
+
```env
|
|
97
|
+
DATABASE_URL="postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres"
|
|
98
|
+
DIRECT_URL="postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres"
|
|
86
99
|
```
|
|
87
100
|
|
|
88
|
-
|
|
101
|
+
#### Storage (fichiers contacts + images éditeur)
|
|
89
102
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
1. Allez dans **Storage** dans votre projet Supabase
|
|
104
|
+
2. Créez **2 buckets** :
|
|
105
|
+
- `contacts` — fichiers attachés aux contacts (privé)
|
|
106
|
+
- `editor-images` — images uploadées dans l'éditeur (privé)
|
|
107
|
+
3. Pour chaque bucket, configurez les **policies RLS** :
|
|
108
|
+
- **SELECT** : `authenticated` (les utilisateurs connectés peuvent lire)
|
|
109
|
+
- **INSERT** : `authenticated` (les utilisateurs connectés peuvent uploader)
|
|
110
|
+
- **DELETE** : `authenticated` (les utilisateurs connectés peuvent supprimer)
|
|
111
|
+
4. Copiez les variables :
|
|
112
|
+
- **Settings > API** → `NEXT_PUBLIC_SUPABASE_URL` (Project URL)
|
|
113
|
+
- **Settings > API** → `SUPABASE_SERVICE_ROLE_KEY` (service_role key, **secret**)
|
|
114
|
+
|
|
115
|
+
```env
|
|
116
|
+
NEXT_PUBLIC_SUPABASE_URL="https://[ref].supabase.co"
|
|
117
|
+
SUPABASE_SERVICE_ROLE_KEY="eyJ..."
|
|
93
118
|
```
|
|
94
119
|
|
|
95
|
-
|
|
120
|
+
> **Important** : le `SUPABASE_SERVICE_ROLE_KEY` contourne les RLS policies. Ne l'exposez jamais côté client.
|
|
96
121
|
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
### 2. Google Cloud (Calendar, Sheets, Drive)
|
|
123
|
+
|
|
124
|
+
1. Allez sur [console.cloud.google.com](https://console.cloud.google.com)
|
|
125
|
+
2. Créez un nouveau projet (ou sélectionnez un existant)
|
|
126
|
+
3. Activez les **3 APIs** :
|
|
127
|
+
- Google Calendar API
|
|
128
|
+
- Google Sheets API
|
|
129
|
+
- Google Drive API
|
|
130
|
+
4. Allez dans **APIs & Services > Credentials**
|
|
131
|
+
5. Créez des identifiants **OAuth 2.0** :
|
|
132
|
+
- Type d'application : **Application Web**
|
|
133
|
+
- URI de redirection autorisés :
|
|
134
|
+
- `http://localhost:3000/api/auth/google/callback` (dev)
|
|
135
|
+
- `https://votre-domaine.com/api/auth/google/callback` (prod)
|
|
136
|
+
6. Copiez les identifiants :
|
|
137
|
+
|
|
138
|
+
```env
|
|
139
|
+
GOOGLE_CLIENT_ID="123456789-xxx.apps.googleusercontent.com"
|
|
140
|
+
GOOGLE_CLIENT_SECRET="GOCSPX-xxx"
|
|
141
|
+
GOOGLE_REDIRECT_URI="http://localhost:3000/api/auth/google/callback"
|
|
99
142
|
```
|
|
100
143
|
|
|
101
|
-
|
|
144
|
+
> **Note** : En production, mettez à jour `GOOGLE_REDIRECT_URI` avec votre domaine de production.
|
|
102
145
|
|
|
103
|
-
|
|
104
|
-
|
|
146
|
+
#### Scopes OAuth demandés
|
|
147
|
+
|
|
148
|
+
L'application demande les scopes suivants lors de la connexion Google :
|
|
149
|
+
- `calendar` — Accès complet au calendrier (lecture/écriture)
|
|
150
|
+
- `spreadsheets` — Accès aux Google Sheets (lecture/écriture)
|
|
151
|
+
- `drive.file` — Accès aux fichiers créés par l'application
|
|
152
|
+
|
|
153
|
+
### 3. QStash (Upstash) — Jobs asynchrones
|
|
154
|
+
|
|
155
|
+
QStash est utilisé pour le traitement asynchrone des imports Google Sheets.
|
|
156
|
+
|
|
157
|
+
1. Créez un compte sur [upstash.com](https://upstash.com)
|
|
158
|
+
2. Allez dans **QStash** (dans le menu de gauche)
|
|
159
|
+
3. Copiez les 3 valeurs depuis la page **QStash** :
|
|
160
|
+
|
|
161
|
+
```env
|
|
162
|
+
QSTASH_TOKEN="eyJ..."
|
|
163
|
+
QSTASH_CURRENT_SIGNING_KEY="sig_xxx"
|
|
164
|
+
QSTASH_NEXT_SIGNING_KEY="sig_xxx"
|
|
105
165
|
```
|
|
106
166
|
|
|
107
|
-
|
|
167
|
+
#### Comment ça fonctionne
|
|
108
168
|
|
|
109
|
-
|
|
169
|
+
- Quand un utilisateur lance un import Google Sheets, le CRM publie un job via QStash
|
|
170
|
+
- QStash appelle le worker `POST /api/jobs/google-sheet/process` de façon asynchrone
|
|
171
|
+
- Le worker vérifie la signature QStash puis exécute l'import
|
|
172
|
+
- L'endpoint `GET /api/integrations/google-sheet/jobs/usage` permet de suivre les quotas (24h)
|
|
173
|
+
- Le bouton de synchronisation manuelle dans les paramètres d'intégration force un enqueue
|
|
110
174
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
175
|
+
### 4. Vercel (Déploiement + Cron Jobs)
|
|
176
|
+
|
|
177
|
+
#### Déploiement
|
|
178
|
+
|
|
179
|
+
1. Connectez votre repo GitHub à [vercel.com](https://vercel.com)
|
|
180
|
+
2. Configurez **toutes** les variables d'environnement dans **Settings > Environment Variables**
|
|
181
|
+
3. Le `buildCommand` dans `vercel.json` exécute automatiquement les migrations Prisma
|
|
182
|
+
|
|
183
|
+
#### Cron Jobs
|
|
184
|
+
|
|
185
|
+
Le fichier `vercel.json` définit 2 crons qui sont auto-détectés par Vercel :
|
|
114
186
|
|
|
115
|
-
|
|
187
|
+
| Cron | Schedule | Description |
|
|
188
|
+
|------|----------|-------------|
|
|
189
|
+
| `/api/workflows/process` | Toutes les minutes | Exécute les actions de workflow planifiées |
|
|
190
|
+
| `/api/cron/cleanup-editor-images` | Tous les jours à 3h | Nettoie les images éditeur orphelines |
|
|
191
|
+
|
|
192
|
+
Vérifiez dans **Vercel Dashboard > Cron Jobs** que les 2 crons sont actifs.
|
|
193
|
+
|
|
194
|
+
> **Note** : Les crons Vercel nécessitent le plan **Pro** (ou supérieur) pour une exécution toutes les minutes.
|
|
195
|
+
|
|
196
|
+
#### Variable CRON_SECRET
|
|
197
|
+
|
|
198
|
+
```env
|
|
199
|
+
CRON_SECRET="votre-secret" # openssl rand -base64 32
|
|
116
200
|
```
|
|
117
201
|
|
|
118
|
-
|
|
202
|
+
Cette clé authentifie les appels cron de Vercel vers vos API routes.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Variables d'environnement (récapitulatif)
|
|
207
|
+
|
|
208
|
+
| Variable | Obligatoire | Description |
|
|
209
|
+
|----------|:-----------:|-------------|
|
|
210
|
+
| `DATABASE_URL` | Oui | Supabase pooled connection (port 6543) |
|
|
211
|
+
| `DIRECT_URL` | Oui | Supabase direct connection (port 5432, migrations) |
|
|
212
|
+
| `BETTER_AUTH_SECRET` | Oui | Secret d'authentification (min 32 chars) |
|
|
213
|
+
| `BETTER_AUTH_URL` | Oui | URL de base pour Better Auth |
|
|
214
|
+
| `NEXT_PUBLIC_APP_URL` | Oui | URL publique de l'application |
|
|
215
|
+
| `APP_NAME` | Oui | Nom affiché de l'application |
|
|
216
|
+
| `ENCRYPTION_KEY` | Oui | Clé de chiffrement SMTP passwords (min 32 chars) |
|
|
217
|
+
| `GOOGLE_CLIENT_ID` | Oui | OAuth 2.0 Client ID |
|
|
218
|
+
| `GOOGLE_CLIENT_SECRET` | Oui | OAuth 2.0 Client Secret |
|
|
219
|
+
| `GOOGLE_REDIRECT_URI` | Oui | URI de callback Google OAuth |
|
|
220
|
+
| `CRON_SECRET` | Oui | Authentification des cron jobs Vercel |
|
|
221
|
+
| `QSTASH_TOKEN` | Oui | Token Upstash QStash |
|
|
222
|
+
| `QSTASH_CURRENT_SIGNING_KEY` | Oui | Signing key QStash (courante) |
|
|
223
|
+
| `QSTASH_NEXT_SIGNING_KEY` | Oui | Signing key QStash (rotation) |
|
|
224
|
+
| `NEXT_PUBLIC_SUPABASE_URL` | Oui | URL du projet Supabase |
|
|
225
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Oui | Service role key Supabase (secret) |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Structure du projet
|
|
119
230
|
|
|
120
231
|
```
|
|
121
232
|
src/
|
|
122
233
|
├── app/
|
|
123
|
-
│ ├── (auth)/ #
|
|
234
|
+
│ ├── (auth)/ # Pages d'authentification (signin, reset-password, invite)
|
|
124
235
|
│ ├── (dashboard)/ # Espace connecté (protégé)
|
|
125
236
|
│ │ ├── dashboard/ # Tableau de bord
|
|
126
|
-
│ │ ├── contacts/ # Gestion des contacts
|
|
237
|
+
│ │ ├── contacts/ # Gestion des contacts + entreprises
|
|
127
238
|
│ │ ├── agenda/ # Agenda (mois / semaine / jour)
|
|
128
239
|
│ │ ├── automatisation/ # Workflows / automatisations
|
|
129
|
-
│ │ ├── templates/ # Templates d
|
|
130
|
-
│ │ ├── settings/ # Paramètres (profil, entreprise, intégrations
|
|
131
|
-
│ │ ├── users/ # Gestion des utilisateurs & rôles
|
|
132
|
-
│ │
|
|
133
|
-
│
|
|
134
|
-
│
|
|
135
|
-
├──
|
|
136
|
-
├──
|
|
137
|
-
|
|
240
|
+
│ │ ├── templates/ # Templates d'emails
|
|
241
|
+
│ │ ├── settings/ # Paramètres (profil, entreprise, intégrations)
|
|
242
|
+
│ │ ├── users/ # Gestion des utilisateurs & rôles
|
|
243
|
+
│ │ ├── closing/ # Motifs de fermeture
|
|
244
|
+
│ │ └── layout.tsx # Layout avec sidebar + contexts
|
|
245
|
+
│ ├── api/ # API routes (REST)
|
|
246
|
+
│ │ ├── auth/ # Better Auth + Google OAuth
|
|
247
|
+
│ │ ├── contacts/ # CRUD contacts, import, export, fichiers
|
|
248
|
+
│ │ ├── companies/ # CRUD entreprises
|
|
249
|
+
│ │ ├── tasks/ # CRUD tâches + Google Meet
|
|
250
|
+
│ │ ├── workflows/ # CRUD workflows + processing cron
|
|
251
|
+
│ │ ├── webhooks/ # Meta Leads, Google Ads
|
|
252
|
+
│ │ ├── jobs/ # Workers QStash (Google Sheets)
|
|
253
|
+
│ │ ├── integrations/ # Google Sheets sync, logs
|
|
254
|
+
│ │ ├── settings/ # Configuration (SMTP, statuts, intégrations)
|
|
255
|
+
│ │ └── cron/ # Jobs planifiés (cleanup images)
|
|
256
|
+
│ └── page.tsx # Redirection vers /dashboard
|
|
257
|
+
├── components/ # Composants UI (sidebar, header, éditeur, etc.)
|
|
258
|
+
├── contexts/ # React contexts (toast, sidebar, reminders, view-as)
|
|
259
|
+
├── hooks/ # Custom hooks (SWR, permissions, etc.)
|
|
260
|
+
├── lib/ # Utilitaires (auth, prisma, workflows, intégrations)
|
|
261
|
+
├── types/ # Types TypeScript
|
|
262
|
+
└── proxy.ts # Protection des routes (middleware)
|
|
138
263
|
```
|
|
139
264
|
|
|
140
|
-
##
|
|
265
|
+
## Scripts disponibles
|
|
141
266
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
système, intégrations, export contacts) sont réservées aux administrateurs
|
|
267
|
+
```bash
|
|
268
|
+
pnpm dev # Serveur de développement
|
|
269
|
+
pnpm build # Build de production (+ prisma generate)
|
|
270
|
+
pnpm start # Serveur de production
|
|
271
|
+
pnpm db:migrate # Migrations Prisma (dev)
|
|
272
|
+
pnpm db:deploy # Migrations Prisma (prod)
|
|
273
|
+
pnpm lint # ESLint
|
|
274
|
+
pnpm format # Prettier
|
|
275
|
+
```
|
|
152
276
|
|
|
153
|
-
##
|
|
277
|
+
## Personnalisation
|
|
154
278
|
|
|
155
279
|
### Ajouter une nouvelle page protégée
|
|
156
280
|
|
|
157
281
|
1. Créez votre page dans `src/app/(dashboard)/ma-page/page.tsx`
|
|
158
|
-
2. Ajoutez-la dans la navigation (`src/
|
|
159
|
-
3. (Optionnel) Protégez-la par
|
|
282
|
+
2. Ajoutez-la dans la navigation (`src/config/nav-pages.ts`)
|
|
283
|
+
3. (Optionnel) Protégez-la par permission dans `src/lib/permissions.ts`
|
|
160
284
|
|
|
161
285
|
### Modifier le thème
|
|
162
286
|
|
|
163
|
-
Les couleurs
|
|
164
|
-
dans les composants pour personnaliser le thème.
|
|
165
|
-
|
|
166
|
-
## 📝 Scripts disponibles
|
|
287
|
+
Les couleurs sont configurées avec Tailwind CSS v4. Les variables CSS sont dans `src/app/globals.css`.
|
|
167
288
|
|
|
168
|
-
|
|
169
|
-
pnpm dev # Lancer le serveur de développement
|
|
170
|
-
pnpm build # Build de production
|
|
171
|
-
pnpm start # Lancer le serveur de production
|
|
172
|
-
pnpm lint # Linter le code
|
|
173
|
-
pnpm format # Formater le code avec Prettier
|
|
174
|
-
```
|
|
289
|
+
---
|
|
175
290
|
|
|
176
|
-
##
|
|
291
|
+
## Licence
|
|
177
292
|
|
|
178
293
|
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "new-york",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "src/app/globals.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
10
|
+
"cssVariables": true,
|
|
11
|
+
"prefix": ""
|
|
12
|
+
},
|
|
13
|
+
"iconLibrary": "lucide",
|
|
14
|
+
"aliases": {
|
|
15
|
+
"components": "@/components",
|
|
16
|
+
"utils": "@/lib/utils",
|
|
17
|
+
"ui": "@/components/ui",
|
|
18
|
+
"lib": "@/lib",
|
|
19
|
+
"hooks": "@/hooks"
|
|
20
|
+
},
|
|
21
|
+
"registries": {}
|
|
22
|
+
}
|
|
@@ -5,6 +5,18 @@ import nextTs from "eslint-config-next/typescript";
|
|
|
5
5
|
const eslintConfig = defineConfig([
|
|
6
6
|
...nextVitals,
|
|
7
7
|
...nextTs,
|
|
8
|
+
{
|
|
9
|
+
rules: {
|
|
10
|
+
// Dette TypeScript large : garder visible sans bloquer la CI
|
|
11
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
12
|
+
// Apostrophes françaises courantes dans le JSX (d', l', n', etc.)
|
|
13
|
+
"react/no-unescaped-entities": ["error", { forbid: [">", "}"] }],
|
|
14
|
+
// Règles React Compiler : refactors souvent lourds, à traiter au fil de l’eau
|
|
15
|
+
"react-hooks/set-state-in-effect": "warn",
|
|
16
|
+
"react-hooks/immutability": "warn",
|
|
17
|
+
"react-hooks/refs": "warn",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
8
20
|
// Override default ignores of eslint-config-next.
|
|
9
21
|
globalIgnores([
|
|
10
22
|
// Default ignores of eslint-config-next:
|
|
@@ -12,6 +24,7 @@ const eslintConfig = defineConfig([
|
|
|
12
24
|
"out/**",
|
|
13
25
|
"build/**",
|
|
14
26
|
"next-env.d.ts",
|
|
27
|
+
"eslint-report.json",
|
|
15
28
|
]),
|
|
16
29
|
]);
|
|
17
30
|
|