Files
balam/bind-api-sandbox/README.md
T
JohannVelazquez 633d05e330 Reorganiza repo como fuente de la verdad + propuesta v1.0 con emisión de facturas
- Estructura nueva: README maestro, bitacora/ (REGISTRO, PENDIENTES, plantillas),
  propuesta/, fuentes/; material superado a _archivado/
- Propuesta v1.0: MVP BIND-first con emisión asistida MXN/USD (dry-run +
  confirmación, timbra PAC de BIND), 112-136 h / $67,200-$81,600 + IVA,
  stack .NET 10 + EF Core + Angular 21 + PostgreSQL 17 sobre Azure
- Bitácora: historial de correos + 2 llamadas (incl. revisión 4-jun) y pendientes
- Prototipo y diagrama actualizados a v1.0; precios de Azure verificados
- Archivo ajeno (proyecto EOS) retirado del repo

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 10:57:27 -06:00

160 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BIND ERP API · sandbox local
Sandbox para validar la integración del MVP **BIND-first** de Balam **sin tocar producción**.
Está pensado para que tú (Johann), Pedro (Balam) o un futuro dev puedan:
1. Entender la forma real del API de BIND ERP antes de tener el API key.
2. Probar el cliente tipado contra un mock que replica los headers, el formato OData y el rate-limit observable de BIND.
3. Cuando Pedro entregue las credenciales reales, **cambiar dos variables de entorno** y apuntar el mismo código a `https://api.bind.com.mx` sin reescribir nada.
---
## TL;DR del API de BIND (lo que descubrí del discovery)
| Tema | Hallazgo |
|---|---|
| **Base URL** | `https://api.bind.com.mx` |
| **Estilo** | REST con sintaxis **OData v3** (filtros `$filter`, `$top`, `$skip`, `$orderby`, `$count`, IDs como `guid'...'`) |
| **Auth** | Dos headers: `Authorization: Bearer <API_KEY>` + `Ocp-Apim-Subscription-Key: <SUBSCRIPTION_KEY>` (este último cuando aplica) |
| **Origen del API key** | Cuenta BIND → Perfil de usuario → pestaña *Integraciones* |
| **Rate limit** | **20,000 peticiones / día** (confirmado por Noe, 25-may-2026) |
| **Sandbox oficial** | **No existe.** BIND recomienda Postman contra producción → razón #1 de este sandbox |
| **Portal dev** | [developers.bind.com.mx](https://developers.bind.com.mx) (login requerido para ver schemas detallados) |
| **PAC para CFDI** | Integrado dentro del propio BIND — la plataforma de Balam **no toca el SAT**, solo orquesta |
| **Recursos confirmados** | `Activities`, `Customers`, `Products` (y según el discovery doc: `Invoices`, `Payments`, `Quotes` muy probables) |
### Por qué un sandbox propio y no Postman
- BIND solo tiene producción → cualquier `POST` real toca facturas reales con consecuencias fiscales.
- El contrato exacto está detrás de login → necesitamos un lugar donde ir **acumulando lo que aprendemos** del API real conforme Pedro nos dé acceso.
- Tener el contrato en código (TypeScript + tipos) hace que **el motor de cobranza del MVP se pueda probar con CI** sin depender de la red.
- Cuando llegue Belvo / BUK en Fase 2 esta misma estructura sirve como plantilla.
---
## Cómo correrlo
Requiere Node 20+.
```powershell
# 1) Instalar deps
cd bind-api-sandbox
npm install
# 2) Levantar el mock en una terminal
npm run mock
# -> [bind-mock] escuchando en http://localhost:4010
# 3) Correr la demo end-to-end en otra terminal
npm run demo
```
La demo ejecuta 5 escenarios alineados al MVP:
| # | Escenario | Qué demuestra |
|---|---|---|
| 1 | Listar clientes activos | Cómo se construye la query OData base del dashboard |
| 2 | Facturas vencidas (`Status eq 'overdue' and DueDate lt ...`) | El motor de cobranza |
| 3 | CxC agregada por cliente (MXN) | KPI directivo del dashboard |
| 4 | Factura USD a cliente extranjero | Regla sin-IVA + TC fijado al emitir |
| 5 | Intento de `POST /Activities` en modo read-only | El guardrail que evita escribir a BIND prod por accidente |
Output esperado (verificado):
```
── 2. Facturas vencidas — motor de cobranza
┌─────────┬──────────┬────────────┬──────────────┬──────────┬─────────┐
│ Folio │ Cliente │ DueDate │ Currency │ Balance │
│ 'A-0003' │ '22222222' │ '2026-04-01' │ 'MXN' │ 20880 │
│ 'A-0005' │ '11111111' │ '2026-05-20' │ 'MXN' │ 62640 │
── 5. Intento de escritura en read-only (debe BLOQUEARSE)
✅ Guardrail OK: Read-only mode bloqueó POST /api/Activities. Cambia BIND_MODE=write...
Stats del cliente
{ requestsToday: 6, quota: 20000, remaining: 19994, mode: 'read-only' }
```
### Apuntar a producción (cuando llegue el API key)
Solo cambiar variables de entorno — el código no se modifica:
```powershell
$env:BIND_BASE_URL = "https://api.bind.com.mx"
$env:BIND_API_KEY = "<key del perfil de usuario de Balam>"
$env:BIND_SUBSCRIPTION_KEY = "<si aplica>"
$env:BIND_MODE = "read-only" # mantenlo así hasta tener autorización para escribir
npm run demo
```
---
## Mapeo a la arquitectura de Balam
Este sandbox es el prototipo de lo que en el repo principal vivirá en `packages/integrations/bind/`:
```
balam/
└── packages/
└── integrations/
└── bind/
├── BindClient.ts ← este sandbox lo prototipa
├── types.ts ← este sandbox lo prototipa
├── odata.ts ← este sandbox lo prototipa
└── README.md
apps/
└── worker/
└── src/
└── modules/
└── bind-sync/ ← consume BindClient, escribe a Postgres,
respeta tenant_id + outbox pattern
```
El cliente está pensado para encajar con los principios del proyecto (ver `01 - ARQUITECTURA-TECNICA.md`):
- **Modo seguro por default** (`read-only`): bloquea `POST/PUT/PATCH/DELETE` en código. Cumple §1 "La plataforma no escribe a BIND en MVP".
- **Dry-run** opcional: imprime el request sin enviarlo (cumple §1 punto 2 "Modo dry-run disponible en cualquier acción con efecto externo").
- **Idempotencia preparada**: el método `addActivity` está aislado para que cuando se autorice escritura, sea fácil envolverlo con `idempotency_key`.
- **Quota awareness**: el cliente lleva un contador local de requests del día y avisa cuando se acerca al límite de 20K.
- **Retries con backoff** en 429 y 5xx, respetando `Retry-After`.
---
## Decisiones de discovery que este sandbox **acelera**
Estos son los puntos del `03_Anexo_Tecnico_Integraciones_Discovery_Balam.docx` y del `04_Checklist_Accesos_Datos_Dependencias_Balam.docx` que dejan de estar "pendientes de validar" en cuanto se ejecuta esta prueba con un API key real:
| Item del discovery | Cómo lo cierra este sandbox |
|---|---|
| Tipo de autenticación, headers requeridos | Ya implementado en `BindClient`: dos headers, listos para producción |
| Estructura de URLs por recurso | Confirmada (`/api/{Recurso}` + OData) y probada en mock |
| Operaciones de lectura: clientes, facturas, pagos | Demo las ejerce todas. Una vez con API key, basta correr `BIND_BASE_URL=https://api.bind.com.mx npm run demo` |
| Filtros y paginación (`$filter`, `$top`, `$skip`) | Validados contra mock con la misma sintaxis que documenta BIND |
| Estrategia de pruebas sin sandbox | **Esta es la respuesta**: mock local + cliente tipado + modos read-only / dry-run / write |
| Rate limits | El cliente cuenta requests; el mock simula `?simulate=throttle` para probar el backoff |
---
## Pendientes para cerrar con Pedro (sugerencia de mail)
> Pedro, para destrabar la integración con BIND necesitamos:
>
> 1. **API key** generado desde *Perfil → Integraciones* en la cuenta de Balam, idealmente con permisos **solo lectura** primero.
> 2. **Subscription Key** si el plan de Balam la requiere (algunos planes en Azure API Management la piden además del Bearer).
> 3. Confirmación del **plan contratado** — para saber si 20K req/día aplica o si está reducido.
> 4. **Schema exacto** del recurso `Invoices` (especialmente nombres de campos `UUID`, `Folio`, `Status`, `Balance`). Una llamada de ejemplo con una factura real anonimizada serviría: `GET /api/Invoices?$top=1`.
> 5. ¿Existe endpoint para descargar **XML/PDF del CFDI**? Por la doc parece que sí, pero falta confirmar la ruta exacta.
>
> Con (1)(2) podemos correr el sandbox apuntando a `https://api.bind.com.mx` y validar lo demás de un jalón sin necesidad de otra llamada.
---
## Limitaciones honestas de este sandbox
- **El schema de `Invoice`, `Customer`, etc. es una aproximación** — está modelado a partir de la doc pública y del flujo que necesita Balam, no del SDK oficial. Cuando salga el primer `GET` real contra producción, hay que reconciliar nombres de campos (especialmente capitalización y campos opcionales).
- **El mock acepta cualquier Bearer**, solo valida que exista. No es un servidor de auth real, es un placeholder.
- **El parser de OData del mock solo cubre lo que el cliente genera** (`eq, ne, gt, lt, ge, le, and, or`, paréntesis). No soporta `contains`, `startswith`, funciones, lambdas. Suficiente para el MVP.
- **No reproduce la lógica de `$expand`** — si BIND lo soporta para traer `Lines` o `Customer` embebidos, hay que extender.
Cuando alguno de estos límites se vuelva una piedra en el zapato, se extiende. Hoy es deliberadamente mínimo.