A
Arquitectura del sistema
Power Pilates

Arquitectura del sistema

Cómo está construido Amalfi por dentro: las piezas, dónde viven los datos y cómo fluyen los pagos.

En resumen

Tres aplicaciones

Una para tus clientas (reservar y pagar), una para tu equipo (recepción, instructor, admin) y una interna de Amalfi.

Datos seguros y separados

Cada estudio tiene sus datos aislados de los demás. Nadie de otro estudio puede ver tu información.

Pagos directos a ti

El dinero de tus clientas llega directo a tu cuenta vía Wompi. Amalfi te cobra aparte su suscripción.

El detalle técnico de abajo es para el equipo de desarrollo. No hace falta entenderlo para usar el producto.

Stack técnico
Laravel 13PHP 8.4FilamentNext.js 16React 19Tailwind v4shadcn/uistancl/tenancyPostgreSQLRedisSanctumCloudflare R2WompiStripeResend

Forma general — multi-repo

Backend monolito Laravel (API + Filament) en su propio repo, más dos frontends Next.js independientes y los SDKs propios de Wompi. No es monorepo ni Inertia: cada frontend tiene su SSR, NextAuth e i18n.

Repo Tech Rol
amalfi-core Laravel 13 · PHP 8.4 API backend (monolito) + Filament admin
amalfi-dashboard Next.js 16 · React 19 Back Office (operadores del estudio)
amalfi-web Next.js 16 · React 19 Front Office (clientes finales)
wompi-laravel · wompi-sdk-php PHP SDK / integración Wompi propia

Diagrama de componentes

Tres audiencias entran por sus frontends; el Core Laravel orquesta datos, cache y storage en Laravel Cloud, y se integra con los proveedores externos de pago, payout y email. Fuente: ASM Amalfi V1.

Diagrama de componentes de Amalfi: Studios, Customers y Admins entran por Back Office (Next.js), Front Office (Next.js) y Admin Panel (Filament); el Core/Dashboard en Laravel orquesta PostgreSQL, Redis y Cloudflare R2 dentro de Laravel Cloud, e integra Stripe (payout), Wompi (payment gateway) y Resend (SMTP).

Multi-tenancy — row-based (stancl/tenancy)

Single-database, row-scoping por studio_id vía el trait BelongsToTenant. La resolución de tenant en Back Office es por usuario autenticado (no por dominio). Camino soportado a DB dedicada por estudio cuando uno crezca.

Superficies y dominios
Front Office (clientes)[estudio].amalfi.app
Back Office (operadores)dashboard.amalfi.app
Admin Panel (Amalfi)admin.amalfi.app

El Front Office se sirve bajo subdominio dinámico por estudio, con dominio custom configurable. Back Office y Admin Panel son dominios fijos.

Dos integraciones de dinero separadas: Wompi procesa el pago de la alumna al estudio (el estudio recibe el 100%); Stripe cobra a los estudios la suscripción + comisión de Amalfi, configurable por estudio desde Filament.

Backend (amalfi-core)
Framework Laravel 13
Lenguaje PHP 8.4
Admin Filament
Tenancy stancl/tenancy
API auth Sanctum 🟡
Tests PestPHP
Frontends (Next.js)
Framework Next.js 16
UI lib React 19
Lenguaje TypeScript
Estilos Tailwind v4
UI shadcn/ui
Auth NextAuth 5
Infra
Core Laravel Cloud
Frontends Cloud Run / CF 🔴
DB PostgreSQL
Cache Redis 🟡
Storage Cloudflare R2 🟡
Email Resend 🟡
en uso 🟡 planeado / en build 🔴 decisión pendiente

Aislamiento de tenants — cómo funciona

Single-database, shared schema con aislamiento por studio_id. stancl/tenancy maneja resolución de tenant, scoping (vía Global Scopes de Eloquent) y bootstrapping en jobs/colas. La resolución en Back Office es por usuario autenticado (no por dominio). El superadmin puede impersonar cualquier estudio con flag auditado. Tests automatizados verifican que un usuario de un estudio no accede a datos de otro.

Resolución de tenant
usuario autenticado → studio_id activo

En Back Office el tenant se resuelve por el usuario autenticado, no por subdominio. stancl/tenancy lo inicializa para la request y los jobs.

Scoping automático
BelongsToTenant → WHERE studio_id = ?

Los modelos tenant aplican el trait BelongsToTenant. El scope se inyecta en cada query (joins, subqueries y eager loads incluidos).

Superadmin bypass
impersonation con audit log

El panel Filament puede impersonar cualquier estudio saltándose los scopes, con flag auditado. Camino soportado: graduar un estudio a su propia DB.

Decisiones de arquitectura (del repo)

Stateless (target)

Sesiones/cache en Redis, storage en R2 → sin disco local, habilita escalado horizontal. Hoy corre en drivers database; mover a Redis + R2 es cambio de configuración, no de código.

Async-first

Lo que no es necesario para la respuesta inmediata corre en job encolado (email de confirmación, recibos, webhooks de Wompi).

Arquitectura modular

app/Modules/ organizado en buckets Central/ (staff Amalfi) y Tenant/ (datos del estudio), con generadores propios (MakeModuleCommand y demás).

Toolchain estricto

composer check = Pint + PHPStan (level max) + Rector + composer-normalize + Pest. Requisitos: PHP 8.4, PostgreSQL, Node 22, Composer 2.

Flujos críticos

Reserva online (alumna)
  1. 1 Alumna elige clase en el Front Office (amalfi-web)
  2. 2 API valida créditos disponibles con el scope de tenant
  3. 3 Reserva con pessimistic lock sobre el cupo de la sesión
  4. 4 Job en queue: email de confirmación vía Resend
  5. 5 Clase aparece en "Mis reservas" inmediatamente
Compra de paquete — Wompi
  1. 1 Alumna selecciona paquete en el Front Office
  2. 2 API crea la sesión de pago y redirige a Wompi hosted checkout
  3. 3 Alumna paga con tarjeta en el widget de Wompi
  4. 4 Wompi → webhook firmado → job ProcessWompiWebhook
  5. 5 Job activa el client_package + Resend recibo de compra
Cierre mensual — Amalfi (Stripe)
  1. 1 Scheduler calcula comisiones sobre las transactions del mes
  2. 2 Job GenerateMonthlyInvoice por estudio
  3. 3 Stripe: suscripción fija en su ciclo + comisión los días 3–5
  4. 4 Configurable por estudio desde Filament (superadmin)
  5. 5 amalfi_invoices actualiza status → paid