@bacano/sdk 1.0.1 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +439 -18
- package/STOREFRONT_CLARITY.md +140 -0
- package/STOREFRONT_CONSTRUCTION.md +105 -0
- package/STOREFRONT_LEADS.md +130 -0
- package/STOREFRONT_LEGAL.md +66 -0
- package/STOREFRONT_MARKETING.md +291 -0
- package/STOREFRONT_PERFORMANCE.md +304 -0
- package/STOREFRONT_PREVIEW.md +499 -0
- package/STOREFRONT_PRODUCT_SPECIFICATIONS.md +127 -0
- package/STOREFRONT_VOLUME_PRICING.md +131 -0
- package/client.d.ts +8 -1
- package/errors.d.ts +9 -1
- package/graphql.cjs +266 -3
- package/graphql.d.ts +2 -2
- package/graphql.js +266 -3
- package/index.cjs +2035 -255
- package/index.d.ts +8 -6
- package/index.js +2035 -255
- package/marketing/attribution.d.ts +53 -0
- package/marketing/clarity.d.ts +3 -0
- package/marketing/domain.d.ts +1 -0
- package/marketing/ga4.d.ts +2 -0
- package/marketing/index.d.ts +5 -0
- package/marketing/runtime.d.ts +2 -0
- package/marketing/sanitize.d.ts +2 -0
- package/marketing/types.d.ts +111 -0
- package/media.d.ts +45 -2
- package/modules/auth.d.ts +3 -2
- package/modules/availability.d.ts +2 -2
- package/modules/cart-errors.d.ts +2 -0
- package/modules/cart-session.d.ts +2 -2
- package/modules/cart.d.ts +4 -3
- package/modules/catalog.d.ts +15 -3
- package/modules/content.d.ts +2 -2
- package/modules/marketing.d.ts +5 -0
- package/modules/orders.d.ts +2 -2
- package/modules/profile.d.ts +1 -1
- package/modules/static-catalog.d.ts +13 -0
- package/modules/website.d.ts +7 -1
- package/package.json +14 -3
- package/react/context-registry.d.ts +9 -0
- package/react/context.d.ts +1 -1
- package/react/hooks.d.ts +24 -2
- package/react/marketing-context.d.ts +3 -0
- package/react/marketing-provider.d.ts +10 -0
- package/react/preview/cache.d.ts +23 -0
- package/react/preview/context.d.ts +5 -0
- package/react/preview/navigation.d.ts +9 -0
- package/react/preview/provider.d.ts +3 -0
- package/react/preview/shell.d.ts +3 -0
- package/react/preview/toolbar.d.ts +3 -0
- package/react/preview/types.d.ts +60 -0
- package/react/preview.cjs +742 -0
- package/react/preview.d.ts +14 -0
- package/react/preview.js +730 -0
- package/react/website-gate.d.ts +22 -0
- package/react.cjs +3893 -1795
- package/react.d.ts +8 -4
- package/react.js +3891 -1789
- package/skills/bacano-web/SKILL.md +116 -0
- package/skills/bacano-web/agents/openai.yaml +4 -0
- package/skills/bacano-web/references/architecture-runtime.md +109 -0
- package/skills/bacano-web/references/common.md +92 -0
- package/skills/bacano-web/references/informational.md +39 -0
- package/skills/bacano-web/references/report.md +70 -0
- package/skills/bacano-web/references/storefront.md +116 -0
- package/skills/bacano-web/scripts/audit-http.mjs +284 -0
- package/skills/bacano-web/scripts/cli.mjs +222 -0
- package/skills/bacano-web/scripts/postinstall.mjs +8 -0
- package/transport/documents.d.ts +23 -18
- package/transport/graphql.d.ts +13 -1
- package/types.d.ts +338 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Microsoft Clarity en storefronts Bacano
|
|
2
|
+
|
|
3
|
+
Este documento define la integración oficial de Microsoft Clarity para todos
|
|
4
|
+
los storefronts que usan `@bacano/sdk`. Clarity aporta mapas de calor,
|
|
5
|
+
grabaciones de sesión y análisis de comportamiento; no reemplaza GA4, Meta ni
|
|
6
|
+
los eventos comerciales autoritativos de Bacano.
|
|
7
|
+
|
|
8
|
+
## Responsabilidades
|
|
9
|
+
|
|
10
|
+
El comercio crea y administra su proyecto en Microsoft Clarity. Se recomienda
|
|
11
|
+
un proyecto diferente por dominio. En Bacano, dentro de **Sitios web > Marketing
|
|
12
|
+
y medición > Microsoft Clarity**, registra el `Project ID`, guarda, prueba la
|
|
13
|
+
conexión y la activa.
|
|
14
|
+
|
|
15
|
+
El `Project ID` es público. Bacano lo guarda por `website_id`; no existe un
|
|
16
|
+
secreto de servidor para esta integración. El SDK solo lo recibe cuando la
|
|
17
|
+
integración está activa, validada y la petición corresponde al dominio canónico
|
|
18
|
+
de producción.
|
|
19
|
+
|
|
20
|
+
El storefront es responsable únicamente de:
|
|
21
|
+
|
|
22
|
+
1. Usar una versión del SDK que incluya este contrato.
|
|
23
|
+
2. Montar una sola vez el `BacanoMarketingProvider` existente.
|
|
24
|
+
3. Seguir emitiendo los eventos canónicos mediante `useMarketing().track()`.
|
|
25
|
+
|
|
26
|
+
No debe instalar otro paquete de Clarity, copiar el snippet de Microsoft,
|
|
27
|
+
consultar GraphQL ni construir una segunda petición de configuración.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { getWebsitePublicConfig } from "@bacano/sdk";
|
|
31
|
+
import { BacanoMarketingProvider } from "@bacano/sdk/react";
|
|
32
|
+
|
|
33
|
+
const publicConfig = await getWebsitePublicConfig({ apiUrl, websiteSlug });
|
|
34
|
+
|
|
35
|
+
<BacanoMarketingProvider publicConfig={publicConfig} scriptLoadStrategy="idle">
|
|
36
|
+
<Storefront />
|
|
37
|
+
</BacanoMarketingProvider>;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Cuando Clarity está activo, el provider carga una sola vez
|
|
41
|
+
`https://www.clarity.ms/tag/{projectId}`. En localhost, preview y dominios no
|
|
42
|
+
canónicos se mantiene como `no-op`.
|
|
43
|
+
|
|
44
|
+
Si el storefront aplica una Content Security Policy, debe permitir los
|
|
45
|
+
endpoints oficiales de Clarity (`https://*.clarity.ms` y
|
|
46
|
+
`https://c.bing.com`) en las directivas correspondientes de scripts y
|
|
47
|
+
conexiones. Conviene probar primero la política en modo report-only y revisar
|
|
48
|
+
la consola del navegador antes de aplicarla.
|
|
49
|
+
|
|
50
|
+
La matriz distribuible de CSP para Clarity, GA4 y Meta vive únicamente en
|
|
51
|
+
[`STOREFRONT_MARKETING.md`](./STOREFRONT_MARKETING.md). No mantener una segunda
|
|
52
|
+
lista dentro del storefront: componer desde allí solo los proveedores activos
|
|
53
|
+
y añadir por separado los orígenes propios de autenticación, pagos o video.
|
|
54
|
+
|
|
55
|
+
Las imágenes y videos públicos entregados por
|
|
56
|
+
`/storage/v1/files/{fileId}` aceptan lectura credentialless desde renderizadores
|
|
57
|
+
externos. Bacano valida que el archivo pertenezca a media pública de una empresa
|
|
58
|
+
con un storefront activo antes de servirlo y mantiene privados los archivos no
|
|
59
|
+
elegibles. El storefront no debe crear un proxy, reenviar cookies ni modificar
|
|
60
|
+
las URLs de media para que aparezcan en las reproducciones de Clarity.
|
|
61
|
+
|
|
62
|
+
Una política CSP solo puede componerse con datos conocidos durante el build.
|
|
63
|
+
El runtime no intenta modificar una cabecera CSP después de cargar la página.
|
|
64
|
+
Si un proveedor incorpora un origen dinámico no documentado —por ejemplo, un
|
|
65
|
+
endpoint auxiliar de Meta alojado en infraestructura cloud— no se deben abrir
|
|
66
|
+
comodines amplios como `*.on.aws` o `*.run.app`. Ese origen debe validarse y
|
|
67
|
+
declararse de manera exacta en el hosting hasta que el proveedor ofrezca un
|
|
68
|
+
contrato estable que Bacano pueda publicar de forma segura.
|
|
69
|
+
|
|
70
|
+
## Eventos y alcance
|
|
71
|
+
|
|
72
|
+
Clarity captura automáticamente navegación, clics, desplazamiento, errores y
|
|
73
|
+
la representación necesaria para sus mapas y grabaciones. Adicionalmente, el
|
|
74
|
+
SDK reenvía cada evento canónico de navegador como un evento personalizado de
|
|
75
|
+
Clarity con el mismo nombre, por ejemplo:
|
|
76
|
+
|
|
77
|
+
- `view_item`
|
|
78
|
+
- `add_to_cart`
|
|
79
|
+
- `begin_checkout`
|
|
80
|
+
- `contact`
|
|
81
|
+
|
|
82
|
+
Esto permite filtrar grabaciones y mapas por pasos del embudo sin instrumentar
|
|
83
|
+
handlers paralelos. El storefront no debe llamar a `window.clarity()`.
|
|
84
|
+
|
|
85
|
+
Clarity es un destino exclusivo de navegador. `order_placed`, `purchase` y
|
|
86
|
+
`refund` continúan enviándose de forma autoritativa a GA4 y Meta desde Bacano;
|
|
87
|
+
no se crea un outbox de servidor para Clarity.
|
|
88
|
+
|
|
89
|
+
## Privacidad y seguridad
|
|
90
|
+
|
|
91
|
+
- No enviar email, teléfono, documento, dirección, tokens ni otros datos
|
|
92
|
+
personales a eventos o etiquetas de Clarity.
|
|
93
|
+
- Clarity enmascara por defecto entradas, números y correos. Los storefronts
|
|
94
|
+
deben añadir `data-clarity-mask` a cualquier zona personalizada sensible que
|
|
95
|
+
requiera protección adicional.
|
|
96
|
+
- No usar `data-clarity-unmask` en checkout, cuenta, autenticación o formularios
|
|
97
|
+
con datos personales.
|
|
98
|
+
- Microsoft indica que Clarity no debe utilizarse en sitios o aplicaciones
|
|
99
|
+
dirigidos a menores de 18 años. El comercio debe evaluar su audiencia antes
|
|
100
|
+
de activarlo.
|
|
101
|
+
- El aviso informativo de cookies de Bacano no es un gestor de consentimiento.
|
|
102
|
+
Si un comercio opera en una jurisdicción que exige consentimiento previo,
|
|
103
|
+
debe implementar un mecanismo de consentimiento válido antes de activar la
|
|
104
|
+
recolección completa.
|
|
105
|
+
|
|
106
|
+
No se utiliza la API `identify`: Bacano no entrega a Clarity identidades de
|
|
107
|
+
clientes ni compradores.
|
|
108
|
+
|
|
109
|
+
## Verificación
|
|
110
|
+
|
|
111
|
+
Después de desplegar el storefront en su dominio canónico:
|
|
112
|
+
|
|
113
|
+
1. Abrir el sitio sin modo preview.
|
|
114
|
+
2. Confirmar en la pestaña Network la carga de `clarity.ms/tag/{projectId}` y
|
|
115
|
+
solicitudes de recolección a Clarity.
|
|
116
|
+
3. Navegar, abrir un producto y agregarlo al carrito.
|
|
117
|
+
4. Revisar sesiones en tiempo real, mapas y eventos personalizados dentro del
|
|
118
|
+
proyecto correcto de Clarity.
|
|
119
|
+
5. Abrir una reproducción y confirmar que las imágenes públicas de productos y
|
|
120
|
+
Content cargan desde `api.bacanoerp.com/storage/v1/files/`.
|
|
121
|
+
6. Confirmar que localhost, preview y otro dominio no envíen datos.
|
|
122
|
+
7. Confirmar que una falla o bloqueo del script no afecte catálogo, carrito o
|
|
123
|
+
checkout.
|
|
124
|
+
|
|
125
|
+
Microsoft puede tardar algunos minutos en mostrar la primera información. Una
|
|
126
|
+
prueba válida en Bacano confirma el Project ID y la disponibilidad del tag; no
|
|
127
|
+
demuestra que un navegador concreto esté libre de bloqueadores.
|
|
128
|
+
|
|
129
|
+
## Checklist para agentes de storefront
|
|
130
|
+
|
|
131
|
+
- [ ] Uso un único `BacanoMarketingProvider`.
|
|
132
|
+
- [ ] No instalé el snippet ni un paquete paralelo de Clarity.
|
|
133
|
+
- [ ] Los eventos continúan saliendo solo de `useMarketing().track()`.
|
|
134
|
+
- [ ] Preview y localhost no cargan Clarity.
|
|
135
|
+
- [ ] Las zonas sensibles permanecen enmascaradas.
|
|
136
|
+
- [ ] No uso `identify`, PII ni etiquetas con datos personales.
|
|
137
|
+
- [ ] Las imágenes públicas se reconstruyen sin un proxy del storefront.
|
|
138
|
+
- [ ] Validé carga, recolección, sesiones y eventos en producción.
|
|
139
|
+
|
|
140
|
+
El contrato general de eventos permanece en `STOREFRONT_MARKETING.md`.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Sitio en construcción para storefronts Bacano
|
|
2
|
+
|
|
3
|
+
Este documento define el contrato oficial para ocultar temporalmente un sitio
|
|
4
|
+
Bacano sin reconstruir su export estático. Aplica a SiteGround y otros hostings
|
|
5
|
+
estáticos; una futura integración con CloudFront podrá aplicar la misma
|
|
6
|
+
configuración en el edge.
|
|
7
|
+
|
|
8
|
+
## Responsabilidades
|
|
9
|
+
|
|
10
|
+
- Bacano conserva la configuración por `website_id`, valida las imágenes y
|
|
11
|
+
entrega únicamente datos públicos.
|
|
12
|
+
- `public-config` decide si la pantalla debe aplicarse. Localhost, desarrollo y
|
|
13
|
+
orígenes no canónicos nunca quedan bloqueados.
|
|
14
|
+
- El SDK administra la consulta en vivo, la pantalla responsive y el acceso
|
|
15
|
+
temporal de vista previa.
|
|
16
|
+
- El storefront solo monta `BacanoWebsiteGate`. No consulta GraphQL, no lee
|
|
17
|
+
`websites.config` y no construye URLs de Storage.
|
|
18
|
+
|
|
19
|
+
## Integración React
|
|
20
|
+
|
|
21
|
+
El gate debe envolver autenticación, marketing y la aplicación. De esta forma
|
|
22
|
+
Clerk, GA4, Meta y Clarity no se cargan mientras la pantalla esté activa.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
"use client";
|
|
26
|
+
|
|
27
|
+
import { BacanoWebsiteGate } from "@bacano/sdk/react";
|
|
28
|
+
|
|
29
|
+
export function WebsiteVisibility({ children }: { children: React.ReactNode }) {
|
|
30
|
+
return (
|
|
31
|
+
<BacanoWebsiteGate
|
|
32
|
+
config={{
|
|
33
|
+
apiUrl: process.env.NEXT_PUBLIC_BACANO_API_URL!,
|
|
34
|
+
websiteSlug: process.env.NEXT_PUBLIC_BACANO_WEBSITE_SLUG!,
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</BacanoWebsiteGate>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Después del gate se montan `ClerkProvider`, `BacanoProvider`,
|
|
44
|
+
`BacanoMarketingProvider` y el resto del storefront. Puede entregarse
|
|
45
|
+
`initialConfig` si el build ya obtuvo `public-config`; el gate vuelve a
|
|
46
|
+
consultarlo antes de montar el sitio para detectar cambios posteriores al
|
|
47
|
+
despliegue.
|
|
48
|
+
|
|
49
|
+
Mientras confirma la configuración, el gate serializa `children` dentro de un
|
|
50
|
+
`<noscript>` semántico. El catálogo, los productos, encabezados y enlaces siguen
|
|
51
|
+
presentes en el HTML exportado y son visibles cuando JavaScript está
|
|
52
|
+
deshabilitado, pero React no monta esos descendientes. Así evita cargar Clerk,
|
|
53
|
+
GA4, Meta o Clarity y tampoco muestra fugazmente la tienda si construcción está
|
|
54
|
+
activa. `loadingFallback` es únicamente la UI visible para navegadores con
|
|
55
|
+
JavaScript durante esa consulta; por defecto permanece vacío.
|
|
56
|
+
|
|
57
|
+
La pantalla oficial usa la imagen mobile hasta 767 px y la desktop desde 768
|
|
58
|
+
px. En ambos casos emplea las fuentes responsivas generadas por Bacano. Si solo
|
|
59
|
+
existe una de las dos imágenes la reutiliza de forma segura; si no existe
|
|
60
|
+
ninguna, conserva el fondo y muestra el título y mensaje configurados. El
|
|
61
|
+
storefront puede proporcionar `constructionFallback` si requiere una UI propia,
|
|
62
|
+
pero no debe alterar la decisión `construction.enforced`.
|
|
63
|
+
|
|
64
|
+
## Vista previa temporal
|
|
65
|
+
|
|
66
|
+
Desde Bacano, un usuario con `websites.manage` puede generar un enlace válido
|
|
67
|
+
durante dos horas:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
https://tienda.example/#bacano-preview=<token-firmado>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
El fragmento no viaja al hosting ni se incluye en el `Referer`. El gate lo
|
|
74
|
+
guarda en `sessionStorage`, limpia la barra de direcciones y valida el token
|
|
75
|
+
contra `public-config`. La vista previa termina al cerrar esa sesión, al vencer
|
|
76
|
+
el token o al borrar los datos del navegador.
|
|
77
|
+
|
|
78
|
+
No convertir el token en query string, cookie permanente ni variable de build.
|
|
79
|
+
|
|
80
|
+
## Seguridad y límites de hosting estático
|
|
81
|
+
|
|
82
|
+
En SiteGround esta es una barrera de presentación ejecutada por JavaScript. No
|
|
83
|
+
impide descargar el HTML estático ni devuelve HTTP 503, por lo que no debe
|
|
84
|
+
usarse como control de acceso para información sensible. El contenido privado
|
|
85
|
+
nunca debe formar parte del export público. Mientras la pantalla está activa,
|
|
86
|
+
el gate añade `noindex,nofollow`; en un hosting estático esto sigue dependiendo
|
|
87
|
+
de que el crawler ejecute JavaScript.
|
|
88
|
+
|
|
89
|
+
Cuando Bacano opere el storefront en CloudFront, la misma bandera podrá
|
|
90
|
+
resolverse antes de servir la página, devolver 503 y aplicar `noindex` desde el
|
|
91
|
+
edge. El contrato del SDK y la configuración por website permanecen válidos.
|
|
92
|
+
|
|
93
|
+
## Checklist del storefront
|
|
94
|
+
|
|
95
|
+
- `BacanoWebsiteGate` está por fuera de auth y marketing.
|
|
96
|
+
- El export contiene el catálogo estático dentro del fallback `<noscript>`.
|
|
97
|
+
- Sin JavaScript, catálogo, productos y enlaces continúan visibles.
|
|
98
|
+
- La configuración se consulta en runtime con `cache: no-store`.
|
|
99
|
+
- La pantalla activa no inicializa Clerk, GA4, Meta ni Clarity.
|
|
100
|
+
- Localhost y dominios de desarrollo siguen mostrando la web.
|
|
101
|
+
- Las imágenes desktop y mobile usan `srcset` y `sizes`.
|
|
102
|
+
- El enlace temporal abre el storefront y desaparece de la barra de dirección.
|
|
103
|
+
- Un token vencido no concede acceso y se elimina de `sessionStorage`.
|
|
104
|
+
- La pantalla oficial sigue siendo útil aunque no tenga imágenes.
|
|
105
|
+
- Un fallo de `public-config` degrada de forma abierta y no tumba el sitio.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Captura de leads en storefronts Bacano
|
|
2
|
+
|
|
3
|
+
Este es el contrato canónico para formularios comerciales construidos por un
|
|
4
|
+
storefront. Bacano no impone un constructor visual: cada tienda decide sus
|
|
5
|
+
campos y diseño, pero toda captura debe entrar por `@bacano/sdk`.
|
|
6
|
+
|
|
7
|
+
## Responsabilidades
|
|
8
|
+
|
|
9
|
+
El storefront:
|
|
10
|
+
|
|
11
|
+
- Renderiza el formulario y valida su experiencia básica.
|
|
12
|
+
- Muestra exactamente `publicConfig.legal.directMarketingConsent.statement`.
|
|
13
|
+
- Mantiene la aceptación opcional desmarcada hasta una acción explícita.
|
|
14
|
+
- Genera una clave de idempotencia por envío y la conserva durante reintentos.
|
|
15
|
+
- Envía únicamente respuestas necesarias para el propósito informado.
|
|
16
|
+
|
|
17
|
+
Bacano:
|
|
18
|
+
|
|
19
|
+
- Deriva y valida el website y su dominio.
|
|
20
|
+
- Resuelve la campaña por su clave pública.
|
|
21
|
+
- Conserva la versión y huella del texto aceptado.
|
|
22
|
+
- Reutiliza la identidad, el lead o el cliente existente sin duplicarlos.
|
|
23
|
+
- Completa un correo o teléfono faltante únicamente cuando la coincidencia de
|
|
24
|
+
identidad es inequívoca; nunca reemplaza un dato existente.
|
|
25
|
+
- Conserva el contacto enviado dentro de la evidencia de autorización ligada a
|
|
26
|
+
la captura, incluso cuando el participante ya era cliente.
|
|
27
|
+
- Conserva la captura, atribución y respuestas como evidencia inmutable.
|
|
28
|
+
- Aplica límites de frecuencia, tamaño e idempotencia.
|
|
29
|
+
|
|
30
|
+
## Configuración previa
|
|
31
|
+
|
|
32
|
+
1. Configura el texto de **Autorización de comunicaciones comerciales** en la
|
|
33
|
+
pestaña Legal del website.
|
|
34
|
+
2. Crea una campaña en Bacano y actívala.
|
|
35
|
+
3. Usa su clave pública estable en el formulario.
|
|
36
|
+
|
|
37
|
+
Una campaña en borrador, pausada, finalizada, fuera de vigencia o asociada a
|
|
38
|
+
otro website no acepta capturas. Si el texto legal no existe, el storefront no
|
|
39
|
+
debe mostrar ni habilitar el formulario comercial.
|
|
40
|
+
|
|
41
|
+
## Implementación
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
const consent = publicConfig.legal.directMarketingConsent;
|
|
45
|
+
|
|
46
|
+
if (!consent) return null;
|
|
47
|
+
|
|
48
|
+
// Renderiza consent.statement junto a un checkbox desmarcado.
|
|
49
|
+
// Ejecuta esta llamada únicamente después de validar el formulario y aceptar.
|
|
50
|
+
// Conserva esta clave en el estado del formulario mientras reintentas el envío.
|
|
51
|
+
const idempotencyKey = crypto.randomUUID();
|
|
52
|
+
const result = await client.marketing.captureLead({
|
|
53
|
+
campaignKey: "newsletter-baby-rex",
|
|
54
|
+
idempotencyKey,
|
|
55
|
+
commercialConsent: true,
|
|
56
|
+
contact: {
|
|
57
|
+
partyKind: "PERSON",
|
|
58
|
+
firstName: "Ana",
|
|
59
|
+
email: "ana@example.com",
|
|
60
|
+
},
|
|
61
|
+
answers: {
|
|
62
|
+
interest: "bebe-nina",
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Debe existir al menos correo o teléfono. Los nombres son opcionales. Para una
|
|
68
|
+
empresa pueden usarse `partyKind: "COMPANY"`, `legalName` y `commercialName`.
|
|
69
|
+
|
|
70
|
+
`source` se omite para formularios normales y será `WEBSITE`. Usa `QR`
|
|
71
|
+
únicamente cuando el formulario se abrió mediante una entrada QR controlada por
|
|
72
|
+
el storefront. UTM, referidor y click IDs se toman automáticamente de la
|
|
73
|
+
atribución segura del SDK.
|
|
74
|
+
|
|
75
|
+
El storefront no debe construir ni enviar manualmente el payload HTTP. El SDK
|
|
76
|
+
serializa este contrato como JSON y la ruta pública de Bacano lo procesa antes
|
|
77
|
+
de validar la campaña. Un SDK `1.0.14` o posterior conserva esta forma del
|
|
78
|
+
payload; no se requieren adaptadores específicos por tienda.
|
|
79
|
+
|
|
80
|
+
## Respuestas personalizadas
|
|
81
|
+
|
|
82
|
+
`answers` es un snapshot del formulario, no un constructor de campos del CRM.
|
|
83
|
+
|
|
84
|
+
- Máximo 50 claves, cada una de hasta 80 caracteres.
|
|
85
|
+
- Payload total aproximado máximo: 30 KB.
|
|
86
|
+
- No incluyas contraseñas, tokens, datos de pago, documentos adjuntos ni HTML.
|
|
87
|
+
- No dupliques correo o teléfono dentro de `answers`; usa `contact`.
|
|
88
|
+
- Un cambio futuro del formulario no modifica capturas anteriores.
|
|
89
|
+
|
|
90
|
+
## Idempotencia y privacidad
|
|
91
|
+
|
|
92
|
+
- La misma interacción debe reutilizar el mismo `idempotencyKey` hasta obtener
|
|
93
|
+
respuesta. Un nuevo envío voluntario usa una clave nueva.
|
|
94
|
+
- La respuesta es deliberadamente genérica y nunca revela si la persona ya era
|
|
95
|
+
lead o cliente.
|
|
96
|
+
- Si correo y teléfono pertenecen a identidades activas diferentes, Bacano no
|
|
97
|
+
sobrescribe ninguna de ellas y conserva el caso para revisión manual.
|
|
98
|
+
- No llames GraphQL, Hasura ni endpoints internos directamente.
|
|
99
|
+
- No captures un lead si el visitante no aceptó el texto comercial vigente.
|
|
100
|
+
- Una revocación posterior conserva el historial, pero impide comunicaciones
|
|
101
|
+
futuras hasta una nueva aceptación expresa.
|
|
102
|
+
|
|
103
|
+
## Beneficio de primera compra
|
|
104
|
+
|
|
105
|
+
Cuando la campaña activa tiene objetivo `FIRST_PURCHASE_COUPON` y referencia un
|
|
106
|
+
cupón online vigente, Bacano puede encolar el correo de bienvenida después de
|
|
107
|
+
aceptar la captura. Esta operación es completamente del servidor:
|
|
108
|
+
|
|
109
|
+
- el storefront no envía correos ni consulta Resend;
|
|
110
|
+
- no debe afirmar que el cupón ya fue enviado;
|
|
111
|
+
- repetir la misma captura no duplica el beneficio;
|
|
112
|
+
- una falla de correo nunca convierte la captura en error;
|
|
113
|
+
- Bacano revalida autorización, campaña, website, cupón y compras anteriores
|
|
114
|
+
inmediatamente antes del envío.
|
|
115
|
+
|
|
116
|
+
El contrato de `captureLead()` no cambia y no expone estados internos del
|
|
117
|
+
correo. La evidencia operativa queda en `outbound_emails` dentro de Bacano. El
|
|
118
|
+
newsletter masivo y las automatizaciones visuales continúan fuera de alcance.
|
|
119
|
+
|
|
120
|
+
## Checklist para agentes
|
|
121
|
+
|
|
122
|
+
- [ ] Leí este contrato antes de crear el formulario.
|
|
123
|
+
- [ ] Uso un único `BacanoClient` inicializado.
|
|
124
|
+
- [ ] Leo el texto desde `publicConfig.legal.directMarketingConsent`.
|
|
125
|
+
- [ ] La aceptación empieza desmarcada y es explícita.
|
|
126
|
+
- [ ] Uso `client.marketing.captureLead()` y no GraphQL directo.
|
|
127
|
+
- [ ] Conservo la clave de idempotencia durante reintentos.
|
|
128
|
+
- [ ] No envío secretos ni información innecesaria en `answers`.
|
|
129
|
+
- [ ] No afirmo que el correo o el cupón fueron entregados a partir de la
|
|
130
|
+
respuesta genérica de `captureLead()`.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Storefront legal settings
|
|
2
|
+
|
|
3
|
+
This document is the canonical contract for legal content exposed by the
|
|
4
|
+
Bacano SDK. Storefronts must use this configuration instead of maintaining
|
|
5
|
+
parallel legal documents in Content or querying GraphQL directly.
|
|
6
|
+
|
|
7
|
+
## Public contract
|
|
8
|
+
|
|
9
|
+
`getWebsitePublicConfig()` returns the current configuration for the resolved
|
|
10
|
+
website:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
const config = await getWebsitePublicConfig(options);
|
|
14
|
+
|
|
15
|
+
config.legal = {
|
|
16
|
+
schemaVersion: 1,
|
|
17
|
+
version: 3,
|
|
18
|
+
contentHash: "...",
|
|
19
|
+
documents: {
|
|
20
|
+
terms: { type: "doc", content: [] },
|
|
21
|
+
shipping: { type: "doc", content: [] },
|
|
22
|
+
returns: { type: "doc", content: [] },
|
|
23
|
+
privacy: { type: "doc", content: [] },
|
|
24
|
+
cookies: { type: "doc", content: [] },
|
|
25
|
+
},
|
|
26
|
+
inquiriesChannel: "privacidad@example.com",
|
|
27
|
+
cookieNotice: {
|
|
28
|
+
enabled: true,
|
|
29
|
+
message: "Usamos cookies propias y de terceros...",
|
|
30
|
+
buttonLabel: "Entendido",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
All documents and the inquiries channel are optional. Missing documents are
|
|
36
|
+
returned as `null`. Documents use Bacano's rich-text JSON format and must be
|
|
37
|
+
rendered safely; do not inject untrusted HTML.
|
|
38
|
+
|
|
39
|
+
The configuration is included in the existing public-config request. Do not
|
|
40
|
+
add a second request, direct GraphQL access, or local fallback copies of legal
|
|
41
|
+
text.
|
|
42
|
+
|
|
43
|
+
## Informational cookie notice
|
|
44
|
+
|
|
45
|
+
Render the notice only when `config.legal.cookieNotice.enabled` is `true`.
|
|
46
|
+
Display the message and button label supplied by Bacano, allow the visitor to
|
|
47
|
+
close it, and store that dismissal locally if the storefront should avoid
|
|
48
|
+
showing it again in the same browser.
|
|
49
|
+
|
|
50
|
+
The notice is informational. It is not a consent manager and does not gate,
|
|
51
|
+
delay, or reconfigure the GA4, Meta, or Microsoft Clarity runtime. Marketing remains governed by
|
|
52
|
+
`config.marketing`.
|
|
53
|
+
|
|
54
|
+
## Storefront checklist
|
|
55
|
+
|
|
56
|
+
- Preserve existing public legal routes and their SEO behavior.
|
|
57
|
+
- Source terms, shipping, returns, privacy, cookies, and the contact channel only from
|
|
58
|
+
`config.legal`.
|
|
59
|
+
- Handle every nullable document without crashing or inventing content.
|
|
60
|
+
- Remove only the obsolete legal Content keys; keep unrelated Content data.
|
|
61
|
+
- Do not add direct GraphQL calls or duplicate public-config requests.
|
|
62
|
+
- Verify the notice in enabled, disabled, and dismissed states.
|
|
63
|
+
- Verify GA4, Meta, and Clarity continue operating in every notice state.
|
|
64
|
+
- Do not present the informational notice as consent for Clarity. Review the
|
|
65
|
+
privacy rules in `STOREFRONT_CLARITY.md` before activating it.
|
|
66
|
+
- Run typecheck, lint, unit tests, E2E tests, and the production build.
|