feat: sitio comercial FSPM con micro CRM interno

Sitio público orientado a venta consultiva e implementación de las
recomendaciones de la auditoría de marca y mercado:

- Inicio con tres rutas (industria, riesgo, cumplimiento) y clasificador
  de riesgo en el héroe, contra el hallazgo de que el visitante tenía que
  inferir qué solución le correspondía.
- Cinco páginas por segmento prioritario y catálogo comparable por clase
  de fuego, capacidad y agente.
- Los claims sin evidencia por modelo quedan aislados y se presentan como
  compromiso de documentación, nunca como característica del producto.
- SEO técnico completo: metadatos por página, sitemap derivado de los
  datos, JSON-LD, iconos y tarjeta social generadas.

Micro CRM:

- Captura por formulario embebido y por widget de WhatsApp que registra
  antes de abrir la conversación.
- Atribución de primer toque que sobrevive a la navegación.
- Deduplicación de contacto; un mismo contacto acumula oportunidades.
- Motor de asignación por reglas con reparto por turno de respaldo.
- Panel con dos roles de alcance distinto, tablero analítico, bitácora,
  pedidos y reglas. No enlazado desde el sitio público y con noindex.

Empaquetado en Docker multietapa con la base de demostración horneada en
la imagen y el volumen de datos separado, para que los leads capturados
sobrevivan a los redespliegues.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Uriel Jareth
2026-08-28 00:07:20 -06:00
co-authored by Claude Opus 5
parent 122e06a4bb
commit 01b817d098
649 changed files with 26690 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
# FSPM — sitio comercial y micro CRM
Demostración construida por **Consultoría E3** para Fire Service Plus México.
Sitio público orientado a venta consultiva, con un CRM interno que registra cada
envío de formulario y de widget de WhatsApp como oportunidad, con su atribución
de campaña.
No es un maquetado: los formularios escriben en base de datos, el panel lee de
ella, y las reglas de asignación reparten los leads entre vendedores.
## De dónde salió el contenido
El sitio implementa las recomendaciones de una auditoría de marca y mercado
previa. Los hallazgos que dirigieron el diseño:
| Hallazgo de la auditoría | Cómo se resuelve aquí |
|---|---|
| Propuesta demasiado amplia, ocho categorías sin rutas | Inicio con tres rutas —industria, riesgo y cumplimiento— y cinco páginas por segmento prioritario |
| El visitante debe inferir qué solución le toca | Clasificador de riesgo en el héroe: elige operación y clases de fuego, y el sitio lo enruta |
| Claims sin condiciones ni evidencia por modelo | Aislados en `claimsPorVerificar` y presentados como compromiso de documentación, nunca como característica |
| Sin meta description ni Open Graph | Metadatos por página, sitemap derivado de los datos, JSON-LD y tarjeta social generada |
| Conversión poco consultiva | El formulario pide lo que un ingeniero necesita para cotizar, no "solicita información" |
| Sin forma de medir efectividad comercial | Atribución de primer toque que sobrevive a la navegación, y analítica por campaña en el panel |
Los datos de producto provienen de la extracción del sitio público de FSPM. Lo
que la fuente no sostiene está marcado como pendiente de verificar; nada se
inventó para rellenar.
## Stack
Next.js 15 App Router · React 19 · TypeScript estricto · Tailwind CSS v4 ·
Prisma 6 + SQLite · sesiones propias con `jose` · Playwright para pruebas.
Sin librería de gráficas: el tablero dibuja SVG a mano.
## Arrancar en local
```bash
npm install
cp .env.example .env # ajusta AUTH_SECRET
npx prisma db push
npm run db:seed # datos de demostración
npm run dev
```
Sitio en `http://localhost:3000`. El panel en `/admin/login` — **no está
enlazado desde el sitio público**, es intencional.
Las credenciales del seed se imprimen al final de `npm run db:seed`. En la
pantalla de acceso hay además entrada rápida por perfil para la demostración,
que se apaga con `DEMO_ACCESO_RAPIDO=false`.
## Estructura
```
src/app/(sitio)/ páginas públicas
src/app/admin/ panel comercial, con noindex y fuera del sitemap
src/app/api/leads/ captura: deduplica contacto, crea oportunidad, asigna
src/data/ catálogo, industrias, clases de fuego, datos de empresa
src/lib/crm/ dominio, sesiones, consultas, acciones, asignación
src/components/marca/RielClases.tsx el elemento firma del diseño
tests/ Playwright, incluidos dos proyectos WebKit
docs/CONTRATO.md sistema de diseño y reglas de contenido
docs/DESPLIEGUE.md variables, Docker y despliegue
```
## Cómo funciona la captura
1. El visitante llega con parámetros de campaña. `src/lib/utm.ts` guarda el
**primer toque** y no lo sobreescribe.
2. Navega. Envía el formulario en una ficha de producto, ya sin parámetros en
la URL.
3. `POST /api/leads` deduplica el contacto por correo o teléfono normalizado,
crea una **oportunidad nueva** —un mismo contacto acumula varias— y guarda
la campaña del primer toque junto con el producto y la URL exactos.
4. Las reglas de asignación eligen vendedor; si ninguna coincide, se reparte por
turno entre los activos.
5. El widget de WhatsApp hace lo mismo **antes** de abrir la conversación, así
el lead existe aunque la persona nunca mande el mensaje.
## Pruebas
```bash
npm run test:e2e # todos los proyectos
npm run test:webkit # solo Safari e iOS
```
Cubren rutas y metadatos, responsividad de 320 a 1440 sin desborde horizontal,
el circuito de captura con atribución, el aislamiento entre roles del panel y
accesibilidad básica.
## Alcance
Los datos del panel son ficticios. Los logotipos de clientes se muestran sin
atribuirles testimonio ni resultado: la auditoría pide confirmar la relación
antes de usarlos comercialmente. La información normativa es de referencia y no
sustituye dictamen técnico ni jurídico.