Saltar a contenido

Visión General

Arquitectura de alto nivel

graph TB
    subgraph Clientes["Clientes"]
        ERP1["ERP Cliente A"]
        ERP2["ERP Cliente B"]
        DASH["Dashboard Admin"]
    end

    subgraph CF["Cloudflare"]
        WORKER["⚡ Worker<br/>Hono + OpenAPI"]
        D1["🗄️ D1 Database<br/>SQLite"]
        CRON["⏰ Cron Trigger<br/> Token Refresh"]
    end

    subgraph MP["MercadoPago"]
        MPAPI["API v1"]
        MPOAUTH["OAuth Server"]
        MPWEBHOOK["Webhook Sender"]
    end

    ERP1 -->|"x-api-token: mk_..."| WORKER
    ERP2 -->|"x-api-token: mk_..."| WORKER
    DASH -->|"x-api-token"| WORKER

    WORKER <-->|"Bearer token"| MPAPI
    WORKER <-->|"PKCE Flow"| MPOAUTH
    MPWEBHOOK -->|"HMAC-SHA256"| WORKER

    WORKER <--> D1
    CRON --> WORKER

Flujo de una orden de pago

sequenceDiagram
    participant ERP
    participant API as Integration API
    participant DB as D1 Database
    participant MP as MercadoPago

    ERP->>API: POST /orders (caja_id, amount)
    API->>DB: Buscar POS → obtener terminal
    API->>MP: POST /v1/orders (terminal_id, amount)
    MP-->>API: order_id, status: "created"
    API->>DB: Guardar orden
    API-->>ERP: 201 { order_id, status }

    Note over MP: El cliente paga en la terminal

    MP->>API: Webhook order.processed
    API->>DB: Actualizar estado orden
    API-->>MP: 200 OK

    ERP->>API: GET /orders/:orderId
    API->>DB: Buscar orden local
    API->>MP: GET /v1/orders/:id (estado real)
    MP-->>API: status: "processed", payments: [...]
    API->>DB: Actualizar si cambió
    API-->>ERP: 200 { status, payments, refunds }

Capas del sistema

graph TD
    subgraph Request["Request Layer"]
        MW1["Security Middleware<br/>adminToken() / clientToken()"]
        MW2["Activity Log Middleware"]
        MW3["Webhook Signature Middleware"]
    end

    subgraph Routes["Route Layer"]
        R1["OAuth Routes"]
        R2["Store Routes"]
        R3["Terminal Routes"]
        R4["Order Routes"]
        R5["Webhook Routes"]
        R6["API Key Routes"]
        R7["Admin Routes"]
        R8["Health Routes"]
    end

    subgraph Business["Business Layer"]
        DB["lib/database.ts<br/>Queries & mutations"]
        MPLIB["lib/mercadopago.ts<br/>mpRequest() centralizado"]
        KEYS["lib/api-key.ts"]
        PKCE["lib/pkce.ts"]
    end

    subgraph Data["Data Layer"]
        D1DB["Cloudflare D1"]
        MPAPI["MercadoPago API"]
    end

    MW1 --> Routes
    MW2 --> Routes
    MW3 --> R5
    Routes --> Business
    DB --> D1DB
    MPLIB --> MPAPI

Multi-tenancy

Cada cliente es completamente aislado:

graph LR
    subgraph ClienteA["Cliente A"]
        KEY_A["API Key: mk_abc..."]
        OAUTH_A["OAuth Token MP"]
        STORES_A["Stores + POS"]
        ORDERS_A["Orders"]
    end

    subgraph ClienteB["Cliente B"]
        KEY_B["API Key: mk_xyz..."]
        OAUTH_B["OAuth Token MP"]
        STORES_B["Stores + POS"]
        ORDERS_B["Orders"]
    end

    API["Integration API"]
    API --> ClienteA
    API --> ClienteB
  • Cada cliente tiene su propia cuenta de MercadoPago (OAuth independiente)
  • Las API keys identifican al cliente automáticamente
  • Todas las queries filtran por client_name
  • Un cliente nunca puede ver datos de otro