Version: 0.1.0 · Hono · Drizzle ORM · Neon Postgres · tRPC · Better Auth · Redis
flowchart TB
Client[Cliente / Dashboard / Astro App]
Hono[Hono Server 4.6 + CORS]
Logger[Pino Logger Instance]
Auth[Better Auth 1.6<br/>cookies httpOnly + internal trust]
TRPC[tRPC Router 11.18]
Central[(Neon Postgres<br/>DB Central)]
Satellite[(Neon Postgres<br/>DB Satellite x cliente)]
Redis[(Upstash Redis<br/>Cache)]
WH_MP[POST /webhooks/mercadopago]
WH_Re[POST /webhooks/resend]
MP_SDK[Mercado Pago SDK ⚠️ Stub]
Re_SDK[Resend SDK ⚠️ Stub]
Client -->|HTTP Request| Hono
Hono --> Logger
Hono --> Auth
Auth -->|Sesion valida| TRPC
TRPC --> Central
TRPC --> Satellite
TRPC --> Redis
TRPC -.->|TODO| MP_SDK
TRPC -.->|TODO| Re_SDK
WH_MP --> Central
WH_Re --> Logger
⚠️ Nota: Arcjet WAF (middleware de seguridad) y Pino Logger middleware estan implementados pero no activos ensrc/index.ts. Se activaran en una proxima version.
| Tecnologia | Version package.json | Proposito | Estado |
|---|---|---|---|
| Hono | ^4.6.x | Framework web ultraligero (14KB) | ✅ Activo |
| Drizzle ORM | 1.0.0-rc.4 | ORM tipado con SQL nativo | ✅ Activo |
| Neon | @neondatabase/serverless ^0.9.0 | PostgreSQL serverless | ✅ Activo |
| tRPC | ^11.18.0 | APIs end-to-end type-safe | ✅ Activo |
| Better Auth | 1.6.23 | Auth con sesiones + cookies httpOnly | ✅ Activo |
| Upstash Redis | ^1.38.0 | Cache en memoria con TTL | ✅ Activo |
| Zod | ^4.4.3 | Validacion de esquemas | ✅ Activo |
| Pino | ^10.3.1 | Logging estructurado | ✅ Activo |
| Biome | ^2.5.2 | Linter + formatter unificado | ✅ Activo |
| Arcjet | ^1.6.1 (Node) | WAF + rate limiting (20 req/s, burst 40) | |
| Mercado Pago | ^2.0.0 | Pagos y suscripciones | |
| Resend | ^4.0.0 | Emails transaccionales | |
| pg | ^8.22.0 | Driver PostgreSQL | ✅ Activo |
| dotenv | ^17.4.2 | Variables de entorno | ✅ Activo |
| TypeScript | ^5.8.0 | Tipado estricto | ✅ Activo |
sequenceDiagram
participant C as Cliente
participant H as Hono Server
participant T as tRPC
participant A as Better Auth
participant D as Neon DB
participant R as Redis
C->>H: POST /trpc/clients.listar (con cookie)
H->>H: CORS check
H->>H: Pino log (entrada)
H->>T: @hono/trpc-server
T->>A: Validar sesion via cookie o x-internal-trust
A->>T: Usuario autenticado
T->>D: Query via Drizzle ORM
T->>R: Cachear resultado (opcional)
T->>H: Response tipado
H->>C: JSON Response
src/
├── index.ts # Entrypoint: Hono + serve() + CORS
├── config.ts # Validacion Zod de env vars (DATABASE_URL, PORT, etc.)
├── middleware/
│ ├── auth.ts # Better Auth (sesiones, cookies httpOnly, internal trust)
│ ├── security.ts # ⚠️ Arcjet WAF + token bucket (no conectado al server)
│ ├── logger.ts # Pino logger + middleware pinoLogger (no conectado)
│ └── error.ts # Error handler global + 404 handler
├── db/
│ ├── client.ts # Conexion Neon (centralDb + getSatelliteDb bajo demanda)
│ ├── migrate.ts # Script de migraciones Drizzle (npx tsx src/db/migrate.ts)
│ └── schema/
│ ├── central.ts # perfiles, clientes, mercadoPagoWebhooks, auditLogs
│ └── satellite.ts # componentesPagina, elementosGaleria, leads, analyticsLogs, dailyAnalyticsSummary
├── services/
│ ├── redis.ts # Upstash Redis cache (get/set/del con TTL) — cliente lazy
│ ├── mercadopago.ts # ⚠️ Stub: crearPreferencia, procesarWebhook
│ └── resend.ts # ⚠️ Stub: enviarEmail
├── trpc/
│ ├── init.ts # tRPC server + middleware de autenticacion
│ ├── context.ts # Contexto (db, user, logger) desde headers + internal trust
│ ├── router.ts # Router raiz (appRouter)
│ └── routes/
│ ├── clients.ts # CRUD clientes multi-tenant (listar, obtener, crear, actualizar, cambiarEstado)
│ ├── pages.ts # Bloques de landing page por cliente (CRUD + reordenar)
│ ├── payments.ts # ⚠️ Stub: crearPreferencia, estadoSuscripcion
│ ├── emails.ts # ⚠️ Stub: enviar
│ └── theme.ts # Tema visual del cliente (colors, font, logo, radius, shadows, overlay, headerStyle, customCSS)
├── webhooks/
│ ├── mercadopago.ts # POST /webhooks/mercadopago — guarda en DB Central + procesa
│ └── resend.ts # POST /webhooks/resend — solo log, TODO actualizar estados
└── lib/
└── utils.ts # formatearError, sleep
Archivos de configuracion en la raiz:
drizzle.config.ts # Configuracion de Drizzle Kit
package.json # v0.1.0
GET /health → { status: "ok", uptime, timestamp }
| Procedimiento | Auth | Input | Descripcion |
|---|---|---|---|
clients.listar |
✅ | — | Listar todos los clientes |
clients.obtener |
✅ | { id: uuid } |
Obtener cliente por ID |
clients.crear |
✅ | { nombre, rut, plan, ... } |
Crear nuevo cliente con RUT chileno |
clients.actualizar |
✅ | { id, data } |
Actualizar datos parciales |
clients.cambiarEstado |
✅ | { id, estado } |
Cambiar estado (pendiente, en_desarrollo, activo, etc.) |
pages.listarBloques |
✅ | { clienteId } |
Bloques del landing ordenados |
pages.agregarBloque |
✅ | { clienteId, bloque } |
Agregar bloque a la pagina |
pages.actualizarBloque |
✅ | { clienteId, bloqueId, data } |
Actualizar bloque existente |
pages.eliminarBloque |
✅ | { clienteId, bloqueId } |
Eliminar bloque |
pages.reordenarBloques |
✅ | { clienteId, orden: [{ id, orden }] } |
Reordenar todos los bloques |
theme.obtener |
✅ | { clienteId } |
Obtener tema (colors, fonts, logo, CSS) |
theme.actualizar |
✅ | { clienteId, theme } |
Actualizar tema completo |
payments.crearPreferencia |
✅ | { titulo, monto, clienteId } |
|
payments.estadoSuscripcion |
✅ | { subscriptionId } |
|
emails.enviar |
✅ | { para, asunto, texto } |
POST /webhooks/mercadopago → Guarda payload en DB + procesa (stub)
POST /webhooks/resend → Solo log, TODO persistir estado
| Estado | Descripcion |
|---|---|
pendiente |
Recien registrado, sin desarrollo iniciado |
en_desarrollo |
En fase de construccion |
en_revision |
Pendiente de aprobacion del cliente |
activo |
Landing en produccion |
impago |
Suspendido por falta de pago |
suspendido |
Suspendido por decision administrativa |
de_baja |
Cliente dado de baja |
- perfiles: Usuarios administradores del dashboard (id, nombre, rol)
- clientes: Inquilinos multi-tenant (id, nombre, rut, plan, estado, dominio, satelliteUrl, theme, etc.)
- mercadoPagoWebhooks: Auditoria de webhooks recibidos (payload, procesado)
- auditLogs: Trazabilidad de acciones
- componentesPagina: Bloques de la landing page (orden, tipo, nombreBloque, contenido)
- elementosGaleria: Items del catalogo/portafolio
- leads: Contactos capturados desde formularios
- analyticsLogs: Eventos de telemetria crudos
- dailyAnalyticsSummary: Resumen diario consolidado
- Multi-Tenancy: DB Central para datos compartidos + DB Satellite por cliente (Neon URL por tenant)
- Type-Safe: tRPC conecta frontend y backend con tipos compartidos
- Auth Segura: Better Auth con cookies httpOnly + Secure + SameSite
- Internal Trust: Mecanismo
x-internal-trustpara llamadas desde el Dashboard sin sesion directa - Config Validada: Zod schema para validacion estricta de env vars al iniciar
- Cache Inteligente: Redis con TTL automatico, cliente lazy (no obligatorio)
- Webhooks con Auditoria: MP webhooks se persisten en DB Central antes de procesar
- Arquitectura Modular: Schemas, servicios y rutas separados por dominio
npm run dev # Desarrollo con hot-reload (tsx watch src/index.ts)
npm run build # Compilacion TypeScript (tsc)
npm run start # Produccion (node dist/index.js)
npm run db:generate # Generar migraciones Drizzle
npm run db:migrate # Ejecutar migraciones
npm run db:push # Push directo del schema
npm run db:studio # Drizzle Studio (GUI de DB)
npm run typecheck # TypeScript check (tsc --noEmit)
npm run lint # Biome check --write
npm run format # Biome format --writeDATABASE_URL=postgres://... # Neon Central DB
CORS_ORIGIN=http://localhost:3000 # Origen permitido
BETTER_AUTH_SECRET=... # Min 32 caracteres
BETTER_AUTH_URL=http://localhost:3001 # URL base del authPORT=3001 # Puerto (default: 3001)
MP_ACCESS_TOKEN=... # Mercado Pago (sin esto → modo simulado)
MP_WEBHOOK_SECRET=... # Firma de webhook MP
RESEND_API_KEY=... # Resend (sin esto → modo simulado)
UPSTASH_REDIS_REST_URL=https://... # Redis (sin esto → cache desactivado)
UPSTASH_REDIS_REST_TOKEN=...
ARCJET_KEY=... # Arcjet WAF (sin esto → WAF desactivado)- Sin
MP_ACCESS_TOKEN, todas las operaciones retornan IDs simulados - Webhook guarda payload en DB pero NO procesa activamente
- TODO: Integrar con SDK oficial
mercadopago
- Sin
RESEND_API_KEY, los emails se loguean pero no se envian - Webhook solo loguea, no actualiza estados en DB
- TODO: Integrar con SDK oficial
resend
- Activar Arcjet WAF middleware en index.ts
- Activar Pino Logger middleware en index.ts
- Integracion real con Mercado Pago SDK
- Integracion real con Resend SDK
- Endpoint de health detallado (DB status, Redis ping)
- Tests E2E con Playwright
Todos los derechos reservados. Proyecto de desarrollo privado — Ecosistema Procyon.