# Arquitectura directa SUNAT

```text
HTTP JSON / SDK
      ↓ Zod
modelo canónico por tenant
      ↓ Decimal
UBL 2.1 (01/03/07/08) o SUNAT RC/RA
      ↓ XMLDSig + verificación + XSD oficial
ZIP en memoria
      ↓ SOAP WS-Security
SUNAT billService / billConsultService
      ↓
CDR + estado + auditoría + artefactos
```

## Capas activas

- `src/domain`: contratos JSON y modelo canónico Zod.
- `src/money`: cálculos exclusivamente con Decimal.
- `src/ubl`: builders UBL 2.1 y contenedores RC/RA.
- `src/signature`, `src/validation`, `src/zip`: integridad local previa a transmisión.
- `src/soap`, `src/cdr`: transporte directo y normalización.
- `src/services`: orquestación sin conocimiento HTTP.
- `src/persistence`: repositorios memoria/Mongoose y secuencias atómicas.
- `src/storage`: artefactos locales o S3.
- `src/routes`: API JSON multitenant.

## Persistencia

Colecciones:

```text
pe_sunat_documents
pe_sunat_sequences
pe_sunat_transmissions
pe_sunat_daily_summaries
pe_sunat_certificates
pe_sunat_tenant_configs
```

La clave única de documento incluye tenant, RUC, tipo, serie, número y ambiente. Otra clave única protege `tenantId + idempotencyKey`. El correlativo usa `findOneAndUpdate + $inc + upsert` y un índice compuesto único.

## Decisión XSD y firma

El `ext:ExtensionContent` oficial espera contenido externo y un documento sin firma no satisface por completo ese punto del XSD. Por eso el orden real es:

```text
validación de dominio → XML bien formado → firma → verificación XMLDSig → XSD oficial completo → ZIP
```

No se inserta una firma falsa para pasar una validación previa ni se modifica el XML después de firmarlo.

## Flujos asíncronos

Boletas y notas asociadas a boletas no usan `sendBill`; quedan `PENDING_SUMMARY` y entran a `RC`. Las bajas permitidas se modelan como `RA`. Ambos usan `sendSummary`, ticket y `getStatus` con backoff y máximo de intentos.

## Recuperación

Un timeout o estado ambiguo no crea otro correlativo. Se conserva la transmisión y se intenta reconciliar con el servicio oficial de consulta CDR cuando está disponible. Los rechazos tributarios, XML inválido, firma inválida y credenciales incorrectas no se reintentan automáticamente.

## Extensiones

`InvoicePdfRenderer` recibe el mismo modelo canónico; nunca reconstruye XML desde PDF. El QR usa el orden oficial SUNAT y el `ds:DigestValue` del XML firmado. `PublicDocumentAccess` genera tokens aleatorios, guarda sólo su HMAC, los liga a tenant/documento/receptor, permite revocarlos y vence por defecto a los 366 días.

`AsynchronousRecoveryWorker` reclama con lease los Resúmenes Diarios y Comunicaciones de Baja en `PROCESSING`/`UNKNOWN`. Así `getStatus` continúa después de un reinicio sin depender del request HTTP original.

En modo productivo el runtime exige repositorio durable, almacenamiento S3 o equivalente, gestor de secretos explícito y un resolvedor de identidad. Los headers tenant inseguros sólo existen en desarrollo.
