← Retour aux projets

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

4Korners portal architectureA browser reaches the Next.js portal through a Caddy TLS proxy on a VPS. The portal reads and writes PostgreSQL, receives Stripe and Zeffy webhooks, writes to the Airtable CRM, and refreshes from it asynchronously.EXTERNAL SERVICESON THE VPSHTTPSREAD/WRITEWEBHOOKWRITESREFRESHStripeZeffyAirtableBrowserCaddyPortalPostgreSQLmembershipdonationsCRMTLSNext.jsUSERPROXYAPPSTORELEGENDHTTP / webhookinternalasync refreshfocal
Paiements via Stripe et Zeffy. Le CRM se synchronise depuis Airtable via un cache de lecture quotidien.

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.

Stack

Next.js 15TypeScriptPostgreSQLDrizzle ORMAuth.js v5StripeZeffyDockerGitHub Actions