Files
Uriel JarethandClaude Opus 5 01b817d098 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]>
2026-08-28 00:07:20 -06:00

8.1 KiB

Contrato del proyecto — léelo completo antes de escribir código

Sitio + micro CRM para FSPM (Fire Service Plus México), protección contra incendios. Es una demo comercial de Consultoría E3: tiene que verse y funcionar como producción.

Raíz: H:\MegaSync\Proyectos\fspm\fspm-web

Stack ya instalado — no cambies versiones, no agregues dependencias

Next.js 15.5.4 (App Router) · React 19 · TypeScript estricto · Tailwind CSS v4 (sin tailwind.config, los tokens viven en @theme dentro de src/app/globals.css) · Prisma 6.16 + SQLite · zod 4 · jose · bcryptjs.

Si crees que necesitas una dependencia nueva, no la instales: resuélvelo con lo que hay o dilo en tu reporte final.

Regla de propiedad de archivos — la más importante

Trabajas en paralelo con otros agentes sobre el mismo árbol. Solo puedes crear y editar los archivos de tu lote. Si necesitas cambiar un archivo ajeno, no lo toques: descríbelo en tu reporte final y el orquestador lo integra.

Archivos del orquestador, de solo lectura para ti:

src/app/globals.css          src/app/layout.tsx
src/data/*.ts                src/lib/db.ts
src/lib/utm.ts               src/lib/crm/constantes.ts
src/lib/leads/esquema.ts     src/components/marca/RielClases.tsx
src/components/site/Encabezado.tsx   src/components/site/Pie.tsx
prisma/schema.prisma         package.json   next.config.ts   .env

Sistema de diseño — deriva todo de aquí, no improvises color ni tipografía

Los tokens están en src/app/globals.css bajo @theme. Úsalos como clases de Tailwind (bg-ink, text-muted, border-rule, text-signal) o como var(--color-…).

Dos mundos, y el contraste entre ellos es la idea:

  • Oscuro = el riesgo y la operación. bg-ink (#0C1116, acero-humo azulado), paneles bg-ink-2 / bg-ink-3, filetes border-rule.
  • Claro = la evidencia y el documento. bg-paper (#EEF1F3, blanco de plano de ingeniería — no es crema), texto text-deep.

Alterna secciones entre los dos mundos. Es la traducción visual del diagnóstico del estudio: convertir autoridad técnica en confianza comprable.

Señal: text-signal / bg-signal = #DB042B, el rojo real de FSPM extraído de su CSS. Es señal, no relleno: úsalo en el CTA, en el riel de clases y en acentos puntuales. text-ember (#F2B705) es el amarillo del traje de bombero de su propia fotografía: solo para estados de riesgo, advertencia y atención, nunca decorativo.

Tipografía, ya cargada en el layout raíz:

  • font-display — Archivo 800/900. Encabezados. Versalitas y tracking cerrado. Es rotulación de equipo industrial.
  • font-sans — IBM Plex Sans. Cuerpo.
  • font-mono — IBM Plex Mono. La capa de datos: etiquetas, especificaciones, folios, cifras, códigos, UTMs. Todo dato numérico lleva font-variant-numeric: tabular-nums (ya aplicado a .font-mono y a table).

Radios casi rectos: rounded-[3px] / rounded-[2px]. Es una herramienta, no una app de consumo.

Utilidades ya escritas — reúsalas en vez de reinventar: .shell .shell-wide .eyebrow .btn .btn-signal .btn-ghost .btn-deep .btn-sm .field .field-lite .field-label .field-error .panel .panel-lite .spec .spec-cell .spec-key .spec-val .hair .hair-lite .grid-bg .grid-bg-lite .hazard .badge .badge-signal .badge-ember .badge-ok .link .skip .anim-rise .anim-ignite .reveal.

Elemento firma: el riel de clases de fuego

src/components/marca/RielClases.tsx — cinco celdas fijas A B C D K, se encienden solo las que ese producto/solución/lead cubre. Aparece en el sitio y en el panel. Úsalo siempre que haya clases de fuego; no dibujes otra variante.

Movimiento

Contenido. Una secuencia orquestada en el héroe y revelados discretos al hacer scroll con .reveal + IntersectionObserver. Nada de efectos dispersos: delatan trabajo automático. prefers-reduced-motion ya está respetado globalmente.

Piso de calidad, no negociable

  • Responsive real desde 320px. Prueba mentalmente 320 / 768 / 1280 / 1920.
  • Compatibilidad WebKit (Safari e iOS). Es requisito explícito del cliente: usa -webkit-backdrop-filter junto a backdrop-filter, -webkit-appearance: none en controles, -webkit-overflow-scrolling: touch en scroll horizontal, -webkit-tap-highlight-color en elementos táctiles, y evita gap en inline-flex sin fallback. Nada de 100vh a secas en móvil: usa 100dvh con 100vh de respaldo.
  • Accesibilidad: un solo <h1> por página, jerarquía correcta, aria-label en controles sin texto, foco visible (ya en :focus-visible), contraste suficiente, navegación completa con teclado.
  • Nada de texto dentro de imágenes. next/image con width/height o fill + sizes.
  • Sin any. Sin console.log en el código final. npx tsc --noEmit debe pasar.
  • Español de México, acentuación correcta, tono técnico y sereno.

Honestidad del contenido — regla dura del cliente

El estudio de marca concluyó que los claims del sitio original ("no caduca", "20 años de garantía", "no requiere recarga") no pueden presentarse como universales. src/data/catalogo.ts ya los aisló en producto.claimsPorVerificar.

  • Nunca presentes un claim de claimsPorVerificar como hecho.
  • Muéstralos en un bloque aparte, honesto, del tipo "Qué documentamos antes de cotizar". Eso es el argumento de venta: la competencia promete, FSPM documenta.
  • No inventes cifras, certificados, precios, casos de éxito ni testimonios. Si un dato no está en src/data/, no existe.
  • Los logotipos de clientes en src/data/empresa.ts se muestran sin atribuirles testimonio ni resultado: el estudio pide confirmar la relación antes de usarlos como caso.
  • Los casos de aplicación deben estar rotulados como ilustrativos.

Datos disponibles (solo lectura)

  • src/data/catalogo.ts — 8 categorías, 22 productos. CATEGORIAS, PRODUCTOS, getCategoria, getProducto, productosDeCategoria.
  • src/data/industrias.ts — los 5 segmentos prioritarios del estudio. INDUSTRIAS, getIndustria.
  • src/data/clases-fuego.ts — CLASES, CLASES_INFO, parseClases, serializeClases.
  • src/data/empresa.ts — EMPRESA, NAV_PRINCIPAL, NAV_PIE, CLIENTES, PRENSA, NORMAS, SITIO_URL, WHATSAPP, AVISO_DEMO.
  • src/lib/crm/constantes.ts — dominio del CRM. SQLite no guarda enums: todo estado sale de aquí.
  • src/lib/leads/esquema.ts — contrato de captura de leads y helpers de normalización.
  • src/lib/utm.ts — capturarAtribucion(), para clientes.

Assets en public/media/: marca/, producto/, clientes/, prensa/, iconos/, foto/. Usa solo archivos que existan: verifícalo con ls public/media/<carpeta>.

Rutas del proyecto

Público, dentro del grupo src/app/(sitio)/: / · /soluciones · /soluciones/[industria] · /catalogo · /catalogo/[categoria] · /producto/[slug] · /cumplimiento-nom-002 · /evidencia · /casos · /preguntas-frecuentes · /nosotros · /contacto · /aviso-de-privacidad

Panel, en src/app/admin/: /admin/login · /admin · /admin/oportunidades · /admin/oportunidades/[id] · /admin/contactos · /admin/contactos/[id] · /admin/pedidos · /admin/analitica · /admin/equipo · /admin/reglas

El panel no se enlaza desde ninguna parte del sitio público. Sin enlace en el encabezado, en el pie, ni en el sitemap. Se llega escribiendo la URL. Además va con robots: { index: false, follow: false } en su metadata.

Comandos

npm run dev        # servidor de desarrollo
npx tsc --noEmit   # verificación de tipos: tiene que pasar limpio
npx prisma db push # aplicar el esquema
npm run db:seed    # sembrar datos de demo

No corras npm install. No corras git commit. No borres archivos ajenos.

Tu reporte final

Termina con, en este orden:

  1. Archivos creados o modificados, con una línea de qué hace cada uno.
  2. Resultado literal de npx tsc --noEmit sobre tus archivos.
  3. Lo que dejaste pendiente o lo que necesitas de otro lote.
  4. Cualquier dato del sitio original que te pareció inconsistente o sin sustento.