🔄 Propuesta: Esquema Universal de Integraciones
🎯 Objetivo
Crear un esquema que funcione para TODAS las integraciones sin usar JSON genérico, con campos universales que cubran todos los casos de uso.
🗂️ Esquema Propuesto
model OrganizationIntegration {
id String @id @default(uuid())
organizationId String
availableIntegrationId String
name String?
// ===== ESTADOS =====
status IntegrationStatus @default(INACTIVE)
isConfigured Boolean @default(false) // ✅ NUEVO
isDefault Boolean @default(false)
// ===== CREDENCIALES UNIVERSALES =====
// Campos que cubren 95% de integraciones
username String? // ✅ NUEVO - Usuario/Email/Client ID
password String? // ✅ NUEVO - Contraseña/Secret/Token
apiKey String? // ✅ NUEVO - API Key/Token/Access Token
apiSecret String? // ✅ NUEVO - API Secret/Client Secret
apiUrl String? // ✅ NUEVO - URL base del API
apiVersion String? // ✅ NUEVO - Versión del API
// ===== CONFIGURACIÓN ESPECÍFICA =====
companyCode String? // ✅ NUEVO - Código empresa (Coordinadora)
storeUrl String? // ✅ NUEVO - URL tienda (Shopify)
environment String? // ✅ NUEVO - "sandbox" / "production"
// ===== CAMPOS FLEXIBLES =====
additionalFields Json? // ✅ MEJORADO - Solo para casos muy específicos
settings Json? // ✅ MANTENER - Configuraciones no-credenciales
// ===== MONITOREO Y USO =====
maxUsagePerMonth Int?
maxUsagePerDay Int?
usageThisMonth Int @default(0)
usageThisDay Int @default(0)
lastUsedAt DateTime?
lastTestedAt DateTime?
lastErrorAt DateTime?
lastErrorMsg String?
// ===== METADATA =====
metadata Json?
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
// ===== RELACIONES =====
AvailableIntegration AvailableIntegration @relation(fields: [availableIntegrationId], references: [id], onDelete: Cascade)
Organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@unique([organizationId, availableIntegrationId], map: "unique_org_available_integration")
@@index([organizationId, status], map: "idx_org_integration_org_status")
@@index([isConfigured], map: "idx_org_integration_configured") // ✅ NUEVO
@@index([status], map: "idx_org_integration_status")
}
🔧 **MAPEO POR INTEGRACIÓN:**
**🚛 Coordinadora (Shipping)**
username → usuario
password → clave
companyCode → codigoEmpresa
apiUrl → "https://coordinadora.com/agencia/ws/EnviosPrepago"
environment → "sandbox" | "production"
**🛒 Shopify (Web/Marketplace)**
storeUrl → "mi-tienda.myshopify.com"
apiKey → API Key de la app privada
password → API Secret Token
apiVersion → "2023-10"
**💳 Wompi (Payment)**
apiKey → Public Key
apiSecret → Private Key
environment → "sandbox" | "production"
apiUrl → "https://api.wompi.co" | "https://api.sandbox.wompi.co"
**📝 WordPress (Web)**
storeUrl → "https://mi-sitio.com"
username → Usuario WordPress
password → Application Password
apiUrl → "https://mi-sitio.com/wp-json/wc/v3"
✅ **VENTAJAS DEL NUEVO ESQUEMA:**
- Universal Cubre 95% de integraciones sin JSON
- Claro Cada campo tiene propósito específico
- Separación clara
isConfiguredvsstatus(ACTIVE/INACTIVE) - Type-safe No más parsing de JSON
- Query eficiente Índices en campos importantes
- Extensible
additionalFieldssolo para casos edge
🔄 **FLUJO PROPUESTO:**
- Usuario configura credenciales →
isConfigured = true,status = INACTIVE - Usuario activa integración →
status = ACTIVE(solo siisConfigured = true) - Usuario desactiva →
status = INACTIVE(mantiene credenciales) - Error en integración →
status = ERROR,lastErrorMsgpopulated
📊 **QUERIES EJEMPLO:**
Obtener integraciones configuradas pero inactivas
query {
organizationIntegrations(where: {
isConfigured: true
status: INACTIVE
})
}
Obtener integraciones activas
query {
organizationIntegrations(where: {
status: ACTIVE
})
}
🚀 **PRÓXIMOS PASOS:**
- Crear migration que agregue estos campos
- Migrar datos existentes de JSON a campos estructurados
- Actualizar resolvers GraphQL
- Probar con Postman
- Actualizar frontend