Déploiement Automatique Cloudflare - CLAR-IA

Solution complète de déploiement automatisé avec base de données D1, Workers et Dashboard

🚀 Démarrage Rapide

Une seule commande pour tout déployer :

bash deploy-clar-ia.sh

Prérequis

Compte Cloudflare

  • Compte Cloudflare actif
  • Token API avec permissions Workers et D1
  • Domaine configuré (optionnel)

Outils requis

  • Node.js 18+ installé
  • npm ou yarn
  • Git (optionnel)

Script Principal : deploy-clar-ia.sh

#!/bin/bash # Script de déploiement automatique CLAR-IA sur Cloudflare # Usage: bash deploy-clar-ia.sh set -e # Exit on any error # Configuration PROJECT_NAME="clar-ia-candidatures" DB_NAME="clar_ia_db" WORKER_NAME="clar-ia-api" DASHBOARD_NAME="clar-ia-dashboard" echo "🚀 Déploiement automatique CLAR-IA sur Cloudflare" echo "=================================================" # Vérification des prérequis check_prerequisites() { echo "📋 Vérification des prérequis..." if ! command -v node &> /dev/null; then echo "❌ Node.js n'est pas installé" exit 1 fi if ! command -v npm &> /dev/null; then echo "❌ npm n'est pas installé" exit 1 fi echo "✅ Prérequis validés" } # Installation de Wrangler install_wrangler() { echo "📦 Installation de Wrangler CLI..." npm install -g wrangler@latest echo "✅ Wrangler installé" } # Configuration du token API setup_auth() { echo "🔐 Configuration de l'authentification..." if [ -z "$CLOUDFLARE_API_TOKEN" ]; then echo "⚠️ Variable CLOUDFLARE_API_TOKEN non définie" echo "Créez un token sur https://dash.cloudflare.com/profile/api-tokens" echo "Permissions requises: Zone:Read, Account:Read, D1:Edit, Workers:Edit" read -p "Entrez votre token API: " token export CLOUDFLARE_API_TOKEN=$token fi # Test du token if wrangler whoami &> /dev/null; then echo "✅ Token API validé" else echo "❌ Token API invalide" exit 1 fi } # Création du projet create_project() { echo "📁 Création du projet..." mkdir -p $PROJECT_NAME cd $PROJECT_NAME # Initialisation du projet Wrangler if [ ! -f "wrangler.toml" ]; then cat > wrangler.toml << EOF name = "$WORKER_NAME" main = "src/index.js" compatibility_date = "2024-01-01" [[d1_databases]] binding = "DB" database_name = "$DB_NAME" database_id = "TBD" [vars] ALLOWED_ORIGINS = ["https://your-domain.com", "http://localhost:3000"] EOF fi mkdir -p src echo "✅ Structure du projet créée" } # Création de la base de données D1 create_database() { echo "🗄️ Création de la base de données D1..." # Création de la base DB_OUTPUT=$(wrangler d1 create $DB_NAME) DB_ID=$(echo "$DB_OUTPUT" | grep -o 'database_id = "[^"]*"' | cut -d'"' -f2) if [ -z "$DB_ID" ]; then echo "❌ Erreur lors de la création de la base de données" exit 1 fi # Mise à jour du wrangler.toml avec l'ID de la base sed -i "s/database_id = \"TBD\"/database_id = \"$DB_ID\"/" wrangler.toml echo "✅ Base de données créée: $DB_ID" } # Création du schéma de base de données create_schema() { echo "📋 Création du schéma de base de données..." cat > schema.sql << 'EOF' -- Table des candidatures CLAR-IA CREATE TABLE IF NOT EXISTS candidatures ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- Informations de base nom_prenom TEXT NOT NULL, email TEXT NOT NULL, telephone TEXT, etablissement TEXT, periode_stage TEXT, niveau_scolaire TEXT, -- Motivation motivation_rejoindre TEXT, motivation_principale TEXT, projet_fier TEXT, -- Compétences competences_automatisation BOOLEAN DEFAULT 0, competences_ia BOOLEAN DEFAULT 0, competences_web BOOLEAN DEFAULT 0, competences_systemes BOOLEAN DEFAULT 0, competences_marketing BOOLEAN DEFAULT 0, portfolio_lien TEXT, -- Tests curiosité cas_artisan TEXT, preference_travail TEXT, niveau_anglais INTEGER, -- Mises en situation situation_priorites TEXT, situation_amelioration TEXT, situation_adaptation TEXT, -- Disponibilité dates_disponibilite TEXT, convention_signee BOOLEAN DEFAULT 0, prolongation_possible TEXT, -- Bonus apprentissage_souhaite TEXT, projet_48h TEXT, -- Métadonnées ip_address TEXT, user_agent TEXT, status TEXT DEFAULT 'nouveau' ); -- Index pour les recherches CREATE INDEX IF NOT EXISTS idx_email ON candidatures(email); CREATE INDEX IF NOT EXISTS idx_created_at ON candidatures(created_at); CREATE INDEX IF NOT EXISTS idx_niveau ON candidatures(niveau_scolaire); CREATE INDEX IF NOT EXISTS idx_status ON candidatures(status); EOF # Exécution du schéma wrangler d1 execute $DB_NAME --file=schema.sql echo "✅ Schéma de base de données créé" } # Création du Worker API create_worker() { echo "⚡ Création du Worker API..." cat > src/index.js << 'EOF' // Worker API pour CLAR-IA Candidatures export default { async fetch(request, env, ctx) { const url = new URL(request.url); const { pathname } = url; // CORS headers const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }; // Handle CORS preflight if (request.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }); } try { // Route: Soumettre une candidature if (pathname === '/api/candidature' && request.method === 'POST') { return await handleSubmission(request, env, corsHeaders); } // Route: Récupérer les candidatures (admin) if (pathname === '/api/candidatures' && request.method === 'GET') { return await handleGetCandidatures(request, env, corsHeaders); } // Route: Dashboard admin if (pathname === '/admin' || pathname === '/admin/') { return await handleAdminDashboard(request, env, corsHeaders); } // Route par défaut return new Response('API CLAR-IA Candidatures', { headers: { ...corsHeaders, 'Content-Type': 'text/plain' } }); } catch (error) { console.error('Error:', error); return new Response(JSON.stringify({ success: false, error: 'Internal server error' }), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } } }; // Gestion de la soumission de candidature async function handleSubmission(request, env, corsHeaders) { try { const data = await request.json(); // Validation des données requises const required = ['nom_prenom', 'email']; for (const field of required) { if (!data[field]) { return new Response(JSON.stringify({ success: false, error: `Le champ ${field} est requis` }), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } } // Préparation des données pour insertion const candidature = { nom_prenom: data.nom_prenom || '', email: data.email || '', telephone: data.telephone || '', etablissement: data.etablissement || '', periode_stage: data.periode_stage || '', niveau_scolaire: data.niveau_scolaire || '', motivation_rejoindre: data.motivation_rejoindre || '', motivation_principale: data.motivation_principale || '', projet_fier: data.projet_fier || '', competences_automatisation: data.competences?.includes('automatisation') ? 1 : 0, competences_ia: data.competences?.includes('ia') ? 1 : 0, competences_web: data.competences?.includes('web') ? 1 : 0, competences_systemes: data.competences?.includes('systemes') ? 1 : 0, competences_marketing: data.competences?.includes('marketing') ? 1 : 0, portfolio_lien: data.portfolio_lien || '', cas_artisan: data.cas_artisan || '', preference_travail: data.preference_travail || '', niveau_anglais: parseInt(data.niveau_anglais) || 0, situation_priorites: data.situation_priorites || '', situation_amelioration: data.situation_amelioration || '', situation_adaptation: data.situation_adaptation || '', dates_disponibilite: data.dates_disponibilite || '', convention_signee: data.convention_signee === 'oui' ? 1 : 0, prolongation_possible: data.prolongation_possible || '', apprentissage_souhaite: data.apprentissage_souhaite || '', projet_48h: data.projet_48h || '', ip_address: request.headers.get('CF-Connecting-IP') || '', user_agent: request.headers.get('User-Agent') || '' }; // Insertion en base const stmt = env.DB.prepare(` INSERT INTO candidatures ( nom_prenom, email, telephone, etablissement, periode_stage, niveau_scolaire, motivation_rejoindre, motivation_principale, projet_fier, competences_automatisation, competences_ia, competences_web, competences_systemes, competences_marketing, portfolio_lien, cas_artisan, preference_travail, niveau_anglais, situation_priorites, situation_amelioration, situation_adaptation, dates_disponibilite, convention_signee, prolongation_possible, apprentissage_souhaite, projet_48h, ip_address, user_agent ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const result = await stmt.bind( candidature.nom_prenom, candidature.email, candidature.telephone, candidature.etablissement, candidature.periode_stage, candidature.niveau_scolaire, candidature.motivation_rejoindre, candidature.motivation_principale, candidature.projet_fier, candidature.competences_automatisation, candidature.competences_ia, candidature.competences_web, candidature.competences_systemes, candidature.competences_marketing, candidature.portfolio_lien, candidature.cas_artisan, candidature.preference_travail, candidature.niveau_anglais, candidature.situation_priorites, candidature.situation_amelioration, candidature.situation_adaptation, candidature.dates_disponibilite, candidature.convention_signee, candidature.prolongation_possible, candidature.apprentissage_souhaite, candidature.projet_48h, candidature.ip_address, candidature.user_agent ).run(); return new Response(JSON.stringify({ success: true, message: 'Candidature enregistrée avec succès', id: result.meta.last_row_id }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } catch (error) { console.error('Submission error:', error); return new Response(JSON.stringify({ success: false, error: 'Erreur lors de l\'enregistrement' }), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } } // Récupération des candidatures (admin) async function handleGetCandidatures(request, env, corsHeaders) { try { const url = new URL(request.url); const limit = parseInt(url.searchParams.get('limit')) || 50; const offset = parseInt(url.searchParams.get('offset')) || 0; const niveau = url.searchParams.get('niveau'); const status = url.searchParams.get('status'); let query = 'SELECT * FROM candidatures'; let params = []; let conditions = []; if (niveau) { conditions.push('niveau_scolaire = ?'); params.push(niveau); } if (status) { conditions.push('status = ?'); params.push(status); } if (conditions.length > 0) { query += ' WHERE ' + conditions.join(' AND '); } query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?'; params.push(limit, offset); const stmt = env.DB.prepare(query); const result = await stmt.bind(...params).all(); // Statistiques const statsStmt = env.DB.prepare(` SELECT COUNT(*) as total, COUNT(CASE WHEN status = 'nouveau' THEN 1 END) as nouveaux, COUNT(CASE WHEN status = 'en_cours' THEN 1 END) as en_cours, COUNT(CASE WHEN status = 'accepte' THEN 1 END) as acceptes, COUNT(CASE WHEN status = 'refuse' THEN 1 END) as refuses FROM candidatures `); const stats = await statsStmt.first(); return new Response(JSON.stringify({ success: true, data: result.results, stats: stats, pagination: { limit, offset, total: stats.total } }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } catch (error) { console.error('Get candidatures error:', error); return new Response(JSON.stringify({ success: false, error: 'Erreur lors de la récupération des données' }), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } } // Dashboard admin async function handleAdminDashboard(request, env, corsHeaders) { const html = ` Dashboard Admin - CLAR-IA

Dashboard CLAR-IA - Candidatures

Chargement des candidatures...

`; return new Response(html, { headers: { ...corsHeaders, 'Content-Type': 'text/html' } }); } EOF echo "✅ Worker API créé" } # Déploiement du Worker deploy_worker() { echo "🚀 Déploiement du Worker..." wrangler deploy # Récupération de l'URL du Worker WORKER_URL=$(wrangler whoami 2>/dev/null | grep -o 'https://[^/]*\.workers\.dev' | head -1) if [ -z "$WORKER_URL" ]; then WORKER_URL="https://$WORKER_NAME.your-account.workers.dev" fi echo "✅ Worker déployé: $WORKER_URL" echo "📱 Dashboard admin: $WORKER_URL/admin" } # Création du formulaire mis à jour create_updated_form() { echo "📄 Création du formulaire mis à jour..." cat > ../formulaire-clar-ia.html << EOF Stage en IA, automatisation & digital – CLAR-IA

Stage en IA, automatisation & digital – CLAR-IA

Bienvenue !

CLAR-IA est un cabinet de conseil digital basé à La Réunion, fondé par un ancien CTO international avec 14 années d'expérience, ayant piloté des équipes dans 23 pays et managé plus de 300 personnes dans les systèmes d'information.

Nous accompagnons les TPE/PME locales avec des outils modernes : automatisation (n8n, Make), intelligence artificielle appliquée (GPT, IA image), sites web et solutions métiers.

Nous recherchons 1 à 2 stagiaires passionnés (3 à 6 mois, Saint-Leu/hybride) pour vivre une expérience formatrice, intense et concrète.

🚀 Si tu aimes apprendre vite, tester, construire et livrer, ce stage est pour toi.

Progression 0%

1. Informations de base

2. Motivation & passion

3. Compétences techniques & appétence

4. Tests de curiosité & mindset

1 (Débutant) 3 5 (Expert)

5. Mises en situation pratiques

6. Disponibilité & engagement

7. Bonus (filtre "passionnés")

Toutes les informations seront traitées de manière confidentielle

EOF echo "✅ Formulaire mis à jour créé" } # Tests de validation run_tests() { echo "🧪 Tests de validation..." # Test de la base de données echo " - Test de la base de données..." TEST_RESULT=$(wrangler d1 execute $DB_NAME --command="SELECT COUNT(*) as count FROM candidatures;") if echo "$TEST_RESULT" | grep -q "count"; then echo " ✅ Base de données opérationnelle" else echo " ❌ Problème avec la base de données" return 1 fi # Test du Worker echo " - Test du Worker..." if wrangler tail --format=pretty &> /dev/null; then echo " ✅ Worker déployé et accessible" else echo " ❌ Problème avec le Worker" return 1 fi echo "✅ Tous les tests passés" } # Fonction de rollback rollback() { echo "🔄 Rollback en cours..." # Supprimer le Worker wrangler delete $WORKER_NAME --force 2>/dev/null || true # Supprimer la base de données wrangler d1 delete $DB_NAME --force 2>/dev/null || true # Nettoyer les fichiers cd .. rm -rf $PROJECT_NAME echo "✅ Rollback terminé" } # Affichage des informations finales show_summary() { echo "" echo "🎉 DÉPLOIEMENT TERMINÉ AVEC SUCCÈS !" echo "====================================" echo "" echo "📊 Récapitulatif :" echo " • Base de données D1 : $DB_NAME" echo " • Worker API : $WORKER_NAME" echo " • Dashboard admin : $WORKER_URL/admin" echo "" echo "📁 Fichiers créés :" echo " • ./clar-ia-candidatures/ (projet Worker)" echo " • ./formulaire-clar-ia.html (formulaire mis à jour)" echo "" echo "🔧 Prochaines étapes :" echo " 1. Mettez à jour l'URL de l'API dans le formulaire" echo " 2. Déployez le formulaire sur votre site" echo " 3. Testez une candidature" echo " 4. Accédez au dashboard admin" echo "" echo "📞 Support : En cas de problème, consultez les logs Cloudflare" echo "" } # Fonction principale main() { echo "🚀 Démarrage du déploiement CLAR-IA..." # Trap pour gérer les erreurs trap 'echo "❌ Erreur détectée. Rollback..."; rollback; exit 1' ERR check_prerequisites install_wrangler setup_auth create_project create_database create_schema create_worker deploy_worker create_updated_form run_tests show_summary echo "" echo "✅ Déploiement terminé avec succès !" echo "🎯 Votre solution CLAR-IA est prête à l'emploi !" } # Exécution du script principal main "$@"

Script PowerShell : deploy-clar-ia.ps1

# Script de déploiement automatique CLAR-IA sur Cloudflare (PowerShell) # Usage: .\deploy-clar-ia.ps1 param( [string]$ProjectName = "clar-ia-candidatures", [string]$DbName = "clar_ia_db", [string]$WorkerName = "clar-ia-api" ) $ErrorActionPreference = "Stop" Write-Host "🚀 Déploiement automatique CLAR-IA sur Cloudflare" -ForegroundColor Cyan Write-Host "=================================================" -ForegroundColor Cyan # Vérification des prérequis function Test-Prerequisites { Write-Host "📋 Vérification des prérequis..." -ForegroundColor Yellow if (!(Get-Command node -ErrorAction SilentlyContinue)) { Write-Host "❌ Node.js n'est pas installé" -ForegroundColor Red exit 1 } if (!(Get-Command npm -ErrorAction SilentlyContinue)) { Write-Host "❌ npm n'est pas installé" -ForegroundColor Red exit 1 } Write-Host "✅ Prérequis validés" -ForegroundColor Green } # Installation de Wrangler function Install-Wrangler { Write-Host "📦 Installation de Wrangler CLI..." -ForegroundColor Yellow npm install -g wrangler@latest Write-Host "✅ Wrangler installé" -ForegroundColor Green } # Configuration de l'authentification function Setup-Auth { Write-Host "🔐 Configuration de l'authentification..." -ForegroundColor Yellow if (!$env:CLOUDFLARE_API_TOKEN) { Write-Host "⚠️ Variable CLOUDFLARE_API_TOKEN non définie" -ForegroundColor Yellow Write-Host "Créez un token sur https://dash.cloudflare.com/profile/api-tokens" Write-Host "Permissions requises: Zone:Read, Account:Read, D1:Edit, Workers:Edit" $token = Read-Host "Entrez votre token API" $env:CLOUDFLARE_API_TOKEN = $token } # Test du token try { wrangler whoami | Out-Null Write-Host "✅ Token API validé" -ForegroundColor Green } catch { Write-Host "❌ Token API invalide" -ForegroundColor Red exit 1 } } # Création du projet function New-Project { Write-Host "📁 Création du projet..." -ForegroundColor Yellow New-Item -ItemType Directory -Path $ProjectName -Force | Out-Null Set-Location $ProjectName # Création du wrangler.toml @" name = "$WorkerName" main = "src/index.js" compatibility_date = "2024-01-01" [[d1_databases]] binding = "DB" database_name = "$DbName" database_id = "TBD" [vars] ALLOWED_ORIGINS = ["https://your-domain.com", "http://localhost:3000"] "@ | Out-File -FilePath "wrangler.toml" -Encoding UTF8 New-Item -ItemType Directory -Path "src" -Force | Out-Null Write-Host "✅ Structure du projet créée" -ForegroundColor Green } # Création de la base de données function New-Database { Write-Host "🗄️ Création de la base de données D1..." -ForegroundColor Yellow $dbOutput = wrangler d1 create $DbName $dbId = ($dbOutput | Select-String 'database_id = "([^"]*)"').Matches[0].Groups[1].Value if (!$dbId) { Write-Host "❌ Erreur lors de la création de la base de données" -ForegroundColor Red exit 1 } # Mise à jour du wrangler.toml (Get-Content "wrangler.toml") -replace 'database_id = "TBD"', "database_id = `"$dbId`"" | Set-Content "wrangler.toml" Write-Host "✅ Base de données créée: $dbId" -ForegroundColor Green } # Exécution du script principal function Main { try { Test-Prerequisites Install-Wrangler Setup-Auth New-Project New-Database Write-Host "" Write-Host "🎉 Script PowerShell exécuté avec succès !" -ForegroundColor Green Write-Host "Continuez avec les étapes bash ou manuelles pour finaliser le déploiement." -ForegroundColor Yellow } catch { Write-Host "❌ Erreur détectée: $($_.Exception.Message)" -ForegroundColor Red exit 1 } } Main

Instructions Step-by-Step

Étape 1 : Préparation

Téléchargez les scripts et préparez votre environnement

# Créer un dossier de travail mkdir clar-ia-deployment cd clar-ia-deployment # Copier le script bash # (Copiez le contenu dans deploy-clar-ia.sh) # Rendre exécutable chmod +x deploy-clar-ia.sh

Étape 2 : Configuration Cloudflare

Obtenez votre token API Cloudflare

  1. Connectez-vous à Cloudflare Dashboard
  2. Allez dans "My Profile" → "API Tokens"
  3. Cliquez "Create Token" → "Custom token"
  4. Permissions: Zone:Read, Account:Read, D1:Edit, Workers Scripts:Edit
  5. Copiez le token généré

Étape 3 : Exécution

Lancez le déploiement automatique

# Définir le token API export CLOUDFLARE_API_TOKEN="your_token_here" # Exécuter le déploiement bash deploy-clar-ia.sh

Étape 4 : Configuration finale

Mettez à jour l'URL de l'API dans le formulaire

# Dans formulaire-clar-ia.html, remplacez : const API_URL = 'REMPLACER_PAR_URL_WORKER'; # Par : const API_URL = 'https://clar-ia-api.your-account.workers.dev';

Étape 5 : Test et validation

Vérifiez que tout fonctionne correctement

  1. Ouvrez le formulaire HTML dans un navigateur
  2. Remplissez une candidature de test
  3. Vérifiez l'envoi (message de succès)
  4. Accédez au dashboard admin : https://your-worker.workers.dev/admin
  5. Vérifiez que la candidature apparaît dans le dashboard

Architecture de la Solution

Frontend

  • • Formulaire HTML5 responsive
  • • Validation côté client
  • • Interface utilisateur moderne
  • • Compatible mobile

Backend

  • • Cloudflare Worker (API)
  • • Endpoints REST
  • • Validation serveur
  • • Gestion CORS

Base de données

  • • Cloudflare D1 (SQLite)
  • • Schéma optimisé
  • • Index de performance
  • • Sauvegarde automatique

Configuration des Variables

# Variables d'environnement requises # Token API Cloudflare (obligatoire) export CLOUDFLARE_API_TOKEN="your_cloudflare_api_token_here" # Configuration optionnelle export PROJECT_NAME="clar-ia-candidatures" export DB_NAME="clar_ia_db" export WORKER_NAME="clar-ia-api" export DASHBOARD_NAME="clar-ia-dashboard" # Domaines autorisés (CORS) export ALLOWED_ORIGINS="https://your-domain.com,http://localhost:3000" # Configuration du worker export WORKER_COMPATIBILITY_DATE="2024-01-01" export WORKER_MEMORY_LIMIT="128" # Configuration de la base de données export DB_BACKUP_ENABLED="true" export DB_MAX_CONNECTIONS="10"

Endpoints API Disponibles

POST /api/candidature

Soumettre une nouvelle candidature

{ "nom_prenom": "Jean Dupont", "email": "jean@example.com", "competences": ["ia", "web"], // ... autres champs }
GET /api/candidatures

Récupérer les candidatures (admin)

// Paramètres optionnels : ?limit=50&offset=0&niveau=Bac+3&status=nouveau
GET /admin

Dashboard administrateur

Interface web complète pour gérer les candidatures

OPTIONS /*

Gestion CORS automatique

Pré-flight requests pour toutes les routes

Fonctionnalités du Dashboard Admin

📊 Statistiques en temps réel

  • Nombre total de candidatures
  • Candidatures par statut (nouveau, en cours, accepté, refusé)
  • Évolution par jour/semaine
  • Répartition par niveau scolaire
  • Compétences les plus fréquentes

🔍 Gestion des candidatures

  • Liste complète des candidatures
  • Filtrage par niveau, statut, date
  • Recherche textuelle avancée
  • Tri par colonnes
  • Vue détaillée de chaque candidature

📤 Export et sauvegarde

  • Export CSV pour Excel/Sheets
  • Export JSON pour analyses
  • Sauvegarde automatique
  • Archivage des données
  • Import/Export sélectif

⚙️ Administration

  • Changement de statut en masse
  • Suppression sécurisée
  • Logs d'activité
  • Configuration des notifications
  • Gestion des accès admin

Sécurité et Bonnes Pratiques

🔒 Sécurité

  • Validation côté serveur stricte
  • Protection contre l'injection SQL
  • Sanitisation des données
  • Rate limiting automatique
  • HTTPS obligatoire
  • Headers de sécurité

⚡ Performance

  • Cache Cloudflare intégré
  • Compression automatique
  • Optimisation des requêtes DB
  • Index de base de données
  • Pagination des résultats
  • Lazy loading

Dépannage et Support

❓ Problèmes courants

Token API invalide : Vérifiez les permissions (Zone:Read, Account:Read, D1:Edit, Workers:Edit)
Base de données inaccessible : Vérifiez que l'ID de la DB est correct dans wrangler.toml
CORS errors : Ajoutez votre domaine dans la liste ALLOWED_ORIGINS

🔧 Commandes utiles

# Voir les logs du Worker wrangler tail # Tester la base de données wrangler d1 execute clar_ia_db --command="SELECT COUNT(*) FROM candidatures;" # Redéployer après modification wrangler deploy # Voir les métriques wrangler dev

🎉 Solution CLAR-IA Prête !

Votre formulaire de candidature avec base de données Cloudflare est maintenant opérationnel. Déployez, testez et commencez à recevoir des candidatures de qualité !

✅ Base D1 configurée ✅ Worker API déployé ✅ Dashboard admin prêt ✅ Formulaire mis à jour