── The Boomer Dev Docs ← Volver a la app

MEMORIA FUNCIONAL — ImageOptim

Producto: ImageOptim — Compresión y optimización inteligente de imágenes URL live: https://imageoptim.theboomer.dev (canonical: https://imageoptim.app/) Stack: React + Vite + React Router (frontend), FastAPI (backend), Clerk (auth), Stripe (billing), react-helmet-async (SEO), i18n propio ES/EN Fuente de verdad: code/frontend/src/App.tsx (44 líneas, router shell), pages/Landing.tsx, pages/ToolPage.tsx (613 líneas), i18n.ts, components/ Fecha de documentación: 2026-08-05


1. Introducción

Propósito

ImageOptim es una herramienta web de compresión de imágenes: el usuario arrastra/sube una imagen (JPEG, PNG, WebP, AVIF — hasta 20MB), ajusta calidad, formato de salida, metadatos y dimensiones máximas, y el backend (POST /api/v1/optimize) devuelve la imagen optimizada con comparación visual antes/después, estadísticas de ahorro y descarga directa.

Público objetivo

Nota de arquitectura

App con dos rutas: / (Landing orientada a SEO, con Helmet + JSON-LD) y /app (ToolPage, la herramienta con vista interna Optimizar/Facturación). Cualquier otra ruta redirige a /. El ToolPage funciona sin sesión (modo demo/dev): Clerk se importa condicionalmente y main.tsx envuelve con un AppShell fallback si falta VITE_CLERK_PUBLISHABLE_KEY. Toda la UI es bilingüe ES/EN vía función t(lang, key) con mapas en i18n.ts.


2. Tipos de usuario (roles)

Rol Identificación Capacidades
Visitante Sin sesión (o app sin Clerk key) Ver Landing completa (SEO). Usar el ToolPage en /app sin límite duro local (contador diario anon_optimizations); tras la primera optimización del día aparece el UpgradeDialog.
Usuario registrado (Free) Sesión Clerk activa Quota diaria (3/día por defecto del QuotaBadge), badge de uso, acceso a la vista Facturación completa, sin bloqueos. (La Landing publicita 50 optimizaciones/día gratis — ver Reglas de negocio, discrepancia documentada.)
Pro Suscripción Stripe (plan pro, €12/mes según Landing) 1.000 optimizaciones/día, hasta 50MB por imagen, AVIF + todos los formatos, control de metadatos, resize/crop, API (1K req/día).
Business Suscripción Stripe (plan business, €39/mes) 10.000 optimizaciones/día, hasta 100MB, batch processing, API (10K req/día), webhooks, soporte prioritario.

3. Funcionalidades

F3.1 Landing page (SEO) /

Descripción: Página pública de marketing con SEO completo (Helmet: title, meta description, OG, Twitter cards, canonical, hreflang, JSON-LD SoftwareApplication con precios 0–39 EUR y rating 4.8/127).

Flujo: 1. Nav fija (backdrop-blur): logo 🖼️ ImageOptim, enlaces ancla Features/Pricing/Testimonials, botón de idioma EN/ES, CTA "Empezar a Optimizar" → /app. 2. Hero (min-h-screen, fondo con grid + glow): badge "10.000+ imágenes optimizadas", H1 "Comprime imágenes sin perder calidad" (highlight con gradiente), subtítulo, CTAs "Empezar Gratis" → /app y "Ver Funcionalidades" → #features. Barra de stats: -73% compresión media, 1.2s procesamiento medio, 4.8★ valoración + botón "Pruébalo ahora". 3. Features (6 cards): 🎯 Compresión Inteligente, 🔄 Conversión de Formato, 📏 Redimensionar y Recortar, 🧹 Eliminar Metadatos, 📦 Procesamiento por Lotes, 🔌 Acceso API. 4. Pricing (3 cards, hardcodeadas): Free €0/mo (50 optimizaciones/día, hasta 5MB, JPEG/PNG/WebP, compresión básica → "Comenzar"), Pro €12/mo badge "Más popular" (1.000/día, 50MB, AVIF + todos, control metadatos, resize/crop, API 1K → "Prueba Gratuita"), Business €39/mo (10.000/día, 100MB, batch, API 10K, webhooks, soporte prioritario → "Comenzar"). Nota anual: "Planes anuales: 34% descuento — Pro a €95/año, Business a €310/año". 5. Testimonials (3 cards con estrellas ★★★★★/★★★★½, cita, avatar con iniciales, autor y rol). 6. CTA final: "¿Listo para imágenes más rápidas y ligeras?" → "Empezar Gratis" → /app. 7. Footer: copyright, Privacidad, Términos.

Validaciones: Ninguna (página estática). El cambio de idioma persiste vía onSetLang (localStorage lang, default es).

F3.2 Subida de imagen (dropzone) — ToolPage /app

Descripción: Zona de arrastre/clic para seleccionar la imagen.

Flujo: 1. Sin archivo: dropzone con borde punteado, icono Upload, texto "Arrastra una imagen aquí o haz clic para subir", hint "Soporta JPEG, PNG, WebP, AVIF — hasta 20MB". 2. Click → abre el file picker oculto (accept="image/*"). 3. Drag & drop: onDragOver activa estado visual (borde primario + fondo); onDrop captura dataTransfer.files[0]. 4. Al seleccionar: se muestra la card del archivo con nombre, tamaño formateado (B/KB/MB/GB), botón X para limpiar, y las opciones de optimización. Se genera preview local con URL.createObjectURL.

Validaciones: - Tipo: si !file.type.startsWith('image/') → error "Please select an image file". - Tamaño: si file.size > 20MB (20 * 1024 * 1024) → error "File too large. Max size: 20MB". - El error se muestra en banner rojo en el panel derecho; se limpia al seleccionar otro archivo válido.

F3.3 Opciones de optimización

Descripción: Controles del panel izquierdo (solo visibles con archivo seleccionado).

F3.4 Optimizar imagen

Descripción: Envía la imagen y opciones al backend.

Flujo: 1. Pulsar "Optimizar Imagen" (deshabilitado mientras loading; muestra "Optimizando..." con spinner). 2. POST /api/v1/optimize con FormData: file, quality, output_format, strip_metadata, max_width?, max_height?. 3. Si hay sesión: header Authorization: Bearer <token Clerk> + guarda token en localStorage.clerk_token. 4. Respuesta OptimizeResult: {id, original_filename, original_size, optimized_size, compression_ratio, format, width, height, download_url, timestamp}. 5. Tras éxito: anónimo → incrementa anon_optimizations (localStorage, por día) y muestra UpgradeDialog si count > 0; logueado → incrementa usage_log. 6. Errores: banner rojo con errData.detail || 'Error <status>'.

F3.5 Comparación antes/después

Descripción: Panel derecho con comparación visual tras optimizar.

Flujo: 1. Card "Antes / Después" (grid 2 columnas divididas): original (preview local, etiqueta "Original") vs optimizado (desde result.download_url, etiqueta "Optimizado" resaltada en primario). 2. Ambos sobre fondo de damero oscuro (oklch(0.2 0.01 260/0.5)).

F3.6 Estadísticas de ahorro

Descripción: Grid de 4 métricas: Tamaño original (formatBytes(original_size)), Tamaño optimizado (verde), Ahorrado (-{round((1-compression_ratio)*100)}%, primario), Dimensiones (width x height).

F3.7 Descargar optimizada

Flujo: 1. Botón "Descargar (.webp)" → crea <a href=download_url download="optimized.<format>"> y dispara click. 2. Botón "Optimizar Otra" → limpia archivo/preview/resultado y vuelve a la dropzone.

F3.8 Autenticación Clerk (modal)

Descripción: Igual patrón que CaptionAI: SignInButton mode="modal" en header (texto "Iniciar sesión"); tras login: QuotaBadge + pill "Gratis" + UserButton (afterSignOutUrl="/"). useClerkToken() sincroniza el JWT a localStorage.

F3.9 QuotaBadge

Descripción: Badge usados/límite para logueados (default free 3/día; límite real del plan vía GET /api/v1/billing/pricing-plans + summary). Click → vista Facturación si plan free. Uso desde localStorage.usage_log.

F3.10 UpgradeDialog

Descripción: Modal para anónimos tras la primera optimización del día: "Desbloquea mas optimizaciones" / "Crea una cuenta gratis y optimiza hasta 3 imagenes al dia!" + botón "Iniciar sesion con Google" (icono 🖼️, X para cerrar, backdrop clicable).

F3.11 Facturación (vista interna)

Descripción: Misma estructura que CaptionAI/HookGenerator: tarjeta "Tu Plan", PlanCards (con límites daily_captions, max_characters, languages, has_api, ai_model), paquetes de créditos (€, "Comprar" → buy-credits), historial de facturas (nº, fecha, importe, estado coloreado, Ver → hostedUrl), botón "Gestionar facturación" (Customer Portal). Sin token Clerk → solo planes con botones "Inicia sesión" + prompt de login. Back button "Volver".

F3.12 Selector de tema e idioma

Descripción: En el header del ToolPage: 3 botones de tema (Moon/Sun/Monitor, persistidos en localStorage.theme, default dark; system sigue a prefers-color-scheme) y select EN/ES (persistido en localStorage.lang). En la Landing solo el selector de idioma (botón circular).

F3.13 VersionBadge

Descripción: Badge de versión global renderizado por App.tsx en todas las rutas.


4. Pantallas (wireframes textuales)

P4.1 Landing /

┌─ NAV fija ─────────────────────────────────────────────────┐
│ 🖼️ ImageOptim | Features Pricing Testimonials | [ES] [Empezar a Optimizar] │
├─ HERO (min-h-screen, grid de fondo) ───────────────────────┤
│  ✨ 10.000+ imágenes optimizadas                           │
│  Comprime imágenes sin perder CALIDAD (gradiente)          │
│  Arrastra, suelta y optimiza. AVIF, WebP, JPEG, PNG…       │
│  [Empezar Gratis →]  [Ver Funcionalidades]                 │
│  ┌─ stats bar ────────────────────────────────┐            │
│  │ -73% | 1.2s | 4.8★        [Pruébalo ahora] │            │
│  └────────────────────────────────────────────┘            │
├─ FEATURES (6 cards) ───────────────────────────────────────┤
│  🎯 Compresión Inteligente  🔄 Conversión de Formato        │
│  📏 Redimensionar y Recortar  🧹 Eliminar Metadatos         │
│  📦 Procesamiento por Lotes  🔌 Acceso API                 │
├─ PRICING (3 cards) ────────────────────────────────────────┤
│  [Gratis €0] [Pro €12 ★Más popular] [Business €39]         │
│  …planes anuales: 34% descuento…                           │
├─ TESTIMONIALS (3 cards con ★) ─────────────────────────────┤
├─ CTA: ¿Listo para imágenes más rápidas y ligeras?          │
│  [Empezar Gratis →] [Más Información]                      │
├─ FOOTER: © 2026 ImageOptim | Privacidad | Términos         │
└────────────────────────────────────────────────────────────┘

P4.2 ToolPage /app — vista Optimizar (grid 3 col: izq 1 / der 2)

┌─ HEADER ────────────────────────────────────────────────────┐
│ 🖼️ ImageOptim | Optimizar | Facturación                     │
│ [QuotaBadge] [Gratis] [avatar] [🌙☀️🖥] [EN|ES] | [Iniciar sesión] │
│ MOBILE: tabs Optimizar | Facturación                        │
├─────────────────────────────────────────────────────────────┤
│ PANEL IZQ (col-1)          │ PANEL DER (col-2)              │
│ ┌────────────────────────┐ │ ┌───────────────────────────┐  │
│ │ SIN ARCHIVO:           │ │ │ SIN ARCHIVO (vacío):      │  │
│ │ ╔════════════════════╗ │ │ │  [🖼 icono]               │  │
│ │ ║  [⬆ icono]         ║ │ │ │  Ningún archivo seleccion.│  │
│ │ ║ Arrastra una imagen ║ │ │ │  Sube una imagen para    │  │
│ │ ║ aquí o haz clic     ║ │ │ │  ver opciones de compresión│ │
│ │ ║ (dashed border)     ║ │ │ └───────────────────────────┘  │
│ │ ╚════════════════════╝ │ │ [banner error rojo si error]   │
│ │ CON ARCHIVO:           │ │ CON ARCHIVO (preview):         │
│ │ [🖼 nombre.jpg  12MB X]│ │ ┌─ ORIGINAL ────────────────┐  │
│ │ Calidad: 80            │ │ │ [preview imagen local]     │  │
│ │ [slider 1───100]       │ │ └───────────────────────────┘  │
│ │ Formato de salida      │ │ CON RESULTADO:                 │
│ │ [WebP][JPEG][PNG][AVIF]│ │ ┌─ ANTES / DESPUÉS ─────────┐  │
│ │ ☑ Eliminar metadatos   │ │ │ ORIGINAL │ OPTIMIZADO     │  │
│ │ Ancho máx [Auto]       │ │ │ [img]    │ [img]          │  │
│ │ Alto máx  [Auto]       │ │ └───────────────────────────┘  │
│ │ [🛠 Optimizar Imagen]  │ │ ┌─ stats ───────────────────┐  │
│ │  (u "Optimizando...")  │ │ │ T.orig | T.optim | Ahorro │  │
│ └────────────────────────┘ │ │ 12MB   | 3.2MB  | -73%    │  │
│                            │ │ Dimensiones: 1920x1080    │  │
│                            │ └───────────────────────────┘  │
│                            │ [⬇ Descargar (.webp)] [🔄 Optimizar Otra] │
└────────────────────────────┴─────────────────────────────────┘
│ [UpgradeDialog] si anónimo tras 1ª optimización del día      │

P4.3 ToolPage /app — vista Facturación

[← Volver]
Facturación — Gestiona tu suscripción y facturación   [Gestionar facturación ↗]
┌─ TU PLAN ───────────────────────────────┐
│ Suscrito a: Pro [Activo🟢]              │
│ Fecha de renovación: …                  │
│ 12.00 EUR/month                         │
└─────────────────────────────────────────┘
┌─ PLANES DE PRECIOS ─────────────────────┐
│ [PlanCard Free] [Pro] [Enterprise]      │
└─────────────────────────────────────────┘
┌─ PAQUETES DE CRÉDITOS ──────────────────┐
│ [1000 créditos €X  Comprar] …            │
└─────────────────────────────────────────┘
┌─ HISTORIAL DE FACTURAS ─────────────────┐
│ Nº | Fecha | Importe | Estado | Ver      │
└─────────────────────────────────────────┘

P4.4 Modal UpgradeDialog

┌─ overlay ───────────────────────────────┐
│ ┌────────────────────────────────────┐  │
│ │ [🖼️]                       [X]     │  │
│ │ Desbloquea mas optimizaciones      │  │
│ │ Crea una cuenta gratis y optimiza  │  │
│ │ hasta 3 imagenes al dia!           │  │
│ │ [G Iniciar sesion con Google]      │  │
│ └────────────────────────────────────┘  │
└─────────────────────────────────────────┘

5. Flujos de trabajo

Flujo A: Alta y onboarding

  1. Visitante llega a / (Landing SEO) o directo a /app.
  2. Pulsa "Empezar Gratis" → /app (no requiere registro para probar).
  3. Usa la herramienta como anónimo; tras la primera optimización del día aparece el UpgradeDialog.
  4. "Iniciar sesion con Google" → modal Clerk → cuenta creada; el header pasa a mostrar QuotaBadge 0/3, pill "Gratis" y avatar.
  5. (Opcional) Facturación → suscribirse a un plan de pago.

Flujo B: Optimización completa

  1. En /app, arrastrar o hacer clic para subir una imagen (≤20MB, tipo image/*).
  2. Ajustar opciones: calidad (slider), formato de salida, strip de metadatos, ancho/alto máximos.
  3. Pulsar "Optimizar Imagen" → estado "Optimizando..." → POST /api/v1/optimize.
  4. Ver comparación antes/después + estadísticas (tamaños, % ahorrado, dimensiones).
  5. "Descargar (.formato)" → descarga local optimized.<format>, o "Optimizar Otra" para reiniciar.

Flujo C: Errores y validaciones

  1. Archivo no-imagen → banner "Please select an image file".
  2. Archivo >20MB → banner "File too large. Max size: 20MB".
  3. Fallo de API → banner con detail del backend.
  4. En todos los casos la dropzone/card del archivo permanece y se puede reintentar.

Flujo D: Billing

  1. Tab "Facturación" (o clic en QuotaBadge si free).
  2. Sin login: solo planes (botones "Inicia sesión") + prompt.
  3. Con login: ver plan actual, suscribirse (Stripe Checkout), gestionar (Customer Portal), comprar créditos, ver facturas.

Flujo E: Upgrade y límites

  1. Plan Free: el badge muestra usados/3; al agotarse, el backend rechaza con error (frontend muestra banner).
  2. Upgrade a Pro/Business vía Facturación → el badge usa limits.daily_captions del plan (/api/v1/billing/pricing-plans).
  3. Enterprise (si aplica): acceso API según limits.has_api (la Landing menciona API en Pro/Business; la UI de billing lo refleja en PlanCard).

6. Reglas de negocio

Regla Detalle
Tamaño máximo de imagen 20MB en frontend (validación local file.size > 20 * 1024 * 1024). La Landing anuncia límites por plan (5MB free, 50MB Pro, 100MB Business) — el límite real de backend prevalece.
Tipos aceptados Solo image/* (validación por MIME type en cliente).
Quota anónima Contador diario anon_optimizations en localStorage (fecha + count); tras la 1ª optimización del día se muestra el UpgradeDialog en cada generación posterior.
Quota logueados localStorage.usage_log alimenta el QuotaBadge; límite del plan desde Stripe (pricing-plans.limits.daily_captions), default free 3/día. Discrepancia documentada: la Landing publicita "50 optimizaciones/día" para el plan Free y "hasta 5MB por imagen", mientras que el QuotaBadge/UpgradeDialog del frontend usan 3/día. El límite autoritativo lo impone el backend por plan.
Formato de salida WebP (default), JPEG, PNG, AVIF.
Calidad Slider 1–100, default 80.
Metadatos Checkbox "Eliminar metadatos" default ON (envía strip_metadata=true).
Redimensionado Opcional vía max_width/max_height (solo se envían si tienen valor; vacío = Auto).
Suscripción GET /api/v1/billing/summary determina plan/estado; active verde, resto ámbar; aviso de cancelación a fin de período si cancelAtPeriodEnd.
Planes (Landing) Hardcodeados: Free €0 (50/día, 5MB, JPEG/PNG/WebP, compresión básica), Pro €12 (1.000/día, 50MB, AVIF, metadatos, resize/crop, API 1K), Business €39 (10.000/día, 100MB, batch, API 10K, webhooks, soporte prioritario). Anual: Pro €95/año, Business €310/año (-34%). Los precios del billing real provienen de Stripe.
SEO Landing con canonical https://imageoptim.app/, hreflang EN/ES/x-default, JSON-LD SoftwareApplication (precio 0–39 EUR, rating 4.8/127). La ruta /app tiene noindex, nofollow.
Auth Clerk; la app funciona en modo demo sin publishable key (ClerkProvider condicional en main.tsx). Token persistido en localStorage.clerk_token.
Tema/Idioma Tema: dark default (light/system disponibles), persistido localStorage.theme. Idioma: es default, persistido localStorage.lang, select EN/ES en header de la herramienta y botón en la Landing.

Endpoints consumidos por el frontend