- Programme de parrainage (referrals): * Page /parrainage pour clients et staff * API /api/referrals (GET, POST) * Table referrals avec tracking complet * Email template avec design orange/gradient * Réductions: 30€ HT parrain, 20€ HT filleul - Bannières promotionnelles (promo_banners): * Page staff /staff/offres-promo pour gérer les bannières * API /api/promo-banners (CRUD complet) * Composant PromoBanner affiché en haut de l'espace * Compte à rebours optionnel * Customisation couleurs (gradient, texte, CTA) - Déduplication des webhooks DocuSeal: * Table webhook_events pour tracker les webhooks traités * Helper checkAndMarkWebhookProcessed() * Intégré dans docuseal-amendment et docuseal-amendment-completed * Prévient les doublons d'emails - Avenants signés: * API GET /api/contrats/[id]/avenants * Affichage des avenants signés dans DocumentsCard * Génération d'URLs presignées S3 - Brouillons d'emails groupés: * Table bulk_email_drafts pour sauvegarder les brouillons * Template HTML bulk-email-template.html - Améliorations ContractsGrid: * Ajout filtre par production (dépendant de la structure) * Tri par production - Templates emails: * referral-template.html (parrainage) * bulk-email-template.html (emails groupés staff)
62 lines
2.5 KiB
PL/PgSQL
62 lines
2.5 KiB
PL/PgSQL
-- Migration: Création de la table de déduplication des webhooks
|
|
-- Date: 2025-10-31
|
|
-- Description: Empêcher les doublons d'emails quand DocuSeal envoie le même webhook plusieurs fois
|
|
|
|
-- Créer la table webhook_events
|
|
CREATE TABLE IF NOT EXISTS public.webhook_events (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Identifiant unique du webhook (submission_id + timestamp + event_type)
|
|
webhook_key TEXT NOT NULL UNIQUE,
|
|
|
|
-- Type de webhook (avenant_signature, contrat_signature, etc.)
|
|
event_type TEXT NOT NULL,
|
|
|
|
-- ID de la soumission DocuSeal
|
|
submission_id TEXT NOT NULL,
|
|
|
|
-- Données du webhook (pour debug)
|
|
payload JSONB,
|
|
|
|
-- Timestamps
|
|
processed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- Index pour recherche rapide
|
|
CREATE INDEX IF NOT EXISTS idx_webhook_events_key ON public.webhook_events(webhook_key);
|
|
CREATE INDEX IF NOT EXISTS idx_webhook_events_submission_id ON public.webhook_events(submission_id);
|
|
CREATE INDEX IF NOT EXISTS idx_webhook_events_event_type ON public.webhook_events(event_type);
|
|
CREATE INDEX IF NOT EXISTS idx_webhook_events_created_at ON public.webhook_events(created_at DESC);
|
|
|
|
-- RLS (Row Level Security)
|
|
ALTER TABLE public.webhook_events ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Policy: Seul le service role peut écrire (les webhooks)
|
|
-- Pas besoin de lecture publique
|
|
CREATE POLICY "Service role can manage webhook_events"
|
|
ON public.webhook_events
|
|
FOR ALL
|
|
TO service_role
|
|
USING (true)
|
|
WITH CHECK (true);
|
|
|
|
-- Commentaires
|
|
COMMENT ON TABLE public.webhook_events IS 'Table de déduplication des webhooks pour éviter les doublons d''emails';
|
|
COMMENT ON COLUMN public.webhook_events.webhook_key IS 'Clé unique composée de submission_id + timestamp + event_type';
|
|
COMMENT ON COLUMN public.webhook_events.event_type IS 'Type de webhook: avenant_employer_signed, avenant_completed, etc.';
|
|
COMMENT ON COLUMN public.webhook_events.submission_id IS 'ID de la soumission DocuSeal';
|
|
COMMENT ON COLUMN public.webhook_events.payload IS 'Données brutes du webhook (pour debug)';
|
|
|
|
-- Nettoyage automatique des vieux événements (> 30 jours)
|
|
-- Créer une fonction pour nettoyer
|
|
CREATE OR REPLACE FUNCTION clean_old_webhook_events()
|
|
RETURNS void AS $$
|
|
BEGIN
|
|
DELETE FROM public.webhook_events
|
|
WHERE created_at < NOW() - INTERVAL '30 days';
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- Commentaire sur la fonction
|
|
COMMENT ON FUNCTION clean_old_webhook_events() IS 'Nettoie les événements webhook de plus de 30 jours';
|