← Volver a proyectos

4Korners Member Portal

Una plataforma de membresías en producción para una organización sin fines de lucro de Montreal. Gestiona el registro y el inicio de sesión, las membresías con Stripe, las donaciones, un catálogo de actividades y un panel de administración. La construí y la opero yo solo, desde la base de datos hasta el pipeline de despliegue.

Arquitectura

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
Pagos con Stripe y Zeffy. El CRM se sincroniza desde Airtable mediante una caché de lectura diaria.

Una aplicación Next.js respaldada por Postgres con Drizzle. Se sincroniza con el CRM Airtable de la organización mediante una caché de lectura que se refresca una vez al día, cobra pagos con Stripe y donaciones con Zeffy, y coloca cada pantalla de administración detrás de un control de acceso basado en roles.

Decisiones clave

Una caché SQL en vez de llamadas en vivo a Airtable

El límite de la API de Airtable no podía servir el portal directamente. Copio los datos del CRM, que cambian poco, en Postgres una vez al día y leo de ahí, así que las páginas que ven los miembros se mantienen rápidas y nunca tocan el límite.

Estado de membresía derivado, calculado y no almacenado

Si un miembro está activo, vencido o en periodo de gracia se calcula a partir de sus pagos cuando carga la página, no se guarda como bandera. Eso mantiene una sola fuente de verdad y no deja ningún estado obsoleto que reconciliar.

La parte difícil

Los escáneres de correo quemaban los enlaces de confirmación

Los escáneres de seguridad de correo precargan los enlaces para revisarlos. Abrían el enlace de confirmación antes que el usuario y gastaban el token, que solo funciona una vez, así que fallaban registros reales. La corrección fue dejar de tratar un GET simple como confirmación y exigir una acción explícita del usuario.

Seguridad y rendimiento

  • Los administradores deben pasar un segundo factor (TOTP con códigos de respaldo) para llegar a cualquier pantalla que muestre datos personales.
  • Los endpoints de inicio de sesión y correo tienen límite de tasa, y las server actions de producción están bloqueadas a su origen.
  • Para cumplir con la Ley 25, los consentimientos se capturan al registrarse, y una solicitud de borrado se cumple tanto en el portal como en el CRM.

Stack

Next.js 15TypeScriptPostgreSQLDrizzle ORMAuth.js v5StripeZeffyDockerGitHub Actions