Saltar al contenido principal
Volver a proyectos 04 · Lúmina W | Software & Technology Live

Lúmina W | Software & Technology

Ecosistema digital de Lúmina W | Software & Technology, empresa de software de Medellín. Reúne el sitio bilingüe, con sus dos caminos de servicio (desarrollo a medida y producto propio por suscripción), y el blog bilingüe con cuentas, moderación y newsletter.

Por Valentina Ramírez
Publicado: 16 de junio de 2026 · Actualizado: 5 de octubre de 2026

Landing de Lúmina W: hero con tagline de marca y llamado a la acción
Problema
Una empresa de software que vende proyectos a medida y producto propio necesita explicar cada camino sin mezclarlos y recibir solicitudes con datos útiles.
Solución
Un sitio bilingüe con dos caminos de servicio claros desde la primera pantalla y un formulario que recoge lo necesario para responder.
Resultado
Sitio y blog en producción, en luminaw.co y blog.luminaw.co.
01

Landing

Sitio bilingüe en Astro con dos caminos de servicio y formulario sobre Supabase.
Ver detalleOcultar
  • Astro
  • TypeScript
  • Tailwind CSS
  • Vercel Functions
  • Supabase
  • Brevo
  • GA4
  • SEO
  • A11y
01

El problema

Una empresa de software que vende dos cosas distintas, proyectos a medida y producto propio por suscripción, necesita explicarlas sin mezclarlas. Y necesita recibir solicitudes de contacto con datos suficientes para responder, sin montar un backend completo para una página de presentación.

Dos ofertas con compradores distintos

El desarrollo a medida y un producto por suscripción tienen tiempos, presupuestos y preguntas diferentes. Mezclados sin estructura, confunden.

Un contacto que cuesta

Un formulario con un solo campo de mensaje obliga a responder con preguntas antes de poder cotizar. Uno demasiado largo espanta.

Dos idiomas sin duplicar el trabajo

Mantener una copia en inglés a mano deja cadenas viejas y claves olvidadas.

Datos de contacto sin un backend propio

Guardar solicitudes exige una base de datos y un punto de escritura seguro, y montar un servidor para una página de presentación es desproporcionado.

02

Resultados

  • Sitio de Lúmina W en producción en luminaw.co, en español e inglés, con los dos caminos de servicio diferenciados.
  • Formulario de contacto que guarda cada solicitud con su necesidad, su etapa y su consentimiento en una tabla compartida, y avisa por correo.
  • TerraCore y OKroot presentados en la landing y en una página propia.
  • SEO técnico con datos estructurados, hreflang, sitemap, robots para rastreadores de IA y llms.txt.
Ver detalle técnico AbrirOcultar detalle técnico
03

Qué construí

  1. 01

    Astro con salida estática y Tailwind CSS. Doce componentes montan la landing en un orden fijo: portada, bifurcación entre los dos caminos, problema, agitación, cinta de frases, solución, proceso, manifiesto, por qué nosotros, producto, preguntas frecuentes y contacto. Cada sección tiene un ancla que coincide con la barra de navegación y el pie.

  2. 02

    Español por defecto en la raíz e inglés bajo /en, con las dos copias en diccionarios tipados: el diccionario en inglés exige las mismas claves que el español, así que una clave que falte rompe el build. Las páginas de productos y contacto tienen ruta traducida, y las legales conservan el mismo nombre.

  3. 03

    Formulario de contacto: el navegador manda un JSON a una Función de Vercel que valida los campos (nombre, empresa, correo, teléfono, necesidad, etapa y mensaje), exige el consentimiento y descarta en silencio lo que llegue por un campo trampa oculto. Los valores de necesidad y etapa son códigos fijos en inglés, así que una opción se guarda igual en los dos idiomas.

  4. 04

    La Función guarda cada solicitud en Supabase y completa la fecha de consentimiento, el origen y el agente de usuario por su cuenta. No guarda la IP. Si el correo ya existe, responde que todo salió bien sin crear otra fila, y avisa igual al buzón interno.

  5. 05

    El aviso interno sale por Brevo y es de mejor esfuerzo: si el correo falla, la solicitud ya quedó guardada. El almacenamiento solo corre en producción de Vercel, así que en las previsualizaciones el formulario responde 503 por diseño.

  6. 06

    La tabla de solicitudes es una sola, compartida con las landings de TerraCore y OKroot, con una columna de producto y una restricción de unicidad por producto y correo. Tiene seguridad por filas activada y sin permisos para los roles públicos: solo la Función puede escribir.

  7. 07

    SEO técnico: un grafo JSON-LD con ProfessionalService, WebSite y WebPage, más FAQPage en las preguntas frecuentes, canónica propia, hreflang entre es, en y x-default, sitemap con alternates y un robots.txt que permite de forma explícita a 21 rastreadores de IA, junto con un llms.txt.

  8. 08

    Analítica con consentimiento: Google Analytics 4 se carga solo si la persona acepta el aviso de cookies, y la decisión se guarda en el almacenamiento local, sin cookies propias. El aviso no bloquea la página y aparece tras desplazarse un poco.

  9. 09

    Rendimiento y entrega: imágenes en WebP con dimensiones explícitas, fuentes con swap, caché de larga duración para los recursos con hash y las imágenes, y cabeceras de seguridad. El despliegue en Vercel es continuo.

  10. 10

    Accesibilidad trabajada en el código: enlace para saltar al contenido, foco visible, etiquetas por campo con errores anunciados y mensaje de éxito con rol de estado, y respeto de prefers-reduced-motion. Un respaldo sin JavaScript deja visible el contenido que aparece al desplazarse.

  11. 11

    Calidad: formato, build y escaneo de secretos en cada PR, con un flujo de ramas por entornos.

Dos caminos

Una bifurcación en la primera pantalla separa el producto propio en SaaS del desarrollo a medida, y cada uno tiene su propio proceso.

Proceso por camino

Cuatro fases para el desarrollo a medida y cuatro para el producto, con las reglas de trabajo de cada una.

Productos

TerraCore y OKroot en la landing y en una página propia, con su estado y su enlace.

Preguntas frecuentes

Diez preguntas con respuesta, también publicadas como datos estructurados.

Formulario de contacto

Recoge necesidad, etapa y consentimiento, guarda la solicitud y avisa por correo.

Español e inglés

Dos copias completas, con rutas traducidas, hreflang y un selector de idioma.

04

Diseño

  1. 01

    Sistema editorial y sobrio: bordes rectos (radios de 0, 2 y 4 píxeles), líneas de un píxel en lugar de sombras y una sola hoja de estilos con los tokens.

  2. 02

    Azul como color principal para enlaces, etiquetas y foco, y ámbar como acento solo de relleno. Cuando el ámbar es texto sobre fondo claro se usa una versión más oscura para mantener el contraste.

  3. 03

    Cabinet Grotesk para los títulos y Switzer para el texto, cargadas desde Fontshare con swap.

  4. 04

    Página clara con superficies oscuras fijas (contacto, pie, productos y la barra de navegación). No hay selector de tema.

  5. 05

    Los llamados a la acción llevan solo texto, sin flechas ni iconos, y la regla del proyecto es no usar guiones como conector en los textos.

05

Decisiones de arquitectura

01 Dos caminos explícitos en vez de un solo servicio VerCerrar
Contexto
Lúmina W ofrece desarrollo a medida y un producto propio en SaaS, y quien compra cada uno llega con preguntas distintas.
Trade-off
Una frase general de desarrollo de software convence menos, pero separar los caminos añade una decisión en la primera pantalla.
Una sección de bifurcación, una solución en dos servicios y un proceso con cuatro fases para cada camino, cada uno con su propio llamado a la acción.
02 Productos propios como evidencia VerCerrar
Contexto
Quien evalúa a una empresa de software quiere ver producto funcionando, no solo promesas de desarrollo a medida.
Trade-off
Dedicar espacio a los productos puede restar protagonismo al servicio, y su estado cambia con el tiempo.
TerraCore y OKroot aparecen en la landing y en una página de productos, con el estado y el enlace de cada uno definidos en el diccionario de textos.
03 Función de Vercel con Supabase, y no un servidor propio VerCerrar
Contexto
El sitio necesita guardar solicitudes de contacto desde el primer día, y montar un backend para una landing es desproporcionado.
Trade-off
Hay una pieza de servidor, aunque pequeña, que mantener, y el formulario no funciona en las previsualizaciones, donde no hay base de datos.
Una Función de Vercel valida, aplica la honeypot y el consentimiento, y escribe en Supabase desde el servidor. El navegador nunca habla con Supabase.
04 Una tabla de solicitudes compartida entre las landings VerCerrar
Contexto
Lúmina W, TerraCore y OKroot reciben solicitudes con casi los mismos datos, y tres bases sueltas habrían multiplicado el trabajo.
Trade-off
Si alguien escribe dos veces con el mismo correo, la segunda no se guarda: el aviso interno la menciona, pero la tabla conserva solo la primera.
Una sola tabla con una columna de producto y unicidad por producto y correo, con el mismo esquema copiado en los tres repositorios.
05 Diccionarios tipados para dos idiomas VerCerrar
Contexto
Cada texto nuevo debe existir en español e inglés, y una cadena olvidada se nota solo cuando alguien cambia de idioma.
Trade-off
Obliga a traducir todo cambio al mismo tiempo, incluso uno pequeño.
El diccionario en inglés está tipado con el del español, así que una clave que falte rompe el build.
06 Analítica solo con consentimiento VerCerrar
Contexto
El sitio mide visitas con Google Analytics 4, y esa medición requiere el permiso de quien visita.
Trade-off
Sin la aceptación no hay datos de ese visitante, y el aviso aparece tras desplazarse para no tapar la primera pantalla.
El script de Analytics se inyecta solo después de aceptar y la decisión queda en el almacenamiento local, sin cookies propias.
06

Aprendizajes

01

Pedir necesidad y etapa en el formulario, con valores fijos, hace que la primera respuesta ya pueda ser una propuesta y que los datos se comparen entre idiomas.

02

Las promesas del texto deben ser algo que el código haga: decir que se recibe una confirmación por correo exige que la Función envíe ese correo.

03

Un diccionario tipado convierte una traducción olvidada en un error de build en lugar de en una página a medias.

02

Blog

Plataforma de blog bilingüe en Next.js con cuentas, moderación y newsletter.
Ver detalleOcultar
  • Next.js
  • React
  • TypeScript
  • Tailwind CSS
  • Prisma
  • PostgreSQL
  • Supabase
  • NextAuth
  • Brevo
  • Claude API
  • Vercel
01

El problema

El conocimiento técnico que sale de proyectos reales necesita un canal propio, con control sobre el contenido, los comentarios y las suscripciones, sin depender de una plataforma externa. El sitio anterior era estático, con un CMS de archivos, y no tenía cuentas ni comunidad.

Una plataforma ajena decide por ti

Publicar en una plataforma de terceros deja la audiencia, los comentarios y la suscripción en manos de otra empresa.

Un sitio estático no tiene comunidad

El sitio anterior publicaba bien, pero no tenía cuentas, comentarios ni una forma de que alguien más propusiera un artículo.

Dos idiomas son doble trabajo

Mantener cada artículo en español e inglés a mano duplica el esfuerzo de publicar.

Abrir comentarios abre el riesgo

Cualquier cuenta que escribe o comenta es una entrada para spam, enlaces dudosos y abuso de las rutas que envían correo.

02

Resultados

  • Plataforma en producción en blog.luminaw.co, con cuentas, publicación con aprobación, comentarios con moderación y newsletter.
  • Seis artículos de archivo importados, tres en español y tres en inglés, y un flujo para publicar más desde la propia aplicación.
  • Traducción automática de artículos publicados al otro idioma, con reintento manual desde el panel.
  • Suite de 28 archivos de pruebas unitarias sobre lógica pura, con lint, build y escaneo de secretos en cada PR.
Ver detalle técnico AbrirOcultar detalle técnico
03

Qué construí

  1. 01

    Aplicación Next.js (App Router, React y TypeScript) con Prisma sobre PostgreSQL en Supabase, y Tailwind CSS para los estilos. Reemplazó a un sitio anterior en Astro con Decap CMS. El layout es dinámico a propósito: el build en CI no necesita base de datos.

  2. 02

    Los artículos viven de dos formas: archivos Markdown en el repositorio (seis hoy, tres por idioma) que un importador sube a la base en cada build de producción, y artículos escritos por cuentas dentro de la aplicación. El importador crea o actualiza por idioma y slug, y nunca toca autoría, likes, guardados ni comentarios.

  3. 03

    Flujo de publicación: un artículo pasa por borrador, pendiente, publicado o rechazado. Cualquier cuenta puede escribir y enviar a revisión, solo la administradora publica directo, y editar un artículo publicado desde una cuenta que no es la de ella lo devuelve a pendiente. El slug queda fijo al publicar.

  4. 04

    Bilingüe: español sin prefijo e inglés bajo /en, con rutas traducidas (articulos, categoria, cuenta) y un middleware que las reescribe a las rutas internas. Cada idioma es una fila de Post enlazada con el original, y likes, guardados y comentarios se anclan siempre al original.

  5. 05

    Traducción automática: al publicar un original, y solo si hay clave configurada, una tarea en segundo plano manda título, descripción, cuerpo y etiquetas a la API de Claude como datos, valida la respuesta y guarda la versión en el otro idioma. La administradora puede reintentarla desde el panel. Los artículos de archivo traen sus propias traducciones.

  6. 06

    Comunidad: comentarios con hilos de hasta 2000 caracteres, likes, guardados, perfiles públicos y seguimiento. La moderación de comentarios es un filtro local por reglas (términos bloqueados y tope de enlaces), sin llamar a ningún modelo: lo que coincide queda pendiente y la administradora lo aprueba o rechaza.

  7. 07

    Newsletter con Brevo: una lista por idioma, suscripción desde el sitio y envío de prueba o campaña desde el panel de administración, con el enlace de baja de Brevo. Las notificaciones de respuesta, seguimiento y guardado también salen por correo, además de dentro del blog.

  8. 08

    Cuentas con correo y clave verificados por correo, más Google, GitHub y LinkedIn cuando están configurados, e invitaciones que llegan con el correo ya verificado. Un proveedor externo solo se acepta si confirma el correo. Cuenta bloqueada 15 minutos tras 5 intentos fallidos, y suspensión y cierre de sesiones desde el panel.

  9. 09

    Los permisos se verifican en el servidor en cada petición. La administración está restringida a una sola cuenta, protegida de suspensión y borrado.

  10. 10

    Seguridad por capas: límites de frecuencia en credenciales y operaciones sensibles, verificación de origen en las rutas que escriben, cabeceras de seguridad y contenido de usuario saneado antes de renderizarse.

  11. 11

    Imágenes: se validan en el servidor, se rechazan los formatos no admitidos y se convierten a WebP con un límite de tamaño según el uso (portada, cuerpo o avatar) antes de guardarlas en almacenamiento de objetos.

  12. 12

    SEO y descubrimiento: sitemap dinámico con alternates por idioma, robots con un grupo aparte para crawlers de IA, llms.txt, feed RSS por idioma y JSON-LD (Organization, WebSite, BlogPosting, Blog, CollectionPage, ProfilePage y BreadcrumbList). La búsqueda usa coincidencia insensible a mayúsculas sobre título, descripción, cuerpo, autor y etiquetas.

  13. 13

    Analítica con consentimiento: GA4 se carga solo si la persona acepta y si hay un identificador configurado, y el enlace entre dominios cubre luminaw.co, terracoreapp.co y okroot.co.

  14. 14

    Calidad y entrega: 28 archivos de pruebas unitarias sobre lógica pura, lint y build en cada PR, escaneo de secretos y un flujo de ramas por entornos. En producción, el despliegue aplica los cambios de base de datos y carga los artículos.

  15. 15

    Un generador de portadas arma las imágenes de 1200 por 630 en WebP, una por idioma, con un tope de 150 KB, a partir de una especificación JSON y un arte SVG.

Artículos y aprobación

Escribe en Markdown, envía a revisión y publica cuando la administradora aprueba, con motivo de devolución.

Comunidad

Comentarios con hilos, likes, guardados, perfiles públicos y seguimiento entre cuentas.

Español e inglés

Rutas, textos, correos y notificaciones en los dos idiomas, con traducción automática de los artículos.

Newsletter

Suscripción por idioma y envío de prueba o campaña desde el panel de administración.

Panel de administración

Cola de artículos y comentarios, destacados, invitaciones y gestión de usuarios: buscar, suspender, reactivar y eliminar.

Búsqueda y descubrimiento

Búsqueda con atajo de teclado, categorías, orden por popularidad, feed RSS, sitemap y llms.txt.

Del borrador al lector en dos idiomas

  1. 01 Una cuenta escribe un artículo en Markdown y lo envía a revisión.
  2. 02 La administradora lo aprueba, o lo devuelve con una nota que recibe como notificación.
  3. 03 Al publicarse, una tarea en segundo plano manda el contenido a la API de Claude como datos y valida la traducción.
  4. 04 La versión en el otro idioma se guarda enlazada al original y entra al sitemap con su alternate.
  5. 05 Los likes, guardados y comentarios de cualquiera de las dos versiones se acumulan en el original.
04

Diseño

  1. 01

    Los estilos del prototipo diseñado aparte se portaron tal cual, y el tema vive en una sola hoja de estilos con Tailwind CSS sin el reset base.

  2. 02

    Artículo con barra de progreso de lectura, tabla de contenidos y tarjeta para compartir, con el menú nativo del dispositivo como camino para Instagram.

  3. 03

    Portadas de 1200 por 630 por idioma, generadas desde una especificación y un arte SVG, con un tope de peso por imagen.

  4. 04

    Accesibilidad trabajada en el código: enlace para saltar al contenido, menús con teclado y un diálogo de confirmación con el foco atrapado. Los cambios de contraste que alterarían el diseño están pendientes de decisión.

  5. 05

    Selector de idioma que recuerda la elección en una cookie, y detección del idioma del navegador en la primera visita.

05

Decisiones de arquitectura

01 Una aplicación con base de datos en lugar de un sitio estático VerCerrar
Contexto
El blog necesitaba cuentas, comentarios, aprobación de artículos, suscripciones y dos idiomas.
Trade-off
Una aplicación dinámica depende de una base de datos y exige más cuidado de seguridad que un sitio de archivos.
Next.js con Prisma y PostgreSQL, y un layout dinámico para que el build no necesite la base. Los artículos de archivo se siguen versionando en el repositorio y se importan al desplegar.
02 Una fila por idioma, enlazada con el original VerCerrar
Contexto
Un artículo existe en dos idiomas con slugs distintos, pero la conversación a su alrededor es una sola.
Trade-off
Cada consulta de interacciones tiene que resolver primero cuál es el original.
Cada versión es una fila de Post con una referencia al original. Likes, guardados y comentarios se anclan siempre al original.
03 Claude para traducir, solo contenido ya publicado VerCerrar
Contexto
Traducir a mano cada artículo duplica el trabajo de publicar.
Trade-off
Una traducción de un modelo puede equivocarse y depende de una clave externa, así que se activa solo si hay clave.
Una tarea en segundo plano manda solo el artículo ya publicado, como datos y no como instrucciones, valida la respuesta antes de guardarla, y la administradora puede reintentarla. Ningún dato de cuentas ni comentarios sale hacia la API.
04 Moderación por reglas locales VerCerrar
Contexto
Los comentarios abiertos reciben spam y enlaces dudosos, y mandarlos a un modelo añade costo y envía texto de usuarios a un tercero.
Trade-off
Un filtro por términos y por cantidad de enlaces es tosco: deja pasar lo que no coincide y retiene lo que sí aunque sea legítimo.
Un filtro local pone en pendiente los comentarios que coinciden y la administradora decide. Sus propios comentarios quedan exentos.
05 Límites de frecuencia sin infraestructura nueva VerCerrar
Contexto
Cada ruta que escribe, envía correo o recibe credenciales necesita un tope, y no se quería sumar infraestructura nueva.
Trade-off
Usa la base de datos de la aplicación en cada llamada y es una ventana fija, menos precisa que una cola dedicada.
Los límites se guardan en la propia base de datos de la aplicación, sin infraestructura nueva. Son estrictos en credenciales y operaciones sensibles, y más flexibles en el resto.
06 Permisos verificados en el servidor VerCerrar
Contexto
Un token de sesión guarda lo que era cierto al emitirse, pero una cuenta puede suspenderse o cambiar de clave después.
Trade-off
Cada petición autenticada hace una lectura a la base de datos.
El servidor comprueba el estado actual de la cuenta en cada petición y descarta la sesión si la cuenta está suspendida o cambió de clave. La sesión por sí sola nunca decide un permiso.
07 Una sola cuenta administradora VerCerrar
Contexto
Hace falta alguien que apruebe contenido, sin montar un sistema de roles para una persona.
Trade-off
No hay roles delegables ni más de una administradora sin cambiar la configuración.
Hay una única cuenta administradora. Cada acción del panel comprueba esa condición en el servidor, y esa cuenta no se puede suspender ni borrar.
06

Aprendizajes

01

Abrir cuentas y comentarios cambia el tipo de proyecto: casi cada ruta nueva necesita un límite de frecuencia, una verificación de origen y una decisión sobre qué pasa si falla.

02

Verificar los permisos en el servidor en cada petición cuesta una consulta, pero evita que una suspensión o un cambio de clave llegue tarde.

03

Un filtro local de moderación es predecible y barato, pero solo ordena la cola: la decisión sigue siendo de una persona.

07

Roadmap

Ahora

  • Blog bilingüe en producción con comunidad, aprobación de artículos, newsletter y traducción automática.
  • Auditorías de seguridad, SEO y accesibilidad aplicadas al código.

Siguiente

  • Artículos relacionados por etiquetas.
  • Eliminar la propia cuenta y cambiar el correo desde el perfil.
  • Reportar un comentario.
  • Alojar las fuentes en el propio sitio, monitoreo de errores y pruebas de extremo a extremo en CI.

Después

  • Generación de borradores con la API de Claude y n8n, y programación automática de publicaciones.
  • Compartir en redes desde n8n y panel de analítica.
A un click

Menos trabajo a mano, más clientes que llegan solos.

Construyo landing pages, sitios web, automatizaciones, chatbots y apps a medida, y el contenido para que te encuentren. Seguridad desde el diseño y precio fijo.

MVP de 6 a 10 semanas. Disponibilidad limitada, respondo en 24 horas.