Aller au contenu principal

Meilleures Pratiques de Déploiement

Guide pour déployer votre intégration MONCRENEAU en production de manière sécurisée et fiable.

Vue d'Ensemble​

Le déploiement en production nécessite une attention particulière à la sécurité, la fiabilité et la surveillance. Ce guide vous accompagne à travers les étapes essentielles pour un déploiement réussi.

Avant le Déploiement​

✅ Checklist Préalable​

  • Tests complets réussis
  • Webhooks testés et vérifiés (signature HMAC)
  • Gestion d'erreurs implémentée (retry, circuit breaker)
  • Monitoring configuré (logs, métriques, alertes)
  • Documentation interne à jour
  • Équipe formée et prête
  • Plan de rollback défini
  • Sauvegardes configurées

Vérifications Techniques​

# 1. Vérifier que les tests passent
npm test

# 2. Vérifier les variables d'environnement
env | grep MONCRENEAU

# 3. Tester la connexion à l'API
curl -H "X-API-Key: $MONCRENEAU_API_KEY" \
{{API_BASE_URL}}/appointments

# 4. Vérifier que les webhooks fonctionnent
# (créer un rendez-vous et vérifier la réception)

Étape 1: Sécuriser les Clés API​

Obtenir et Stocker les Clés​

  1. Connectez-vous à votre compte MONCRENEAU
  2. Allez dans Paramètres > API > Clés
  3. Générez votre clé API de production
  4. Sauvegardez immédiatement dans votre gestionnaire de secrets

Bonnes Pratiques de Stockage​

# ❌ JAMAIS dans le code
const apiKey = "mk_abc123...";

# ❌ JAMAIS dans Git
MONCRENEAU_API_KEY=mk_abc123... # Dans .env commité

# ✅ Variables d'environnement du serveur
# Heroku
heroku config:set MONCRENEAU_API_KEY=mk_abc123...

# AWS Systems Manager
aws ssm put-parameter \
--name /prod/moncreneau/api_key \
--value "mk_abc123..." \
--type SecureString

# Kubernetes Secret
kubectl create secret generic moncreneau-api \
--from-literal=api-key=mk_abc123...

# Docker Compose with secrets
docker secret create moncreneau_api_key -

Étape 2: Configuration des Environnements​

Structure Recommandée​

.env.development   # Variables de développement local
.env.production # Variables de production

Exemple de Configuration​

[object Object]

Vérification au Démarrage​

// app.js
const config = require('./config/api');

function validateConfig() {
const required = ['apiUrl', 'apiKey', 'webhookSecret'];

for (const key of required) {
if (!config[key]) {
console.error(`❌ Missing config: ${key}`);
process.exit(1);
}
}

console.log('✓ Configuration validated');
console.log(`Environment: ${process.env.NODE_ENV}`);
console.log(`API URL: ${config.apiUrl}`);
console.log(`API Key: ${config.apiKey.substring(0, 10)}...`);
}

validateConfig();

Étape 3: Configuration des Webhooks​

Configurer l'URL Webhook​

  1. Dashboard MONCRENEAU > Webhooks > Configuration
  2. Entrez votre URL de production: https://votre-app.com/webhooks/moncreneau
  3. Copiez le secret webhook (commence par whsec_...)
  4. Sauvegardez-le dans vos variables d'environnement

Vérifier l'URL Webhook​

# L'URL doit être:
# ✅ HTTPS (certificat SSL valide)
# ✅ Accessible publiquement (pas localhost)
# ✅ Répond en < 5 secondes

# Test manuel
curl -X POST https://votre-app.com/webhooks/moncreneau \
-H "Content-Type: application/json" \
-H "X-Moncreneau-Signature: sha256=test" \
-d '{"id":"evt_test","type":"appointment.created"}'

# Devrait retourner 401 (signature invalide) ou 200

Étape 4: Déploiement Progressif​

Stratégie Blue-Green​

# 1. Déployer la nouvelle version (green)
# Mais sans router le trafic

# 2. Tester la version green
curl https://green.votre-app.com/health

# 3. Créer un rendez-vous de test
curl -X POST https://green.votre-app.com/api/appointments \
-H "X-API-Key: $MONCRENEAU_API_KEY" \
-d '{ ... }'

# 4. Vérifier que le webhook arrive
# Vérifier dans les logs: "Webhook received: appointment.created"

# 5. Si OK, router le trafic vers green
# 6. Surveiller les métriques pendant 1h
# 7. Si OK, supprimer blue

Déploiement par Feature Flags​

const FeatureFlags = {
ALLOW_APPOINTMENTS: process.env.FEATURE_ALLOW_APPOINTMENTS === 'true',
WEBHOOK_PROCESSING: process.env.FEATURE_WEBHOOK_PROCESSING === 'true'
};

function canCreateAppointment() {
if (!FeatureFlags.ALLOW_APPOINTMENTS) {
throw new Error('Appointment creation is temporarily disabled');
}
return true;
}

// Activer progressivement
// 1. Déployer avec flags désactivés
// 2. Activer pour 10% du trafic
// 3. Augmenter progressivement à 100%

Déploiement Canary​

// Router une partie du trafic vers la nouvelle version
const shouldUseNewVersion = () => {
const percentage = parseInt(process.env.CANARY_PERCENTAGE || '0');
return Math.random() * 100 < percentage;
};

async function createAppointment(data) {
if (shouldUseNewVersion()) {
return createAppointmentV2(data);
}
return createAppointmentV1(data);
}

Étape 5: Vérifications Post-Déploiement​

Tests en Production​

[object Object]

Monitoring Renforcé Initial​

// Alertes plus strictes les premiers jours
const alertThresholds = {
production_first_week: {
errorRate: 0.01, // 1% (vs 5% normal)
responseTime: 200, // 200ms (vs 500ms normal)
webhookDelay: 5 // 5s (vs 60s normal)
}
};

// Logs détaillés temporaires
if (isFirstWeekInProduction()) {
logger.level = 'debug';
logger.info('Running in first week mode - enhanced logging');
}

Étape 6: Gestion des Crédits​

Vérifier le Solde​

async function checkCreditsBeforeLaunch() {
const response = await api.get('/organizations/me');
const credits = response.data.availableCredits;

console.log(`Available credits: ${credits}`);

if (credits < 100) {
console.warn('⚠️ Low credits! Consider purchasing more.');
}

return credits;
}

Alertes de Crédits​

// Surveiller le solde de crédits
setInterval(async () => {
const org = await api.get('/organizations/me');
const credits = org.data.availableCredits;

if (credits < 50) {
await sendAlert('ALERT: Only ' + credits + ' credits left!');
} else if (credits < 100) {
await sendAlert('WARNING: Less than 100 credits remaining');
}
}, 3600000); // Toutes les heures

Rollback​

Plan de Rollback Rapide​

# 1. Si problème critique détecté
# 2. Revenir immédiatement à la version précédente

# Heroku
heroku releases:rollback

# Kubernetes
kubectl rollout undo deployment/votre-app

# Docker
docker-compose down
docker-compose -f docker-compose.old.yml up -d

# 3. Vérifier que l'app fonctionne
curl https://votre-app.com/health

Critères de Rollback​

Déclencher un rollback si:

  • ❌ Taux d'erreur > 10% pendant 5 minutes
  • ❌ Temps de réponse > 2 secondes
  • ❌ Webhooks non reçus depuis 10 minutes
  • ❌ Crédits consommés anormalement vite
  • ❌ Plus de 5 rapports d'erreur utilisateur

Checklist de Déploiement​

Avant le Déploiement​

  • Tous les tests passent
  • Clés API obtenues et sécurisées
  • Variables d'environnement configurées
  • URL webhook configurée et testée
  • Monitoring et alertes activés
  • Équipe prévenue (date et heure)
  • Plan de rollback documenté
  • Backup des données actuelles fait

Pendant le Déploiement​

  • Déploiement en heures creuses
  • Monitoring en temps réel actif
  • Équipe disponible (dev + ops)
  • Communication aux utilisateurs envoyée
  • Premier rendez-vous de test créé
  • Webhook de test reçu et traité
  • Métriques normales (erreurs, latence)

Après le Déploiement​

  • Surveillance renforcée pendant 24h
  • Aucune erreur critique détectée
  • Webhooks reçus correctement
  • Crédits consommés normalement
  • Utilisateurs satisfaits (pas de plaintes)
  • Documentation mise à jour
  • Post-mortem si incidents

Communication​

Annonce aux Utilisateurs​

📢 Maintenance Planifiée

Date: [Date de votre maintenance]
Heure: 02:00 - 04:00 GMT
Durée: Environ 30 minutes

Pendant cette période, notre système de rendez-vous sera
temporairement indisponible. Les rendez-vous existants ne
sont pas affectés.

Merci de votre compréhension !

Notification de Succès​

✅ Déploiement Terminé

Notre système de prise de rendez-vous a été mis à jour avec succès.
Vous pouvez continuer à utiliser le service normalement.

Si vous rencontrez le moindre problème, contactez-nous
immédiatement.

Troubleshooting​

Erreur: "Invalid API Key"​

// Vérifier l'environnement
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('API Key:', process.env.MONCRENEAU_API_KEY?.substring(0, 10));

// Vérifier que la clé est bien définie
if (!process.env.MONCRENEAU_API_KEY) {
console.error('❌ API Key not set!');
}

Webhooks Non Reçus​

# 1. Vérifier l'URL configurée
# Dashboard > Webhooks > Configuration > URL

# 2. Tester manuellement
curl -X POST https://votre-app.com/webhooks/moncreneau \
-d '{"id":"evt_test","type":"appointment.created"}'

# 3. Vérifier les logs du serveur
tail -f /var/log/app.log | grep webhook

# 4. Vérifier le pare-feu
# L'IP de MONCRENEAU doit être autorisée

Crédits Consommés Trop Vite​

// Audit des créations de rendez-vous
const recentAppointments = await db.appointments.find({
createdAt: { $gte: new Date(Date.now() - 3600000) } // 1h
});

console.log(`${recentAppointments.length} appointments in last hour`);

// Si anormal, suspendre temporairement
if (recentAppointments.length > 100) {
console.error('⚠️ Abnormal appointment rate!');
// Déclencher une alerte
// Potentiellement désactiver la création temporairement
}

Monitoring et Observabilité​

Métriques Essentielles​

// Exemple avec Prometheus
const apiRequestsTotal = new Counter({
name: 'moncreneau_api_requests_total',
help: 'Total API requests',
labelNames: ['method', 'status']
});

const apiDuration = new Histogram({
name: 'moncreneau_api_duration_seconds',
help: 'API request duration'
});

const creditsGauge = new Gauge({
name: 'moncreneau_credits_available',
help: 'Available credits'
});

Logs Structurés​

logger.info('Appointment created', {
requestId: req.id,
appointmentId: appointment.id,
organizationId: org.id,
duration: Date.now() - start,
creditsRemaining: org.availableCredits
});

Sécurité en Production​

HTTPS Obligatoire​

// Forcer HTTPS en production
app.use((req, res, next) => {
if (process.env.NODE_ENV === 'production' && !req.secure) {
return res.redirect('https://' + req.headers.host + req.url);
}
next();
});

Rate Limiting​

const rateLimit = require('express-rate-limit');

const apiLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100, // Max 100 requêtes par minute
message: 'Too many requests, please try again later.'
});

app.use('/api/', apiLimiter);

Headers de Sécurité​

const helmet = require('helmet');
app.use(helmet());

// Headers personnalisés
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
next();
});

Ressources​