Saltar al contenido
megapromotingVamos a hablar

Experiencia · Sitios web

Este sitio es nuestra especificación técnica, incluidas las mediciones que no nos favorecen.

Construimos sitios renderizados en servidor, con imágenes en AVIF y WebP, cabeceras de seguridad verificadas desde fuera, mapa del sitio generado a partir de datos y una verificación de aceptación ejecutada después de cada publicación. Todo se puede inspeccionar en la página que lees.

Ya construidoNo podemos citar un sitio de cliente sin su acuerdo, pero no lo necesitamos: la prueba es esta misma página. Ejecuta Next.js 16.2.4 con React 19.1.0, se sirve prerenderizada desde caché (`x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`), lleva HSTS con `preload`, `nosniff`, `SAMEORIGIN`, `Referrer-Policy` y una política de contenido completa — verificado con `curl -I` el 06.09.2026. El mapa del sitio contiene 147 direcciones, todas generadas a partir de datos, no escritas a mano. La segunda implementación, en el mismo repositorio: la infraestructura del formulario — registro append-only, sonda pública de salud, limitación de tasa — y el script de aceptación ejecutado después de la publicación.

Un sitio de presentación tiene una sola prueba honesta: ¿puedes verificar desde fuera lo que la empresa dice sobre él? Por eso esta página no enumera tecnologías, sino cosas que puedes comprobar tú mismo con un comando. El sitio ejecuta Next.js 16.2.4 y React 19.1.0, y las páginas se prerenderizan en la construcción y se sirven desde caché —se ve en los encabezados de respuesta: `x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`, `s-maxage=31536000`, con una ventana de 300 segundos en la que una página antigua aún puede servirse mientras se actualiza.

La renderización en el servidor no es una preferencia de arquitecto. Un visitante con conexión débil y un motor de búsqueda reciben el mismo HTML completo, sin esperar JavaScript. Encima viene la disciplina de recursos: las imágenes salen en AVIF y WebP, con caché de un año; las fuentes están alojadas por nosotros, no solicitadas a un servicio externo; ocho bibliotecas de interfaz tienen las importaciones optimizadas para no cargar módulos enteros por un solo icono.

Los encabezados de seguridad se envían desde dos lugares y se verifican en la respuesta real, no solo en la configuración: transporte seguro impuesto durante dos años con subdominios e inclusión en la lista de precarga, prohibición de adivinar el tipo de archivo, restricción de incrustación en marcos ajenos, política de referencia, y una política de permisos que cierra la cámara y deja el micrófono solo para el propio origen — porque las demostraciones de voz lo necesitan y, sin esta excepción, el navegador lo rechaza en silencio.

La última parte es la que nos diferencia, y es incómoda: publicamos también lo que hemos medido mal en nuestro sitio. El servidor aún no ofrece Brotli ni HTTP/2. El catálogo de traducciones se transmite en cada navegación y cuesta aproximadamente 70 KB comprimidos cada vez. Un paquete de 443 KB contiene cuatro catálogos de idioma, de los que solo uno es enrutable. Las fuentes también traen el subconjunto cirílico, aunque las páginas verificadas no contienen ningún carácter cirílico. Estas cifras están medidas, escritas en el repositorio y en la lista de reparaciones. Un proveedor que no tiene estas cifras sobre su propio sitio o no las ha medido, o no quiere decirlo.

Qué incluye

El trabajo, por componentes

Renderización en el servidor, servida desde caché

Las páginas se prerenderizan en la construcción y se entregan como HTML completo, no se construyen en el navegador. En la respuesta real aparecen `x-nextjs-prerender: 1` y `x-nextjs-cache: HIT`, con `cache-control: s-maxage=31536000` y una ventana de 300 segundos en la que la versión antigua todavía puede servirse mientras se refresca. El efecto práctico: un visitante con conexión débil y un crawler reciben el mismo contenido, en la misma solicitud.

Imágenes y fuentes con presupuesto, no con suerte

Los formatos configurados son AVIF y WebP, con una duración mínima de caché de 31.536.000 segundos — un año — y el encabezado `immutable` en los archivos estáticos, imágenes y fuentes. Las fuentes están alojadas por nosotros en la construcción, no solicitadas a un servicio externo en cada visita, y se muestran con `swap`, para que el texto aparezca antes de descargar la fuente. También existe un script de compresión por lotes, con calidad 80 para WebP y 75 para AVIF, para que la fuente no dependa de lo que alguien haya exportado desde el editor gráfico.

Encabezados de seguridad enviados desde dos lugares y verificados en la respuesta

Desde la aplicación: transporte seguro impuesto durante 63.072.000 segundos con subdominios e inclusión en la lista de precarga, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin` y una política de permisos que cierra la cámara, deja el micrófono solo para el propio origen y desactiva la agrupación por intereses. Desde el servidor web, por separado: una política de seguridad de contenido completa, con la lista explícita de orígenes permitidos. En la entrega se escribe explícitamente que son dos lugares — de lo contrario, el siguiente que cambie algo lo buscará en el sitio equivocado.

Mapa del sitio generado a partir de datos, no escrito a mano

El mapa del sitio se construye a partir de cinco fuentes — 13 direcciones fijas, los artículos, 19 productos, 12 servicios y 100 combinaciones servicio × dominio — y pasa por una deduplicación final. El resultado: 147 direcciones, contadas tanto en el código como en el archivo servido en producción. Una página nueva entra automáticamente; una eliminada desaparece. Nadie mantiene una lista paralela que se desincroniza en tres semanas.

Las direcciones viejas no mueren: 43 redirecciones permanentes

Una limpieza de estructura deja atrás direcciones que alguien tiene guardadas o ha publicado. En la configuración hay 43 redirecciones permanentes — 9 guías hacia el blog, 20 artículos huérfanos, 6 estudios de caso remapeados y 8 páginas individuales. También existen 11 páginas que redirigen desde dentro de la aplicación; son correctas funcionalmente, pero más costosas que una regla de configuración, y se registran como tales en la lista de reparaciones.

El formulario es infraestructura, no decoración

La solicitud se escribe en un registro append-only antes de intentar la entrega, con una segunda línea para el resultado; existe una sonda pública de estado que dice si un lead puede llegar a una persona ahora mismo; y las solicitudes hacia las interfaces se limitan a 10 por minuto, con la clave tomada del último salto del encabezado de direcciones redirigidas, no del primero — el primero lo envía el cliente. Los motivos están escritos en el código, no en documentación separada.

Verificación de aceptación después de cada publicación

Un script abre cada página de producto, en grupos de tres, y falla si falta el código 200, el ancla de preguntas, el ancla de ejemplo o la dirección canónica. Luego verifica el mapa del sitio — que contenga cada producto y no contenga variantes de idioma que no se puedan abrir — y `robots.txt`, para que no bloquee los recursos necesarios para la renderización. Cada verificación corresponde a algo que ya se rompió una vez.

Dirección canónica resuelta una vez, para todo el sitio

La dirección canónica se declara de forma relativa, en un solo lugar del arreglo base, y se resuelve para cada ruta por separado. La misma solución para la dirección de compartir en redes sociales, que antes declaraba la página de inicio en la mayoría de las páginas. Es una línea de código que reemplaza una convención que cada nueva página habría tenido que recordar por sí sola — y que, inevitablemente, no recuerda.

Lo que no funciona está escrito en el repositorio, junto al código

El repositorio contiene un archivo de defectos conocidos que explica, por ejemplo, por qué las variantes de idioma en la dirección no cambian el idioma, por qué la solución obvia empeora las cosas — en el renderizado en servidor no existe ni almacenamiento local ni navegador, así que el detector cae en inglés y todas las páginas salen en inglés — y cuáles son las dos soluciones reales. Preferimos que un comprador técnico encuentre la limitación escrita por nosotros, no descubierta por él.

Qué aspecto tiene

El recorrido, paso a paso.

01

El inventario de direcciones y qué pasa con las antiguas

La primera entrega es la lista de las direcciones existentes y la decisión para cada una: se queda, se redirige o desaparece. En este sitio resultaron 43 redirecciones permanentes. Es el trabajo que todo el mundo se salta y que produce, unos meses más tarde, páginas de error en los resultados de búsqueda.

02

La estructura de contenido y las fuentes a partir de las que se genera

Las páginas de producto y de servicio se construyen a partir de datos, no de archivos separados. De ahí vienen el mapa del sitio generado automáticamente, las direcciones canónicas consistentes y la posibilidad de verificar programáticamente que cada página tenga lo necesario. Entregamos la estructura de datos, no solo las páginas renderizadas a partir de ella.

03

La construcción, con presupuestos fijados antes del contenido

Definimos desde el inicio qué formato tienen las imágenes, qué se cachea y cuánto, qué se renderiza en el servidor y qué queda interactivo en el navegador. El contenido se coloca luego dentro de ese presupuesto. El orden inverso produce sitios que se ven bien al lanzarse y se vuelven más pesados con cada página añadida.

04

La publicación con gate y verificación de aceptación

La publicación verifica la memoria libre del servidor, ejecuta la auditoría de seguridad de las dependencias, construye desde limpio y confirma que el proceso esté iniciado antes de reportar éxito. Justo después, el script de aceptación abre las páginas y comprueba los anclajes, las direcciones canónicas, el mapa del sitio y `robots.txt`. Ambos se entregan, no se quedan con nosotros.

05

La entrega, con la lista de faltantes y de mediciones

Entregamos el código, el procedimiento de publicación, el procedimiento de reversión, las direcciones de salud y la lista escrita de lo que no está cubierto, con cifras. Para este sitio la lista incluye la falta de Brotli y de HTTP/2 en el servidor, el coste del catálogo de traducciones en cada navegación y el subconjunto de fuentes no utilizado. Preferimos que la lista venga de nosotros.

Cuatro capas verificables desde fuera1HTML prerenderizado servido desde la caché2imágenes AVIF/WebP y fuentes alojadas localmente3encabezados de seguridad de la aplicación y del servidor web4el mapa del sitio y las direcciones canónicas generadas a partir de datos
Cuatro capas verificables desde fuera

Los datos

Qué tocamos, dónde están y cuánto se quedan

Las preguntas que hace cualquiera que tenga un delegado de protección de datos — hechas aquí antes de que las haga él.

Los datos del formulario de contacto
Nombre, dirección de correo electrónico, teléfono, empresa, servicio elegido, mensaje, página de procedencia y prefijo de red del visitante. Se escriben en un registro en el propio servidor, con permisos `0700` para el directorio y `0600` para los archivos, fuera del directorio de versiones. Plazo: 24 meses, aplicado por el código en cada escritura, no por un planificador que puede olvidarse.
La dirección IP, recortada antes de ser escrita
Se conserva solo el prefijo de red — `/24` para IPv4, `/48` para IPv6 — y se lee el último salto del encabezado, porque el primero lo envía el cliente y no demuestra nada. La misma función se usa también para la limitación de tasa, así que no existe un segundo lugar donde la dirección completa pueda llegar por error.
Estadísticas de tráfico
La medición pasa por la herramienta de análisis configurada y se activa después del consentimiento. Las cookies reales se verificaron empíricamente en el sitio en vivo, antes y después de aceptar, y la política de cookies fue reescrita después de esa verificación, no al revés. La política anterior enumeraba cookies que no existían.
Registro de tratamientos, versionado junto al código
Cada tipo de datos tocado por el sitio tiene una entrada con finalidad, base, categorías y plazo, en un documento guardado en el mismo repositorio. Cuando el código cambia un plazo, el documento cambia en el mismo commit. Lo que no está establecido —por ejemplo, la retención real de la cuenta de análisis— se marca explícitamente como elemento a aclarar, no se declara como hecho.
Lo que no sale del servidor
Los tokens de notificación, las claves del proveedor y los identificadores de canal. La sonda de salud devuelve exclusivamente valores lógicos, precisamente para poder ser consultada por un servicio externo sin revelar nada sobre la configuración.

Un caso

Lo que muestra la auditoría de tu propio sitio cuando lo publicas entero

La situación

Después de una reestructuración, el sitio propio parecía estar en orden: todas las páginas respondían 200, el panel era verde. Nos hicimos la pregunta que hacemos a los clientes: ¿qué dice una medición hecha desde fuera, en todas las direcciones a la vez, no en la página de inicio?

Qué construimos

Recorrimos con solicitudes directas cada dirección conocida —249 direcciones, 23 columnas por dirección, sin seguir redirecciones, con como máximo seis solicitudes en paralelo— y pusimos el resultado en un archivo tabular versionado. Encima de eso ejecutamos comprobaciones separadas: la compresión real del HTML, qué se transmite en cada navegación, qué contienen los paquetes de JavaScript, qué fuentes se descargan, qué encabezados de caché y de transporte ofrece el servidor. Cada cifra fue verificada en la respuesta real, no deducida de la configuración.

Qué salió

244 direcciones responden 200 y 5 redirigen. 131 páginas no tenían dirección canónica, y 219 de 244 declaraban la página de inicio como dirección de compartición: ambas cosas ya se corrigieron ahora con una línea en la configuración básica, que se aplica a cada ruta. El servidor no ofrece Brotli ni HTTP/2. El catálogo de traducciones, 2.268 claves, se transmite en cada navegación y cuesta aproximadamente 70 KB comprimido cada vez. Un paquete de 443 KB contiene cuatro catálogos de idioma, de los cuales solo uno es enrutable. Las fuentes también traen el subconjunto cirílico, aunque las páginas verificadas no contienen ningún carácter cirílico. Todas las cifras, con los comandos que las reproducen, están escritas en el repositorio.

Qué no dice el caso

Son mediciones de laboratorio, hechas desde fuera, con solicitudes directas. No son datos de campo de visitantes reales y no las presentamos como tales: las métricas de carga percibida no pudieron leerse en la herramienta utilizada y están marcadas explícitamente como no medidas. No ejecutamos la compilación de la aplicación durante la auditoría, porque varias personas trabajaban en el mismo checkout.

Preguntas

Lo que nos pregunta la gente antes de llamar

¿Con qué construyen, concretamente?

Next.js 16.2.4 con React 19.1.0 y TypeScript, con Tailwind para estilos y componentes de interfaz accesibles basados en primitivas Radix. Las páginas se prerenderizan en la compilación y se sirven desde caché — se verifica desde fuera: los encabezados de respuesta contienen `x-nextjs-prerender: 1` y `x-nextjs-cache: HIT`. No es una lista de tecnologías que hayamos leído; es la pila sobre la que corre la página que estás leyendo ahora.

¿Cómo verifico yo mismo lo que dicen sobre seguridad?

Con un solo comando: `curl -I https://www.megapromoting.com/servicii`. Verás `strict-transport-security: max-age=63072000; includeSubDomains; preload`, `x-content-type-options: nosniff`, `x-frame-options: SAMEORIGIN`, `referrer-policy: strict-origin-when-cross-origin`, una política de permisos que cierra la cámara y deja el micrófono solo para su propio origen, además de una política de seguridad de contenido con la lista explícita de orígenes. Los primeros cinco vienen de la configuración de la aplicación; la última la envía el servidor web — dos lugares diferentes, y eso lo escribimos en la entrega.

¿Cómo saben que no rompieron algo en la última publicación?

De un script de aceptación ejecutado después de la publicación. Abre cada página de producto y falla si falta el código 200, el ancla de preguntas, el ancla de ejemplo o la dirección canónica; luego verifica que el mapa del sitio contenga cada producto y no contenga variantes de idioma que no se abren, y que `robots.txt` no bloquee los recursos de renderizado. Cada comprobación de la lista corresponde a algo que ya se rompió. El script se entrega junto con el proyecto: tú también puedes ejecutarlo.

¿Vuestro sitio es rápido?

Depende de lo que midas, y tenemos cifras en ambos sentidos. Buenas: las páginas se prerenderizan y se sirven desde caché, las imágenes salen en AVIF y WebP con caché de un año, las fuentes se alojan localmente. Malas, medidas en el propio sitio: el servidor no ofrece Brotli ni HTTP/2 — una petición con `Accept-Encoding: br` recibe una respuesta sin compresión; el catálogo de traducciones se transmite en cada navegación y cuesta aproximadamente 70 KB comprimidos cada vez; un paquete de 443 KB contiene cuatro catálogos de idioma de los cuales solo uno es rutable. No te doy una puntuación de laboratorio; te doy los octetos medidos y la lista de reparaciones que sale de ellos.

¿Quién mantiene el mapa del sitio?

Nadie, y esa es la respuesta correcta. Se genera a partir de cinco fuentes de datos — direcciones fijas, artículos, productos, servicios y las combinaciones servicio × dominio — y pasa por una deduplicación final. Salen 147 direcciones, la misma cifra en el código y en el archivo servido en producción. Una página nueva entra automáticamente. Lo que falta hoy, dicho claramente: las entradas no llevan fecha de última modificación, y 93 direcciones que se pueden indexar aún no están en el mapa. Están en la lista de reparaciones, no ocultas.

¿Hacéis sitios multilingües?

Aquí tengo que ser preciso, porque es el límite más claro de este sitio. Cambiar el idioma desde la dirección no funciona: la configuración fija el rumano, así que el detector nunca lee el parámetro. Hemos escrito en el repositorio por qué la solución evidente es peor: en el renderizado en servidor no existe ni almacenamiento local ni navegador, así que el detector cae en inglés y todas las páginas salen en inglés, y cuáles son las dos soluciones reales: rutas basadas en la ruta de acceso, con segmento de idioma, o resolver el idioma en el servidor en cada página. La primera es la recomendada. Para un proyecto nuevo empezamos directamente con rutas basadas en la ruta de acceso; para uno existente, es un trabajo, no una configuración.

¿Qué pasa con las direcciones antiguas cuando rehacéis un sitio?

Se inventarían y cada una recibe una decisión: se queda, se redirige permanentemente o desaparece. En la limpieza de este sitio resultaron 43 redirecciones en la configuración. Todavía hay 11 páginas que redirigen desde dentro de la aplicación: funcionan, pero construyen la página antes de enviar la respuesta de redirección, lo cual es un desperdicio; están en la lista para moverlas a la configuración. Te digo esto para que sepas qué tipo de lista recibes en la entrega.

¿Cómo sé que el formulario realmente entrega?

Se lo preguntas a él: `GET /api/health/contact` responde 200 si un lead puede llegar ahora a una persona y 503 si no, verificando por separado que el token del canal de notificación es válido y que el registro de solicitudes se puede escribir. La respuesta contiene solo valores lógicos, nunca el token. Existe porque precisamente aquí se rompió una vez: el token revocado, la ruta devolviendo 500, solicitudes perdidas sin rastro. Ahora la solicitud se escribe en el registro antes de intentar la entrega.

¿Qué no hacéis?

No prometemos posiciones en búsqueda, porcentajes de conversión ni puntuaciones de rendimiento que no hayamos medido en tu proyecto. No entregamos un sitio sin lista de direcciones antiguas y sin procedimiento de retorno. No asumimos plataformas de terceros a las que no tenemos acceso. Y no presentamos como listo algo que tiene un límite conocido — si tengo un límite, lo encuentras escrito en el repositorio antes de encontrarlo tú en producción.

En qué se basan las afirmaciones anteriores (15 fuentes)
  1. La producción sirve páginas prerenderizadas desde caché: `x-nextjs-prerender: 1`, `x-nextjs-cache: HIT`, `cache-control: s-maxage=31536000`, `x-nextjs-stale-time: 300`https://www.megapromoting.com/servicii · 2026-09-06
  2. Cabeceras de seguridad en la respuesta real: HSTS `max-age=63072000; includeSubDomains; preload`, `nosniff`, `SAMEORIGIN`, `strict-origin-when-cross-origin`, política de permisos con `microphone=(self)`; más una política de seguridad de contenido completa servida por nginx y AUSENTE de `next.config.ts`https://www.megapromoting.com/servicii · 2026-09-06

13 de ellas son código y archivos de nuestros repositorios. No publicamos su nombre ni la línea: juntos, en una sola página, describirían con demasiada precisión cómo están construidos sistemas que no son solo nuestros. Los repasamos contigo, en el repositorio, a petición — la verificación sigue siendo posible, solo que se hace en una conversación.

¿Qué te gustaría que funcionara mejor?

Cuéntanos tu proceso. Juntos decidimos qué merece la pena construir, qué podemos conectar y cómo verificamos el resultado.

Vamos a hablar