Proyectos

01 / 05Caso de estudio

OMSTA — ERP y app móvil para una agencia de viajes

ERP en producción para una agencia de viajes dominicana —reservas, cobros, contabilidad de doble partida, DGII, nómina y sucursales— con una app móvil nativa para el equipo.

Panel de OMSTA con reservas del mes, cobrado, comisión, saldo por cobrar y alertas operativas, sobre datos sintéticosInicio de la app móvil con pagos vencidos, próximos check-in, saldo por cobrar, cobrado y comisión del mes
Mi papel
Único desarrollador; arquitectura, backend, web, app móvil, despliegue y mantenimiento
Stack
Python · Django · Django REST Framework · PostgreSQL · Redis · Django Q2 · React Native · Expo · TypeScript · Railway
Estado
En producción diaria · app móvil en desarrollo

Alcance

  • 19apps Django en un monolito modular
  • 150modelos de dominio
  • 54pantallas en la app móvil

El reto

Una agencia vende ocho tipos de producto, cobra en pesos y dólares y declara a la DGII. Venta, dinero y contabilidad necesitaban un solo sistema, sin teclear dos veces el mismo dato.

Lo que construí
Diseñé y construí en solitario un monolito Django de 19 apps —de la reserva al reporte fiscal— y una app en React Native y Expo que usa los mismos servicios que la web.
Decisión técnica clave
Un hecho económico se captura una sola vez y se propaga: servicios atómicos e idempotentes, invariantes en el modelo y PostgreSQL como única fuente de verdad.

Decisiones de diseño

  1. Ficha de una reserva de hotel con 70 % cobrado, escalera de estados y saldo pendiente
    Problema
    Una reserva mezcla estado de venta, cobros y saldo, y hay que leerla de un vistazo.
    Decisión
    Escalera de estados, porcentaje cobrado y saldo en la cabecera, con venta y cobro separados.
  2. Formulario de la app para registrar un cobro que queda por verificar hasta que contabilidad lo aplica
    Problema
    Fuera de la oficina, un vendedor necesita cobrar sin abrir la web y sin saltarse a contabilidad.
    Decisión
    El cobro desde el teléfono usa el mismo servicio que la web y queda «por verificar» hasta que contabilidad lo aplica.
  3. Pago contabilizado que no se edita directamente y ofrece comprobantes, corrección guiada o reembolso
    Problema
    Editar un pago ya contabilizado descuadraría banco, asientos y saldos.
    Decisión
    El pago contabilizado no se edita; se gestionan comprobantes, se corrige de forma guiada o se reembolsa.
  4. Detalle de un asiento que explica en lenguaje llano su débito, su crédito y su origen
    Problema
    Para quien vende, la contabilidad es una caja negra.
    Decisión
    Cada asiento explica en lenguaje llano qué registra, y la reserva enseña todos sus asientos.
  5. Pestaña de pagos de una reserva con la agenda de pago al suplidor programada antes de la entrada
    Problema
    Pagar tarde al hotel pone en riesgo la reserva del cliente.
    Decisión
    La fecha de pago al proveedor se calcula sola desde la entrada y se agenda por vencimiento.
  6. Salud contable de solo lectura, sin bloqueos de cierre y con nueve de nueve identidades cuadradas
    Problema
    Un error contable descubierto al cerrar el mes llega tarde y sale caro.
    Decisión
    Salud contable de solo lectura y un cierre que se bloquea si alguna identidad no cuadra.
  7. Formulario de reserva de vuelo con navegación rápida por secciones y resumen de precio en vivo
    Problema
    Seis tipos de producto con datos distintos acaban en seis formularios que no se parecen.
    Decisión
    Un mismo patrón de alta para todos, con navegación por secciones y el precio resumido en vivo.
  8. Selector de seis tipos de producto y un borrador guardado para continuar
    Problema
    Dar de alta una reserva en el teléfono es largo, y una llamada puede interrumpirla a medias.
    Decisión
    Un asistente por pasos que guarda cada borrador cifrado en el teléfono; la reserva se retoma donde se dejó.

Sistema

Elige un módulo: se enciende su ruta.Elige un módulo: debajo, su decisión.

Arquitectura22 módulos · 31 conexiones

HTML renderizado en el servidor, sin SPA ni build step, para que la lógica crítica y los permisos vivan sólo en el backend.

Django Templates · Bootstrap 5.3 · jQuery 3.7 · Select2 · HTMX 2.0 · Chart.js 4.4

Un segundo cliente que no calcula saldos ni estados: pinta lo que describe el servidor.

React Native 0.86 · Expo SDK 57 · Expo Router · TypeScript 6.0 · TanStack Query 5 · react-native-mmkv · Expo SecureStore

App Django propia con JWT ligado al dispositivo y un contrato OpenAPI que genera los tipos TypeScript de la app.

Django REST Framework 3.16 · Simple JWT 5.5 · drf-spectacular 0.30 · openapi-typescript 7.13

Acceso cerrado por defecto: login obligatorio, roles efectivos (rol más módulos) y reglas por prefijo de URL en un middleware.

Django 5.2 · django-user-agents · django-crum

Ocho tipos de producto en un dominio que habla con contabilidad sólo por un contrato neutral, protegido por tests de frontera.

Django 5.2 · django-filter · django-select2 · django-countries

Un único servicio de registro para web y móvil; todo pago nace «por verificar», con clave de idempotencia, y contabilidad lo aplica.

Django 5.2 · Django REST Framework · django-storages

La factura publica un paquete de asientos atómico para que la CxC nunca quede acreedora ni los anticipos sin reclasificar.

Django 5.2 · openpyxl 3.1

Capa contable genérica que no importa contabilidad y bloquea la publicación en períodos cerrados.

Django 5.2 · PostgreSQL

ReportLab 4.4 · XlsxWriter 3.2 · Chart.js 4.4

Snapshot fiscal inmutable al contabilizar; genera el TXT oficial y el XLSX, y la presentación a la DGII queda en manos humanas.

Django 5.2 · openpyxl 3.1

Una cuenta bancaria por moneda y la tasa de cambio congelada en cada pago en pesos o dólares.

Chart.js 4.4 · chartjs-plugin-zoom · openpyxl 3.1

Recibos renderizados en vivo; sólo la factura con NCF es inmutable.

WeasyPrint 65 · ReportLab 4.4 · qrcode 8.0 · bleach 6.3

Única fuente de verdad: todo lo contable, auditable o durable vive aquí.

PostgreSQL · psycopg 3.3

Sólo cola de Django Q2, caché y sesiones; puede perderse sin perder estado de negocio.

Redis · redis-py 6.1 · hiredis

Comprobantes y documentos en almacenamiento privado con URL firmada, porque contienen datos personales y financieros.

django-storages 1.14 · boto3 1.42

Cada push a la rama principal despliega producción y demo tras lint, checks y pytest en GitHub Actions.

GitHub Actions · pytest 8.4 · Ruff · Black · Jest

Gunicorn con hilos, reciclado escalonado de procesos y una sonda /health/ exenta de login y de la redirección HTTPS.

Railway · Railpack · Gunicorn 23 · WhiteNoise 6.12

Builds de desarrollo internas probadas en un teléfono Android real; las tiendas esperan a las cuentas del negocio.

EAS Build · Expo Dev Client · expo-doctor

Django Q2 en lugar de Celery; los trabajos se encolan al confirmar la transacción y son idempotentes.

Django Q2 1.9 · Redis

Django email · SMTP

Consulta por IP cacheada 24 horas (la negativa, una) para no pagar ni esperar la geolocalización en cada petición.

IPinfo API · requests

Se consulta desde el servidor, para ubicar hoteles sin exponer la llave en la app.

Google Places API · Google Maps JavaScript API

Inspector20 decisiones

Cliente

Web Django

HTML renderizado en el servidor, sin SPA ni build step, para que la lógica crítica y los permisos vivan sólo en el backend.

Tecnologías

67 herramientas en 11 áreas. En el sistema, cada módulo dice las suyas.

Lenguajes

  • Python 3.12
  • TypeScript 6.0
  • JavaScript
  • HTML y Django Templates
  • CSS

Backend

  • Django 5.2
  • WhiteNoise 6.12
  • django-filter 25.1
  • django-select2 8.3
  • bleach 6.3

Interfaz web

  • Bootstrap 5.3
  • Bootstrap Icons 1.11
  • jQuery 3.7
  • Select2 4.1
  • HTMX 2.0
  • Chart.js 4.4
  • flatpickr 4.6
  • SweetAlert2 11

App móvil

  • React Native 0.86
  • React 19.2
  • Expo SDK 57
  • Expo Router
  • TanStack Query 5
  • react-native-mmkv 4.3
  • Expo SecureStore
  • Expo Local Authentication
  • Expo Location
  • Expo Image Picker
  • Expo Document Picker

API y contratos

  • Django REST Framework 3.16
  • Simple JWT 5.5
  • drf-spectacular 0.30
  • OpenAPI 3.0
  • openapi-typescript 7.13

Datos y colas

  • PostgreSQL
  • psycopg 3.3
  • Redis
  • Django Q2 1.9
  • django-storages 1.14
  • boto3 1.42

PDF y exportación

  • WeasyPrint 65
  • ReportLab 4.4
  • qrcode 8.0
  • openpyxl 3.1
  • XlsxWriter 3.2

Integraciones

  • Google Places API
  • Google Maps JavaScript API
  • IPinfo
  • Correo SMTP

Infraestructura

  • Railway
  • Railpack
  • Gunicorn 23
  • Almacenamiento S3 privado

Build móvil

  • EAS Build
  • Expo Dev Client
  • Metro

Calidad y CI

  • pytest 8.4
  • pytest-django 4.11
  • coverage 7.16
  • Ruff 0.15
  • Black 23.12
  • pre-commit
  • Jest 29
  • ESLint 9
  • GitHub Actions
  • expo-doctor
  • Playwright 1.61

Resultados verificables

  • En producción y usado a diario por 15 personas, con despliegue automático en Railway desde la rama principal
  • Ciclo completo venta → cobro → factura con NCF → asientos → reportes DGII 606, 607, 608 y 623
  • Contabilidad de doble partida con invariantes en el modelo y en la base de datos
  • App móvil nativa y su API REST, construidas en 16 días sobre el mismo backend
  • Contrato OpenAPI tipado de punta a punta, con CI que falla si app y API se desalinean
  • 3.164 pruebas automatizadas con pytest sobre PostgreSQL e integración continua en GitHub Actions

Recorrido por módulos

61 pantallas en 10 módulos.

Panel y reservas10 pantallas

  • Panel de OMSTA con reservas del mes, cobrado, comisión, saldo por cobrar y alertas operativas, sobre datos sintéticos

    El mes de la agencia de un vistazo, con alertas que llevan a la acción.

  • Ficha de una reserva de hotel con 70 % cobrado, escalera de estados y saldo pendiente

    Una reserva dice cuánto se vendió, cuánto se cobró y cuánto falta.

  • Listado de reservas con cartera, cobrado, por cobrar, comisión y estado de cada venta

    Cada reserva con su estado de venta y de cobro.

  • Pestaña de pagos de una reserva con la agenda de pago al suplidor programada antes de la entrada

    La fecha de pago al hotel se calcula sola desde la entrada.

  • Reserva facturada con su comprobante NCF y los asientos publicados

    La factura con NCF y sus asientos, desde la propia reserva.

  • Historial de una reserva con veinticinco eventos auditados y financieros

    Todo lo que le pasó a la reserva, auditado.

  • Paquete turístico con hotel, traslado y tour, cada componente con su costo

    Paquetes armados por componentes, cada uno con su costo.

  • Seguro de viaje saldado con dos asegurados y su documento de viaje

    También seguros, cruceros, vuelos y otros servicios.

  • Formulario de reserva de vuelo con navegación rápida por secciones y resumen de precio en vivo

    Alta guiada por secciones, con el precio resumido en vivo.

  • Formulario de reserva de crucero con itinerario, pasajeros y resumen en vivo

    El mismo patrón de alta para cada tipo de producto.

App móvil15 pantallas

  • Inicio de la app móvil con pagos vencidos, próximos check-in, saldo por cobrar, cobrado y comisión del mes

    El mes de la agencia, en el bolsillo.

  • Listado de reservas en la app con búsqueda, filtros, montos y estados

    Todas las reservas con su estado de venta y de cobro.

  • Ficha de reserva en la app con saldo pendiente, 70 % cobrado, vencimiento y acciones rápidas

    Saldo, vencimiento y acciones rápidas de una reserva.

  • Pestaña de pagos de una reserva en la app, con recibo, WhatsApp y correo en cada pago

    Cada pago con su recibo, listo para enviar por WhatsApp.

  • Formulario de la app para registrar un cobro que queda por verificar hasta que contabilidad lo aplica

    Cobrar fuera de la oficina; contabilidad lo verifica después.

  • Selector de seis tipos de producto y un borrador guardado para continuar

    Seis productos y borradores que no se pierden.

  • Calendario de rango del asistente con entrada, salida y cuatro noches

    Calendario propio: entrada, salida y noches de un toque.

  • Paso de habitaciones del asistente con titular, acompañante y tarifa por noche

    Habitaciones, huéspedes y tarifa, paso a paso.

  • Paso de dinero del asistente con descuento, comisión, pago inicial y plazos

    Descuento, comisión, pago inicial y plazos en un solo paso.

  • Listado de clientes de la app con personas y empresas y filtros por estado

    Clientes y empresas, con filtros por estado.

  • Ficha de cliente en la app con saldo pendiente y botones de llamada, WhatsApp y correo

    Ficha del cliente: saldo y contacto en un toque.

  • Avisos de la app con pagos registrados y verificados por contabilidad

    Avisos cuando contabilidad verifica un pago.

  • Índice de catálogos de la app con suplidores, hoteles, aerolíneas, aeropuertos, navieras y barcos

    Catálogos de proveedores, vuelos y cruceros.

  • Centro de configuración de la app con usuarios, empresa, sucursales, monedas y retenciones

    La administración, también desde el teléfono.

  • Retenciones de nómina AFP, SFS e ISR que se activan desde la app

    Retenciones de ley configurables desde la app.

Clientes y catálogos3 pantallas

  • CRM con veintiséis clientes y tres empresas, con filtros y exportación

    Clientes y empresas en un mismo CRM.

  • Ficha de empresa con datos fiscales, representante y contacto

    Ficha de empresa con RNC y régimen de facturación.

  • Catálogo de aerolíneas con código IATA, país y uso frecuente

    Catálogos que alimentan el autocompletado de las reservas.

Cobros y pagos6 pantallas

  • Caja y pagos con método, estado y comprobante de cada cobro

    Cada cobro con su método, su estado y su comprobante.

  • Pago contabilizado que no se edita directamente y ofrece comprobantes, corrección guiada o reembolso

    Un pago contabilizado no se edita: se corrige o se reembolsa.

  • Reembolso de un pago con su trazabilidad contable y motivo obligatorio

    Reembolso con reverso contable y motivo obligatorio.

  • Cuentas por cobrar con cartera, comisión y pendiente de cobro

    Cuentas por cobrar derivadas de reservas y pagos.

  • Cuentas por pagar con la agenda de vencidas, de hoy y próximas

    Lo que se debe a proveedores, ordenado por vencimiento.

  • Cuenta por pagar a un proveedor saldada al cien por cien

    Del costo al pago: la cuenta por pagar se salda.

Contabilidad6 pantallas

  • Libro diario con asientos cuadrados y el documento que originó cada uno

    Cada asiento cuadra y sabe qué documento lo generó.

  • Detalle de un asiento que explica en lenguaje llano su débito, su crédito y su origen

    El asiento explica en español qué registra y por qué.

  • Seis asientos de una misma reserva, del cobro a la factura, el costo y el pago al proveedor

    Toda la contabilidad de una venta en una tabla.

  • Salud contable de solo lectura, sin bloqueos de cierre y con nueve de nueve identidades cuadradas

    Un auditor interno: identidades contables que deben cuadrar.

  • Checklist de cierre del período contable con sus verificaciones y advertencias

    Antes de cerrar el mes, el sistema lo revisa todo.

  • Mapa de cuentas del sistema con la cuenta de débito y de crédito de cada operación

    Qué cuenta usa cada operación, y quién la decide.

Fiscal DGII4 pantallas

  • Documento fiscal de un proveedor con NCF, tipo de gasto 606 y pago aplicado

    La factura del proveedor alimenta el 606 de la DGII.

  • Factura con sus tres asientos publicados como un solo paquete contable

    Emitir la factura publica sus asientos como una unidad.

  • Régimen de ITBIS por tipo de servicio con sus cuentas de ingreso y de costo

    ITBIS y cuentas por tipo de servicio, configurables.

  • Rangos de comprobantes NCF autorizados con disponibilidad y vigencia

    Numeración fiscal automática y sin duplicados.

Banco2 pantallas

  • Transacciones bancarias con entradas, salidas y flujo neto en pesos

    Movimientos bancarios generados por cobros y pagos.

  • Conciliación bancaria que exige el asiento antes de conciliar un movimiento

    Conciliación masiva con validaciones seguras.

Nómina4 pantallas

  • Resumen de nómina con gráfico mensual y plantilla por departamento

    Nómina dentro del ERP: empleados, períodos y pagos.

  • Ficha de una empleada con salario, neto estimado, vacaciones y préstamos

    La ficha del empleado con salario, neto y vacaciones.

  • Retenciones legales AFP, SFS e ISR con su base de cálculo

    AFP, SFS e ISR dominicanos, configurables sin código.

  • Mapeo de las cuentas de sueldos, banco y retenciones de la nómina

    Pagar la nómina publica su asiento automáticamente.

Administración8 pantallas

  • Dos sucursales activas con sus empleados y departamentos

    Operación en varias sucursales, con permisos por sucursal.

  • Listado de usuarios con su estado, su rol y sus acciones de acceso

    Usuarios con rol, estado y control de acceso.

  • Evento auditado inmutable que dice quién cambió qué y sobre qué registro

    Cada cambio queda en una bitácora que no se edita.

  • Notificaciones de pagos registrados por reservas y aplicados por contabilidad

    Reservas registra el pago; contabilidad lo verifica.

  • Centro de documentos con siete documentos para el cliente configurables

    Siete documentos para el cliente, configurables.

  • Correos automáticos de confirmación y recordatorios que se activan uno a uno

    Correos al cliente que se encienden uno a uno.

  • Centro de reportes operativos, contables y fiscales

    Reportes operativos, contables y fiscales en un lugar.

  • Centro de tutoriales con setenta y un tutoriales organizados por módulo

    71 tutoriales dentro del sistema, por módulo.

La web en el teléfono3 pantallas

  • Panel de OMSTA en el ancho de un teléfono

    La web también se adapta al teléfono.

  • Ficha de reserva en el ancho de un teléfono con 70 % cobrado

    La ficha de reserva, legible en una pantalla pequeña.

  • CRM en tarjetas en el ancho de un teléfono

    Bajo 768 px las tablas pasan a tarjetas.

8 min de lectura

El caso completo

Contexto

OMSTA es el sistema con el que opera CristegnoViajes SRL, una agencia de viajes de República Dominicana: vende hoteles, vuelos, paquetes, cruceros, seguros y otros servicios, cobra en pesos y en dólares, paga a sus proveedores, lleva su nómina y declara ante la DGII. Trabaja con dos sucursales, Santo Domingo y Santiago, sobre una misma plataforma.

El primer commit es de abril de 2025. Hoy la web está en producción y la usan a diario 15 personas, y desde septiembre de 2026 el equipo tiene además una app móvil propia.

Problema

Una agencia une tres mundos que suelen vivir separados: la venta, el dinero y la contabilidad. Cuando cada uno vive en una herramienta distinta, el mismo dato se teclea varias veces, los saldos no cuadran y nadie puede reconstruir qué pasó con una reserva.

El reto era que una venta se capturase una sola vez y que de ahí salieran, sin volver a escribir nada, el cobro, la factura con NCF, los asientos, la cuenta por pagar al proveedor, el movimiento bancario y los reportes fiscales. Y que el equipo pudiera hacer su parte también fuera de la oficina.

Mi función

Soy el único desarrollador del sistema: modelé el dominio, diseñé la arquitectura, construí el backend, la interfaz web, la API y la app móvil, y me ocupo del despliegue, del mantenimiento y de los incidentes de producción. El repositorio suma más de mil cien commits.

Usuarios y permisos

Cinco roles base —superadministración, administración, contabilidad, reservas y clientes— y, encima, módulos sueltos que amplían lo que ve cada usuario. Un asesor crea reservas y registra cobros; contabilidad los verifica, factura y cierra; administración gestiona usuarios, sucursales y configuración. Los permisos se imponen en el servidor, por prefijo de URL, y nunca dependen de lo que la interfaz esconda.

Restricciones

  • Fiscalidad dominicana: comprobantes NCF por rango autorizado y formatos 606, 607, 608 y 623. El sistema prepara, valida y descarga; la presentación a la DGII la hace una persona.
  • Multimoneda: cada pago conserva la tasa con que se cobró y cada capa cuadra contra su propio total.
  • Invariantes contables: la cuenta por cobrar nunca queda acreedora, un asiento publicado no se reescribe y un período cerrado no admite asientos.
  • Datos sensibles: los comprobantes de pago viven en almacenamiento privado con URL firmada.
  • Un solo desarrollador: la infraestructura tenía que ser pequeña y predecible.

Cómo lo construí

Por dominios y por capas: primero reservas y clientes; después los servicios que mueven dinero; luego el libro mayor y, al final, la reportería fiscal. Las vistas orquestan, los servicios abren la transacción y emiten el asiento, los selectores leen y los invariantes viven en el modelo y en restricciones de la base de datos, porque los comandos de reparación no pasan por formularios.

Las fronteras entre dominios están protegidas por tests: el libro mayor no importa contabilidad, reservas habla con contabilidad a través de un contrato neutral y la superficie pública de los modelos más grandes sólo puede bajar. Cada cambio pasa por lint, formato, comprobaciones de Django, migraciones y pytest en GitHub Actions antes de desplegarse.

Decisiones de arquitectura

  • Monolito modular, no microservicios. Un equipo de una persona y transacciones que cruzan dominios piden un solo proceso con fronteras claras.
  • HTML renderizado en el servidor. Sin SPA ni paso de build: Bootstrap, jQuery y HTMX sobre plantillas de Django, y la lógica sólo en el backend.
  • Django Q2 y no Celery. PostgreSQL es la única fuente de verdad, también para el estado de los trabajos; Redis es cola, caché y sesiones, y puede perderse sin perder negocio.
  • Paquete contable atómico. Emitir una factura publica venta, costo, anticipos y cobros en un solo servicio.
  • Snapshot fiscal inmutable. Lo que se declaró a la DGII no cambia aunque cambien después los datos de origen.
  • La app no calcula. El servidor le envía importes formateados, estados con su etiqueta y hasta la forma de los formularios.

La app móvil

La web usaba sesión y CSRF, y no había una API pensada para un cliente fuera del navegador. Construí una API REST propia con JWT ligado a cada dispositivo (rotación y lista negra), un contrato OpenAPI generado con drf-spectacular y los tipos TypeScript de la app generados desde ese contrato: si la API y la app se desalinean, la integración continua falla.

La app está hecha con React Native, Expo y TypeScript. Tiene 54 pantallas: inicio con los indicadores del mes, reservas con su ficha y un asistente de alta por pasos con borradores y calendario propio, clientes, cobros, avisos, catálogos y la configuración administrativa. Se desbloquea con la biometría del teléfono, guarda los tokens en el llavero del sistema, consulta sin conexión desde una caché persistida y registra cobros con foto del comprobante usando el mismo servicio que la web.

La API y la app se construyeron en dieciséis días, entre el 10 y el 25 de septiembre de 2026. Hoy se distribuyen como builds internas de Android por EAS y se prueban en un teléfono real. El proyecto ya está configurado para iOS; la versión para iPhone espera a la cuenta de Apple Developer del negocio.

Desafíos

El dinero cruza tres dominios —reservas, contabilidad y libro mayor— y un pago puede aplicarse, corregirse, revertirse o dejar un excedente. Mantener la idempotencia y la integridad en todos esos caminos fue lo más difícil. Le siguen las reglas fiscales dominicanas y reducir el acoplamiento natural de un monolito grande sin frenar la operación diaria.

Incidentes reales resueltos

  • Pagos enviados dos veces: cada pago lleva una clave de idempotencia con una restricción única en la base de datos; un reintento devuelve el pago que ya existía.
  • Un reintento de la app devolvía «posible pago duplicado» porque el formulario validaba antes que el servicio. Ahora la clave se resuelve primero.
  • PDF rotos en producción por librerías del sistema que WeasyPrint necesitaba: la imagen de despliegue las instala en build y en ejecución.
  • Una sonda de salud tras el login hacía que Railway diera por caído un despliegue sano: /health/ quedó exenta de login y de la redirección HTTPS.
  • Un descuento aplicado a una reserva ya pagada generó un crédito a favor correcto, pero nadie se enteraba. Corregí el aviso al guardar y el recibo, y añadí un diagnóstico de sólo lectura para auditar excedentes.

Diseño y UX

El panel prioriza lo que mueve el día: reservas, cobros, comisión, saldos y alertas que llevan a la acción. La ficha de reserva separa el estado de venta del de cobro y enseña la escalera de estados, el porcentaje cobrado y el saldo. Los seis tipos de producto comparten el mismo patrón de alta, con navegación por secciones y el precio resumido en vivo.

La contabilidad deja de ser una caja negra: cada asiento explica en lenguaje llano qué registra y la reserva enseña todos los suyos. Un pago contabilizado no se edita, se corrige de forma guiada o se reembolsa. Y bajo 768 px las tablas se convierten en tarjetas.

Sobre las capturas

Todas las capturas salen de una base de datos aislada, sembrada con datos sintéticos por los mismos servicios que usa el sistema: nombres inventados, correos de ejemplo y documentos fiscales ficticios. Ninguna muestra datos de la agencia ni de sus clientes. Las pantallas que presentaban un fallo o no estaban terminadas se dejaron fuera.

Aprendizajes

En software de dinero, comunicar el resultado importa tanto como calcularlo. Los invariantes tienen que vivir en el modelo y en la base de datos, no en los formularios. La idempotencia va antes que la validación: si no, un reintento parece un duplicado. Y reutilizar el servicio de la web desde la API móvil evitó tener dos versiones de la misma regla de negocio.

Estado actual

La web está en producción y se usa a diario. La app móvil está en desarrollo activo: reservas, clientes, cobros y avisos ya funcionan en un teléfono real, y quedan por delante las notificaciones push y la publicación en las tiendas. El trabajo en curso se concentra en una auditoría contable por fases y en seguir pagando deuda técnica sin interrumpir la operación.

Siguiente paso

El repositorio es privado porque es el sistema de un cliente. Si necesitas una plataforma que conecte operación, dinero y contabilidad con trazabilidad real, en la web y en el teléfono, puedes contactarme.