Saltar al contenido

Disponible para proyectos freelance: páginas web y apps a medida

Desarrollador full-stack. Convierto ideas en páginas y aplicaciones web rápidas, fáciles de usar y listas para publicar.

Retrato de Jeremy Orellana con lentes y chaqueta oscura

Jeremy Orellana

Proyectos destacados

Proyectos publicados y en uso. En cada uno cuento qué problemas tuve y cómo los resolví.

Agenda de Vikoma en español, en una computadora con una columna por profesional y en un celular como lista de citas.

Vikoma

Sistema para negocios de Ecuador que trabajan con citas, como salones de belleza, peluquerías, estudios de uñas, spas y barberías. Reemplaza el cuaderno, los chats y el cuadre de caja a mano. Ya está en uso: la primera barbería de prueba se registró y configuró su negocio.

Cada negocio tiene su propio espacio, con su equipo, servicios y clientes. El dueño entra con su cuenta de Google y deja todo listo en unos 5 minutos, según lo medido con la barbería de prueba. Incluye agenda sin cruces, inventario que baja solo con cada venta, caja y reportes de ingresos, confirmaciones por WhatsApp, lista de espera, fotos de referencia con permiso del cliente según la ley de protección de datos de Ecuador y permisos distintos para el dueño y el equipo. La agenda se puede ver aunque se caiga el internet. Lo hice solo: el dinero se guarda en centavos para evitar errores de redondeo, las horas en UTC, y tiene 2.679 pruebas automáticas que corren en unos 16 segundos y cubren cerca del 81 % del código de las reglas de negocio y del acceso a datos.

Problemas

  1. 01Los datos de un negocio podían quedar enlazados con los de otro, porque la base de datos tursodb no revisaba las relaciones entre tablas y no avisaba.

Cómo los resolví

  1. 01Lo comprobé con una prueba que debía fallar y pasé producción a libSQL. Todos los datos pasan por un solo punto de acceso, con pruebas que confirman que nunca se mezclan. La app no arranca si la base de datos no revisa esas relaciones.
Ver 4 problemas y soluciones másOcultar los problemas y soluciones extra

Problemas

  1. 02Dos clientes no podían reservar la misma hora, aunque lo intentaran en el mismo instante.
  2. 03Dos cobros al mismo tiempo podían vender productos sin stock o repetir un número de factura.
  3. 04El inicio de sesión (OAuth) daba por bueno cualquier valor. Una función leía el texto en el formato equivocado (hexadecimal en vez de base64url), obtenía datos vacíos y todo coincidía.
  4. 05Una falla de WhatsApp no debía impedir que se guardara la cita.

Cómo los resolví

  1. 02Cada reserva vuelve a revisar el horario en el momento de guardarse, no solo en la pantalla.
  2. 03El número de factura se asigna en un solo paso dentro de la base de datos. Una prueba con 25 cobros al mismo tiempo exige 25 números distintos. El stock solo se descuenta si alcanza, y si la base de datos está ocupada, se vuelve a intentar.
  3. 04Lo detectó una prueba de seguridad que intentaba entrar con datos falsos. Ahora se compara un hash de ambos valores, y la comparación siempre tarda lo mismo para no dar pistas.
  4. 05El mensaje se guarda en una cola junto con la cita y se envía después, con reintentos. Si el cliente no dio su permiso, no se envía.

Hecho con

  • Next.js 16
  • TypeScript
  • Turso
  • Drizzle
  • WhatsApp Cloud API
  • Cloudflare R2
  • Vitest
Tres pantallas de Tickets App: el visor de turnos de la sala, la selección de escritorio y el kiosco de tickets.

Tickets App

Kioscos, escritorios de atención y pantallas que muestran los mismos turnos al instante.

Un sistema de turnos para lugares de atención al público, con turnos normales y preferenciales. La interfaz está hecha en React 19 y el servidor en Bun con TypeScript, dentro de un contenedor Docker.

Problemas

  1. 01Kioscos, escritorios y pantallas debían mostrar la misma fila de turnos al mismo tiempo, sin que cada parte manejara su propia conexión.

Cómo los resolví

  1. 01El servidor envía el estado de la fila a todos los equipos por WebSockets y revisa con Zod cada mensaje que recibe. Un hook propio (useSocketTicket) maneja la conexión, y un Context de React comparte el estado con toda la app.
Ver 1 problema y solución másOcultar los problemas y soluciones extra

Problemas

  1. 02Kioscos y pantallas debían reconectarse solos si se caía el internet.

Cómo los resolví

  1. 02Se reconectan solos y esperan un poco más entre cada intento.

Hecho con

  • React 19
  • Bun
  • WebSockets
  • TypeScript
  • Zod
Tres pantallas de Luxe Estate: la búsqueda de propiedades, el detalle de una propiedad con mapa y la tabla de administración.

Luxe Estate

Buscador de propiedades con filtros que se actualizan junto con el mapa, en varios idiomas y con páginas generadas en el servidor.

Aplicación completa hecha con Server Components y Server Actions de Next.js. Supabase maneja los datos y el inicio de sesión, y Leaflet el mapa.

Problemas

  1. 01El mapa y los filtros debían mostrar siempre los mismos resultados.

Cómo los resolví

  1. 01Los filtros se aplican con una sola consulta en el servidor (Supabase PostgREST), así el mapa y la lista siempre coinciden.
Ver 2 problemas y soluciones másOcultar los problemas y soluciones extra

Problemas

  1. 02Guardar favoritos e iniciar sesión se sentía lento si cada clic esperaba la respuesta del servidor.
  2. 03Las páginas de propiedades debían cargar rápido y aparecer en buscadores como Google.

Cómo los resolví

  1. 02Las Server Actions revisan bien los datos, y la pantalla muestra el cambio al instante sin esperar la respuesta del servidor.
  2. 03Las páginas se generan primero en el servidor, llegan con menos JavaScript y los buscadores pueden leer su contenido.

Hecho con

  • Next.js 16
  • Supabase
  • Tailwind CSS 4
  • Leaflet
  • i18n
Tres pantallas de Assembly: Endgame: el tablero, una victoria con confeti y el final de una partida.

Assembly: Endgame

Juego de adivinar palabras que también se puede jugar con lector de pantalla.

Hecho en React 19. Cada error borra un lenguaje de programación del tablero, y todo el juego se puede jugar con el teclado y con lector de pantalla.

Problemas

  1. 01El estado del juego (lenguajes que quedan, intentos, si ganaste o perdiste) cambia con cada tecla y debía estar siempre correcto.

Cómo los resolví

  1. 01El juego está dividido en componentes pequeños (Status, LanguageChips, Keyboard) y cada uno muestra una sola parte del estado.
Ver 2 problemas y soluciones másOcultar los problemas y soluciones extra

Problemas

  1. 02Quienes usan lector de pantalla necesitaban escuchar cada intento y el resultado final sin ver el tablero.
  2. 03El teclado en pantalla debía coincidir siempre con las letras ya usadas.

Cómo los resolví

  1. 02Una región aria-live le avisa al lector de pantalla cada intento y el resultado final.
  2. 03El teclado se dibuja a partir del mismo estado que el resto del juego, así que siempre coincide con las letras ya usadas.

Hecho con

  • React 19
  • CSS Grid
  • ARIA
  • Hooks

Sobre mí

Ubicación
Ecuador, trabajo remoto
Especialidad
Aplicaciones web completas
Disponible para
Páginas web y apps a medida, freelance

Soy Jeremy, desarrollador full-stack en Ecuador, y trabajo de forma remota. Acompaño tu proyecto web desde la idea hasta que está publicado y funcionando.

Me encargo de todo: cómo se guardan los datos, las reglas de tu negocio y lo que ven tus clientes en pantalla. Hablas con una sola persona que entiende tu negocio, responde rápido y te entrega un producto probado, fácil de usar y listo para publicar.

  • Sistemas para negocios

    Aplicaciones en línea que usan varios negocios a la vez, cada uno con sus datos separados, roles de dueño y empleado, facturación y reportes de caja, con pruebas automáticas.

  • Sistemas en tiempo real

    Kioscos, escritorios de atención y pantallas que muestran la misma información al instante y se reconectan solos si se cae el internet.

  • Interfaces para todos

    Pantallas en React y Next.js que se pueden usar solo con el teclado o con lector de pantalla, en varios idiomas y con mapas interactivos.

  • Integraciones

    Mensajes por WhatsApp, inicio de sesión con Google, bases de datos con Supabase y archivos guardados en Cloudflare R2.

Tecnologías

Las herramientas que uso en mis proyectos.

Interfaz
  • React 19
  • Next.js 16
  • Astro
  • TypeScript
  • Tailwind CSS 4
  • Radix UI
Servidor y datos
  • Node.js
  • Bun
  • PostgreSQL
  • Supabase
  • Turso (libSQL)
  • Drizzle ORM
  • WebSockets
Herramientas y publicación
  • Docker
  • Vitest
  • Playwright
  • Zod
  • Biome
  • Cloudflare R2

Cómo trabajo

Fácil de modificar

Separo las reglas del negocio del resto del código, para que cualquier persona pueda cambiarlas sin miedo a dañar algo.

Que cargue rápido

Las páginas se arman primero en el servidor y llegan más livianas al navegador, como en Luxe Estate.

Preparado para los errores

Desde la primera versión incluyo reconexión, validación de datos y mensajes de error claros. Vikoma no arranca si la base de datos no revisa que los datos relacionados existan.

Pruebas automáticas

Vikoma usa ESLint, TypeScript estricto y pruebas con Vitest. Este sitio usa Biome, TypeScript estricto y pruebas en el navegador con Playwright.

  • Biome
  • TypeScript strict
  • Vitest
  • Playwright

Trabajemos juntos

Cuéntame qué proyecto o puesto tienes en mente.

Correo

jejorm8@gmail.com