El problema que queríamos resolver
Muchas empresas tienen conocimiento crítico en PDFs — manuales, procedimientos, SOPs, documentación de producto — y formar a empleados con ese material es lento y caro. Las herramientas tradicionales de autoría e-learning (iSeazy, Articulate, Evolmind) son potentes pero exigen un proceso manual: abrir cada documento, trocearlo en diapositivas, maquetar, añadir quizzes y exportar.
Queríamos un sistema que ingeste el PDF, lo estructure pedagógicamente con IA, permita editarlo visualmente y exporte SCORM listo para Moodle/Canvas. Un Learning Content Operating System.
El stack que elegimos
- Backend: PHP 8.3 + CodeIgniter 4.7 — porque el equipo tiene expertise profundo en CI4 y porque el patrón MVC + filtros + migraciones es exactamente lo que necesita un SaaS multi-tenant.
- DB: MySQL 8.0 con patrón shared-database-shared-schema (
tenant_iden todas las tablas). Redis para cache de sesiones y colas de IA. - Frontend: vistas PHP server-rendered + Alpine.js 3.14 para interactividad. Sin SPA. Sin React. Intencionadamente.
- IA: Claude (Anthropic) como primario, GPT-4 (OpenAI) como fallback. Embeddings para RAG. LLMs locales bajo demanda para clientes con privacidad estricta.
- Infra: VPS Hostinger KVM 2 · Ubuntu 24.04 LEMP · Nginx · Let's Encrypt · Fail2ban.
La decisión más controvertida fue no usar un framework moderno JS. La razón: el producto vive en navegadores empresariales, a veces con políticas de CSP restrictivas; Alpine.js cubre el 95 % de las interacciones sin peajes de build pipeline, bundle size ni hidratación.
Los 8 sprints, en un párrafo cada uno
Sprint 1 — Fundaciones y bugs críticos
Arrancamos con multi-tenancy real, auth de sesión, editor de cursos por bloques básico. Los primeros usuarios se pegaron con bugs que dolían: el jugador público no aplicaba layouts del editor (los cursos se veían como texto plano en producción aunque en editor eran visuales), la navegación móvil desaparecía sin alternativa, y arrastrar módulos en el dashboard no persistía el orden. Sprint 1 fue esencialmente cerrar esas heridas: layouts y bgColor aplicados en public.php, nav móvil con hamburger <820 px, endpoint POST /courses/reorder con transacción.
Sprint 2 — El editor que la gente quería
Cinco nuevos tipos de bloque: flashcard (flip animation CSS puro), hotspot (imagen con puntos interactivos), timeline, audio con subida mp3/wav, y SCORM player inline dentro del editor. Plantillas de diapositiva (portada, índice, contenido+imagen, evaluación, resumen). Drag-and-drop nested con SortableJS, Ctrl+D para duplicar, undo hasta 50 pasos. El cambio cualitativo: los clientes dejaron de pedirnos "queremos más tipos de bloque" porque ya estaban todos.
Sprint 3 — Jugador público pulido
Layouts (slide-layout-*) y bgColor en public.php y embed.php. Quiz con corrección inmediata y feedback por pregunta. Acordeón interactivo. Modo pantalla completa en embed. Evento slide_completed enviado al analytics, tiempo por diapositiva, export a CSV. Lo difícil no fue el código — fue mantener la coherencia visual entre el editor del autor y lo que ve el alumno.
Sprint 4 — Billing real (el más importante para el negocio)
Stripe Checkout + Redsys para pagos en España. Webhooks que activan/desactivan plan automáticamente según tenant.subscription_status. Página de upgrade con tabla comparativa Starter/Pro/Business. Facturas PDF con TCPDF, descargables desde /account/billing. Límites por plan (cursos, usuarios, almacenamiento), banner de aviso al 80 %, hard-stop al 100 %. Lo que rompió más veces: mantener consistencia entre el estado de Stripe y nuestro tenant.subscription_status cuando había un retry de webhook.
Sprint 5 — Multi-usuario y colaboración
Invitaciones por email (users.invited_by, status pending). Roles admin/editor/viewer con RBAC. Panel de gestión de miembros. Lock optimista en el editor (si otro usuario tiene el curso abierto, aviso con timestamp). Comentarios por diapositiva en modo revisión, con notificación email al autor. Lo subestimado: el UX del lock optimista — cuánto tiempo "bloqueas", qué pasa si el otro usuario cierra la pestaña sin logout.
Sprint 6 — IA que genera, no solo asiste
Generación de curso completo desde un prompt (título → estructura → módulos → slides). Sugerencia de imágenes (Unsplash API). Detección de tono y nivel de dificultad del contenido. Reescritura de bloque seleccionado con instrucción libre ("hazlo más conciso", "añade un ejemplo"). Import desde URL (scraping estructurado) y desde vídeo de YouTube (API de transcripción). Lo más caro de entender: cuándo usar Claude vs GPT-4. Conclusión pragmática: Claude por defecto para prosa estructurada, GPT-4 para tareas estructuradas cortas (extracción JSON).
Sprint 7 — White-label y certificados
Dominio custom por tenant (app.miempresa.com). Logo en vista pública y emails. Colores de marca en el jugador. "CreaForm" invisible en interfaz de tenants premium. Certificado PDF al completar curso (TCPDF) personalizable con logo, nombre del alumno, fecha y firma. Este sprint es donde el producto pasa de "SaaS a medida" a "algo que puedes reseller bajo tu propia marca".
Sprint 8 — Infra productiva
CDN con Cloudflare R2 para assets estáticos. Gzip/Brotli en Nginx. Redis para cache de sesiones y resultados de IA (la misma pregunta sobre el mismo módulo no va dos veces a Claude). Backups diarios de MySQL con mysqldump + cifrado + subida offsite. UptimeRobot con alertas a email/Slack. Hardening final: SSH sin password, fail2ban agresivo, auditoría OWASP básica.
Y luego renombramos todo.
El nombre original era CreaForm — unión de "crear" y "formación". Al mes de lanzar, dos problemas se hicieron claros:
creaform.comycreaform.esestaban ambos cogidos. El.espor un estudio de diseño industrial; el.compor una empresa de moldes plásticos. Buscabas "CreaForm" y aparecían ellos, no nosotros.- La unión Crea + Form no era distintiva en el mercado e-learning: suena genérica.
El 18 abril de 2026 elegimos Lectia — del latín lectio, acción de leer, lección. Comprobamos disponibilidad con dig y API del registrador, registramos lectia.es + lectia.io, forkeamos el código, diseñamos identidad nueva (wordmark con el punto de la "i" reemplazado por una página plegada — el símbolo se mantiene minimalista pero cuenta la historia del producto: lo que empieza como documento se transforma en conocimiento).
El rebrand completo — código backend + site marketing + schema.org + assets gráficos + vídeos tutorial pendientes — tomó menos de un día. El secreto no es velocidad: es que el producto estaba bien modelado. La marca era un parámetro, no un acoplamiento.
Qué nos llevamos
- Los sprints 1 y 3 son los que ganaron la confianza de los primeros clientes, no los llamativos (6 y 7). Un producto con bugs en el jugador público no lo salvan las features de IA generativa.
- Elegir un nombre sin verificar los dominios es una apuesta. La verificación costaba 5 minutos y la habíamos saltado.
- No usar SPA cuando no se necesita. Alpine.js + vistas server nos ahorraron semanas de hidratación, tree-shaking y debates estilísticos.
- Billing primero, features después. Sprint 4 desbloqueó ingresos y mentalidad empresarial en el equipo. Antes de Stripe estábamos "haciendo software"; después, "operando un SaaS".
Si tienes un proyecto parecido
Si en tu empresa veis un problema interno que parece resolvible con SaaS a medida — y sospecháis que hay más empresas con el mismo problema — es buen momento para hablar. La arquitectura de Lectia es reutilizable: multi-tenant, billing real, IA integrada, white-label. Podemos desarrollar tu producto propio sobre esta base con precio cerrado por fase.