docs(api): update split website type contracts
This commit is contained in:
@@ -1907,7 +1907,7 @@
|
||||
"description": "Consulta, configura o desvincula cualquier integración usando `{{integration_code}}`.",
|
||||
"item": [
|
||||
{
|
||||
"name": "List Website Type Integration",
|
||||
"name": "List Admin Website Type Integration",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
@@ -1917,16 +1917,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `GET /api/website-types/{websiteType:codigo}/integrations`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@index`\n\nRequiere autenticación Sanctum.",
|
||||
"description": "Ruta Laravel: `GET /api/admin-website-types/{adminWebsiteType:codigo}/integrations`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@index`\n\nRequiere autenticación Sanctum.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations"
|
||||
]
|
||||
},
|
||||
@@ -1944,7 +1944,7 @@
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Website Type Integration",
|
||||
"name": "Get Admin Website Type Integration",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
@@ -1954,16 +1954,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `GET /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@show`\n\nRequiere autenticación Sanctum.",
|
||||
"description": "Ruta Laravel: `GET /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@show`\n\nRequiere autenticación Sanctum.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/{{integration_code}}",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/{{integration_code}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"{{integration_code}}"
|
||||
]
|
||||
@@ -1997,16 +1997,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `PUT /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.",
|
||||
"description": "Ruta Laravel: `PUT /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/{{integration_code}}",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/{{integration_code}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"{{integration_code}}"
|
||||
]
|
||||
@@ -2034,7 +2034,7 @@
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Delete Website Type Integration",
|
||||
"name": "Delete Admin Website Type Integration",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
@@ -2044,16 +2044,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `DELETE /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@destroy`\n\nRequiere autenticación Sanctum.",
|
||||
"description": "Ruta Laravel: `DELETE /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@destroy`\n\nRequiere autenticación Sanctum.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/{{integration_code}}",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/{{integration_code}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"{{integration_code}}"
|
||||
]
|
||||
@@ -2093,16 +2093,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `PUT /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `email`. Configura el transporte SMTP usado para el envío de correos.",
|
||||
"description": "Ruta Laravel: `PUT /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `email`. Configura el transporte SMTP usado para el envío de correos.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/email",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/email",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"email"
|
||||
]
|
||||
@@ -2151,16 +2151,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `PUT /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `telepagos`. Configura las credenciales productivas de Telepagos.",
|
||||
"description": "Ruta Laravel: `PUT /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `telepagos`. Configura las credenciales productivas de Telepagos.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/telepagos",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/telepagos",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"telepagos"
|
||||
]
|
||||
@@ -2209,16 +2209,16 @@
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"description": "Ruta Laravel: `PUT /api/website-types/{websiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\WebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `telepagos_homo`. Configura las credenciales del entorno de homologación de Telepagos.",
|
||||
"description": "Ruta Laravel: `PUT /api/admin-website-types/{adminWebsiteType:codigo}/integrations/{integration_code}`\n\nControlador: `App\\Domains\\Integration\\Controllers\\AdminWebsiteTypeIntegrationController@store`\n\nRequiere autenticación Sanctum.\n\nPreset: `telepagos_homo`. Configura las credenciales del entorno de homologación de Telepagos.",
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/website-types/{{website_type_code}}/integrations/telepagos_homo",
|
||||
"raw": "{{base_url}}/api/admin-website-types/{{admin_website_type_code}}/integrations/telepagos_homo",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"website-types",
|
||||
"{{website_type_code}}",
|
||||
"admin-website-types",
|
||||
"{{admin_website_type_code}}",
|
||||
"integrations",
|
||||
"telepagos_homo"
|
||||
]
|
||||
@@ -2550,7 +2550,7 @@
|
||||
},
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"client_id\": {{client_id}},\n \"codigo\": \"{{tenant_code}}\",\n \"nombre\": \"Tenant Demo\",\n \"dominio\": \"{{tenant_domain}}\",\n \"site_title\": \"ShopIt Demo\",\n \"primary_color\": \"#111827\",\n \"secondary_color\": \"#2563EB\",\n \"danger_color\": \"#DC2626\",\n \"success_color\": \"#16A34A\",\n \"header_bg_color\": \"#FFFFFF\",\n \"footer_bg_color\": \"#111827\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"search_product_layout\": \"column_with_image\",\n \"search_group_layout\": \"paginated\",\n \"search_items_per_page\": 12,\n \"display_categories\": true,\n \"display_seach_bar\": true,\n \"display_cart\": true,\n \"cart_editing_policy\": \"full\",\n \"website_type_code\": \"shopit\"\n}",
|
||||
"raw": "{\n \"client_id\": {{client_id}},\n \"codigo\": \"{{tenant_code}}\",\n \"nombre\": \"Tenant Demo\",\n \"dominio\": \"{{tenant_domain}}\",\n \"site_title\": \"ShopIt Demo\",\n \"primary_color\": \"#111827\",\n \"secondary_color\": \"#2563EB\",\n \"danger_color\": \"#DC2626\",\n \"success_color\": \"#16A34A\",\n \"header_bg_color\": \"#FFFFFF\",\n \"footer_bg_color\": \"#111827\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"search_product_layout\": \"column_with_image\",\n \"search_group_layout\": \"paginated\",\n \"search_items_per_page\": 12,\n \"display_categories\": true,\n \"display_seach_bar\": true,\n \"display_cart\": true,\n \"cart_editing_policy\": \"full\",\n \"admin_website_type_code\": \"shopit\",\n \"storefront_website_type_code\": \"shopit\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
@@ -6268,7 +6268,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "website_type_code",
|
||||
"key": "storefront_website_type_code",
|
||||
"value": "shopit",
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6381,6 +6381,10 @@
|
||||
"key": "s3_path",
|
||||
"value": "postman/test-file.png",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "admin_website_type_code",
|
||||
"value": "shopit"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
- `Integration`: catálogo, URL base, `integration_data_schema` y `requires_configuration`.
|
||||
- `IntegrationInstance`: configuración interna concreta con nombre. `integration_data` se cifra con `EncryptedIntegrationData`, se almacena en `longText` y nunca se devuelve en la API.
|
||||
- `ClientIntegration` y `WebsiteTypeIntegration`: asociaciones a instancias. La clave compuesta verifica el código de la instancia y la unicidad permite una instancia por integración y propietario.
|
||||
- `ClientIntegration` y `AdminWebsiteTypeIntegration`: asociaciones a instancias. La clave compuesta verifica el código de la instancia y la unicidad permite una instancia por integración y propietario.
|
||||
|
||||
Las instancias no se administran directamente por HTTP. Cada configuración enviada desde un cliente o tipo de sitio crea una instancia interna nueva y reemplaza únicamente la asociación de ese propietario. Al reemplazar o desvincular una instancia, esta se elimina si ya no tiene asociaciones con ningún cliente ni tipo de sitio; las instancias compartidas se conservan mientras tengan al menos una asociación.
|
||||
|
||||
## Resolución
|
||||
|
||||
`BaseIntegrationService::forTenant()` busca primero la asociación del cliente y después la del tipo de sitio del tenant. Selecciona una configuración completa, sin mezclar credenciales entre niveles. Si una configuración está presente pero es inválida, produce un error en vez de recurrir a otra instancia.
|
||||
`BaseIntegrationService::forTenant()` busca primero la asociación del cliente y después la del tipo de admin del tenant. Selecciona una configuración completa, sin mezclar credenciales entre niveles. Si una configuración está presente pero es inválida, produce un error en vez de recurrir a otra instancia.
|
||||
|
||||
`forClient()` usa únicamente la asociación del cliente: sin un tenant concreto no se elige un tipo de sitio. Si no existe una instancia y `requires_configuration` es verdadero, se genera un error. Para correo opcional, `MailService` usa el mailer global si no encuentra una instancia; cuando la encuentra, construye un transporte SMTP aislado identificado como `integration-smtp`.
|
||||
|
||||
@@ -25,9 +25,9 @@ Todas estas rutas llevan el prefijo `/api`, requieren `auth:sanctum` y el rol gl
|
||||
| GET | `/clients/{client}/integrations[/{integration_code}]` | Consultar asociaciones directas. |
|
||||
| PUT | `/clients/{client}/integrations/{integration_code}` | Configurar: crea una instancia interna nueva y reemplaza solo la asociación del cliente. Ejecuta el hook de configuración existente. |
|
||||
| DELETE | `/clients/{client}/integrations/{integration_code}` | Desvincular. |
|
||||
| GET | `/website-types/{codigo}/integrations[/{integration_code}]` | Consultar asociaciones del tipo de sitio. |
|
||||
| PUT | `/website-types/{codigo}/integrations/{integration_code}` | Configurar: crea una instancia interna nueva y reemplaza solo la asociación del tipo de sitio. |
|
||||
| DELETE | `/website-types/{codigo}/integrations/{integration_code}` | Desvincular. |
|
||||
| GET | `/admin-website-types/{codigo}/integrations[/{integration_code}]` | Consultar asociaciones del tipo de admin. |
|
||||
| PUT | `/admin-website-types/{codigo}/integrations/{integration_code}` | Configurar: crea una instancia interna nueva y reemplaza solo la asociación del tipo de admin. |
|
||||
| DELETE | `/admin-website-types/{codigo}/integrations/{integration_code}` | Desvincular. |
|
||||
|
||||
Los dos `PUT` reciben `integration_data`, un objeto completo validado según el esquema de la integración. La integración debe existir previamente en el catálogo interno. No hay endpoints públicos para administrar el catálogo ni las instancias directamente.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ No expone rutas HTTP. Consume datos de `Auth`, `Tenant`, `Purchase` y `Ticket`,
|
||||
|
||||
- Los listeners reciben identificadores y vuelven a cargar los modelos, evitando transportar entidades obsoletas.
|
||||
- La recuperación no se envía si el intento dejó de estar pendiente.
|
||||
- Los correos de cuenta (bienvenida y recuperación de contraseña) usan la identidad visual del `WebsiteType` asociado al tenant, con fallback al tenant si no tiene uno configurado.
|
||||
- La bienvenida y la recuperación del storefront usan la identidad visual del tenant. La recuperación del admin y scanner usa el `AdminWebsiteType`, con fallback al tenant si no tiene uno configurado.
|
||||
- El correo transaccional de compra confirmada usa la identidad visual del tenant y adjunta un único PDF cuando la compra generó tickets.
|
||||
- Los handlers deben permanecer idempotentes o tolerantes a reintentos de cola.
|
||||
- Una entrega queda en estado `processing` mientras un worker posee su claim. Si
|
||||
|
||||
@@ -7,8 +7,9 @@ Es la raíz del modelo multi-tenant. Gestiona organizaciones/sitios, tipos de we
|
||||
## Modelo
|
||||
|
||||
- `Tenant`: entidad principal, resuelta en rutas por `codigo`; relaciona catálogo, fechas, redes, menús y configuración visual. Su ubicación pública se representa con `dominio` y `base_path` (`/` para la raíz).
|
||||
- `WebsiteType`: plantilla o tipo de sitio disponible.
|
||||
- `WebsiteTypeExtra`: definición de un extra y su configuración admitida.
|
||||
- `AdminWebsiteType`: dominios, marca e integraciones compartidas del admin y scanner.
|
||||
- `StorefrontWebsiteType`: tipo de storefront que define los extras admitidos.
|
||||
- `StorefrontWebsiteTypeExtra`: definición de un extra y su configuración admitida.
|
||||
- `WebsiteExtra`: valor resuelto y estado del extra para un tenant.
|
||||
- `SocialMedia`: catálogo de redes sociales asociables.
|
||||
|
||||
@@ -16,7 +17,7 @@ Es la raíz del modelo multi-tenant. Gestiona organizaciones/sitios, tipos de we
|
||||
|
||||
- `TenantService`: crea y actualiza tenants, incluyendo sus recursos asociados.
|
||||
- `TenantInformationService`: carga un tenant y las relaciones requeridas por cada contexto.
|
||||
- `WebsiteTypeService`: crea o actualiza tipos de sitio.
|
||||
- `AdminWebsiteTypeService`: crea o actualiza los tipos de admin y su marca.
|
||||
- `WebsiteExtraService`: construye reglas dinámicas, crea, actualiza y habilita/deshabilita extras.
|
||||
- `TenantDomainNormalizer`: normaliza dominios antes de resolver el tenant.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user