4Korners Member Portal
Une plateforme d'adhésion en production pour un organisme à but non lucratif de Montréal. Elle gère l'inscription et la connexion, les adhésions Stripe, les dons, un catalogue d'activités et un back office admin. Je l'ai construite et je l'exploite seul, de la base de données au pipeline de déploiement.
Architecture
Une application Next.js adossée à Postgres avec Drizzle. Elle se synchronise avec le CRM Airtable de l'organisme via un cache de lecture rafraîchi une fois par jour, encaisse les paiements par Stripe et les dons par Zeffy, et place chaque écran d'administration derrière un contrôle d'accès fondé sur les rôles.
Décisions clés
Un cache SQL plutôt que des appels Airtable en direct
La limite de débit de l'API Airtable ne pouvait pas servir le portail directement. Je copie les données du CRM, qui changent peu, dans Postgres une fois par jour et je lis à partir de là, donc les pages que voient les membres restent rapides et n'atteignent jamais la limite.
Un statut d'adhésion dérivé, calculé et non stocké
Le fait qu'un membre soit actif, expiré ou en délai de grâce est calculé à partir de ses paiements au moment du chargement, et non stocké sous forme d'indicateur. Cela garde une seule source de vérité et ne laisse aucun statut périmé à réconcilier.
Le point difficile
Les scanners de courriel brûlaient les liens de confirmation
Les scanners de sécurité des courriels préchargent les liens pour les vérifier. Ils ouvraient le lien de confirmation avant l'utilisateur et consommaient le jeton, qui ne fonctionne qu'une fois, donc de vraies inscriptions échouaient. La correction a été d'arrêter de traiter un simple GET comme une confirmation et d'exiger une action explicite de l'utilisateur.
Sécurité et performance
- Les administrateurs doivent passer un second facteur (TOTP avec codes de secours) pour accéder à tout écran affichant des données personnelles.
- Les points d'accès de connexion et de courriel sont limités en débit, et les server actions de production sont verrouillées à leur origine.
- Pour la conformité à la Loi 25, les consentements sont recueillis à l'inscription, et une demande d'effacement est honorée à la fois dans le portail et le CRM.