Boutique Conny

cuteofertas

MULTIMARCA · MODA · OFERTAS

Boutique Conny · Sistema de Control

La tienda que se llevaba en un cuaderno, ahora con luz encendida

Sistema de control de tienda: inventario vivo, ventas, fiados con semáforo y cierre de caja que se va por WhatsApp

Web app de retail / punto de venta2026

Desarrollo completo (producto, frontend React, modelo de datos y reglas de Firestore, aprovisionamiento del proyecto Firebase)

Estado

En producción interna — desplegable en Firebase Hosting; el único paso manual pendiente es activar el proveedor Email/Contraseña en la consola de Firebase

Herramienta interna de una tienda real: no hay enlace público ni repositorio abierto.

01 / El punto de partida

Del cuaderno a la vitrina

Nadie sabía cuántas unidades quedaban, ni quién debía qué. Todo estaba escrito a mano o recordado de memoria.

Antes · el cuaderno

Lo que nadie podía contestar

Una boutique de ropa multimarca operaba con cuaderno y memoria: nadie sabía con certeza cuántas unidades quedaban de cada categoría, los fiados a clientas y familiares se olvidaban hasta que alguien preguntaba, el cierre del día se cuadraba de cabeza y el contador recibía las ventas del mes en mensajes sueltos. Además la vendedora no debía ver márgenes ni información financiera, pero sí necesitaba operar el día completo sin depender de la dueña.

Después · la app

Una sola app, dos maneras de verla

Una sola app web instalable desde el navegador del teléfono, con navegación por pestañas distinta según el rol. El inventario se maneja por grupo y categoría de producto con stepper de +/- para ajustar existencias en segundos, y viene con un catálogo base de 54 productos precargables desde la lista de precios real de la tienda. Cada venta y cada fiado descuentan del stock dentro de una transacción de Firestore, y guardan un snapshot del producto (grupo, nombre, precio) para que el histórico no cambie aunque después se edite el catálogo. Los fiados llevan un semáforo por fecha promesa (rojo vencido, ámbar por vencer, verde al día, gris liquidado) que reordena la lista sola y hace latir la alerta roja. Al final del día, el cierre calcula totales por método de pago, arma el PDF con la tabla de prendas vendidas y abre WhatsApp con el texto listo para la dueña; el módulo SENIAT hace lo mismo por rango de fechas o mes completo, con exportación a PDF y CSV/Excel.

02 / El perchero

Siete piezas colgadas del mismo riel

Inventario, ventas atómicas, fiados, cierre, contabilidad, offline y roles. Cada una cuelga del mismo dato en tiempo real.

Inventario por categorías con stepper

Cada producto vive como grupo + nombre + precio + cantidad. Un stepper de − / + ajusta existencias sin abrir formularios, con badge de estado (Agotado, Quedan N, N en stock) y catálogo base de 54 ítems cargable de una vez.

Fiados con semáforo de vencimiento

Cada fiado guarda monto total, abono inicial e historial de abonos, y se pinta según su fecha promesa: rojo vencido (con pulso animado), ámbar a tres días o menos, verde al día, gris liquidado. La lista se ordena por urgencia automáticamente.

Cierre de caja a PDF + WhatsApp

Un botón calcula los totales del día por método de pago, descarga un PDF con encabezado de marca y tabla de prendas, y abre WhatsApp con el informe ya escrito hacia el número de la dueña.

Módulo contable SENIAT

Reporte por rango de fechas o mes completo, con detalle de cada venta (ID, fecha, hora, grupo, producto, cantidad, monto, método) exportable a PDF o a CSV con BOM para que Excel abra bien los acentos.

Funciona sin internet

Firestore se inicializa con caché persistente y gestor multipestaña, y la sesión se guarda en el dispositivo. La tienda sigue vendiendo con la señal caída y todo se sincroniza al volver.

Dos roles, una base de datos

El rol vive en users/{uid} y define tanto las pestañas visibles como las reglas de Firestore: solo la administradora puede anular ventas o fiados y escribir perfiles.

Contabilidad anclada a Caracas

Todas las fechas contables se formatean con Intl en la zona America/Caracas, para que una venta cerca de medianoche no caiga en otro mes fiscal según el reloj del teléfono.

03 / Las pantallas

Ocho vistas, todas del mismo dato

La app se abre desde el navegador del teléfono y se instala en la pantalla de inicio. Estas son sus tres primeras pantallas, recreadas aquí en HTML y CSS.

cuteofertas

MULTIMARCA · MODA · OFERTAS

Boutique Conny · Sistema de Control

👗MarisabelVendedora
👑ConnyAdministradora

Correo

conny@boutiqueconny.com

Contraseña

••••••••

Entrar

Cada quien usa su propio correo y contraseña.

Login con selector de rol

Quién entra decide qué se ve

cuteofertas👗 MarisabelSalir

Inventario

18 productos

Productos

18

Unidades

96

Valor en tienda

$1,842

➕ Agregar producto
🔎 Buscar producto o grupo...
Todos los grupos
👗

Vestidos Playeros Largos

12 en stock

Damas · PROD-0007

$23.00

12+
EditarBorrar
👖

Pantalones Jeans Dama

Quedan 3

Damas · PROD-0012

$28.00

3+
EditarBorrar
🧢

Gorras Estampadas

Agotado

Unisex · PROD-0031

$10.00

0+
EditarBorrar
👕

Blusas Manga Larga

7 en stock

Damas · PROD-0004

$23.00

7+
EditarBorrar
👗Inventario
Nueva
💵Vender
📒Fiados
📲Cierre

Inventario (vendedora)

Stepper de − / + sobre stock real

cuteofertas👗 MarisabelSalir

Venta rápida

18 con stock

Producto vendido *

Vestidos Playeros Largos
🔍 Buscar producto o grupo…

Vestidos Playeros Largos · Damas — $23.00 (12 disp.)

Blusas Manga Larga · Damas — $23.00 (7 disp.)

Pantalones Jeans Dama · Damas — $28.00 (3 disp.)

Licras Deportivas · Damas — $18.00 (9 disp.)

Cantidad *

2

Monto cobrado ($) *

46.00

Existencia disponible: 12

EfectivoPago MóvilZelle
💵 Registrar venta

Al registrar, se descuenta la cantidad vendida del stock automáticamente.

Ventas registradas

👕

2× Blusas Manga Larga

Damas · 2026-06-15 14:32

$46.00

Efectivo
👗

1× Vestidos Playeros

Damas · 2026-06-15 12:07

$23.00

Pago Móvil
👗Inventario
Nueva
💵Vender
📒Fiados
📲Cierre

Venta rápida

SearchSelect propio sobre 54 productos

04 / El semáforo

Los fiados se ordenan solos

Cada fiado se pinta por su fecha promesa y la lista se reordena por urgencia sin que nadie toque un filtro. Eso es semaforoSort.

rojo vencido → ámbar por vencer → verde al día → gris liquidado

Yulimar

👖 Pantalones Jeans Dama · Damas

🟢 Al día

$18.00

de $36.00

📅 30 jun 2026

Abono inicial $18.00

💰 Registrar abonoDetalleF-0017

Tía Rosa

👗 Vestidos Casuales Largos · Damas

🔴 ALERTA ROJA · VENCIDO

$45.00

de $75.00

📅 22 jun 2026

Abono inicial $30.00

💰 Registrar abonoDetalleF-0011

Marielys

🧢 Gorras Estampadas · Unisex

🟡 Por vencer

$12.00

de $20.00

📅 18 jun 2026

Abono inicial $8.00

Abono · 12 jun $0.00

💰 Registrar abonoDetalleF-0009

Sra. Belkis

👕 Blusas Manga Larga · Damas

✓ Liquidado

$0.00

de $46.00

📅 05 jun 2026

Abono inicial $20.00

Abono · 03 jun $26.00

💰 Registrar abonoDetalleF-0004

Fiados con semáforo · el bottom-sheet de abono trae los atajos «Mitad» y «Saldar todo», y valida contra el saldo leído del servidor dentro de la transacción.

05 / El tablero

Lo que sólo ve la dueña

El rol vive en users/{uid} y decide qué pestañas existen. La vendedora nunca llega a esta pantalla, y las reglas de Firestore lo respaldan.

Boutique Conny · Resumen

Resumen

Junio 2026

Ingresos del mes

$2,480.00

Vendido hoy

$145.00

Unidades en stock

96

Valor inventario

$1,842.00

Ingresos por método

37 ventas este mes

Efectivo$1,289.60Pago Móvil$818.40Zelle$372.00

Ventas por día

Junio 2026 · tooltip «Día 15 · $145.00»

161116212630

Cuentas por cobrar

Dinero en la calle

Deuda total pendiente

$312.00

🔴 Vencidos (alerta)

2

Ver fiados vencidos →
📊Resumen
🧾SENIAT
📒Fiados
👗Inventario
📲Cierre

Resumen / Dashboard (administradora)

Recharts sobre los mismos onSnapshot que alimentan el inventario

Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.

06 / El cierre

El informe sale hacia el teléfono

Un botón cuadra el día por método de pago, arma el PDF con jsPDF y abre WhatsApp con el mensaje ya redactado. Así es como la información circula de verdad en el negocio.

Informe para la dueña

Se envía a Conny · +1 (407) 770-7272

📲 Enviar informe (PDF + WhatsApp)
📄 Solo PDF📋 Copiar texto

📄 Reporte por período · SENIAT

Desde · 01/06/2026Hasta · 30/06/2026
DamasCaballerosNiñosNiñasUnisexAccesorios

37 ventas en el período seleccionado · $2.480,00

Generar reporte PDFExportar CSV/Excel

El CSV lleva BOM UTF-8 para que Excel abra bien los acentos, y el cierre suma sólo ventas: los fiados viven en su propia cuenta.

BOUTIQUE CONNY

Cierre de caja diario

15/06/2026

Total facturado

$145.00

Efectivo

$80.00

Pago Móvil

$45.00

Zelle

$20.00

Prendas vendidas

ProductoCant.Monto
Blusas Manga Larga2$46.00
Vestidos Playeros Largos1$23.00
Licras Deportivas3$56.00
Gorras Estampadas1$20.00
TOTAL7$145.00

Generado con jsPDF · autoTable · página 1 de 1

Cierre de caja + informe a la dueña · jsPDF + jspdf-autotable, franja de marca y tabla de prendas

07 / Las cifras

El tamaño real de la tienda

8

pantallas reales (login + 7 vistas)

2

roles con navegación propia

5

colecciones de Firestore

7

operaciones atómicas con runTransaction

3

listeners en tiempo real

54

productos en el catálogo base

6

grupos de inventario

3

métodos de pago soportados

0

Cloud Functions (todo cliente + reglas)

08 / Las etiquetas

24 cosas que ya hace

Una etiqueta por función, como las que cuelgan de cada prenda de la tienda.

01

Login con selector visual de rol (Conny administradora / Marisabel vendedora) que precarga el correo correspondiente

02

Sesión persistente en el dispositivo: no hay que escribir la clave en cada visita

03

Inventario buscable por producto o grupo, con filtro por los 6 grupos del negocio

04

Alta de producto con autocompletado de precio desde el catálogo de la lista de precios

05

Edición de producto en modal (grupo, nombre, precio, cantidad) y borrado con confirmación

06

Carga masiva del catálogo base de 54 productos con cantidad cero, en un batch de Firestore

07

Venta rápida con combobox buscador tipo select2, cantidad, monto autocalculado y método de pago

08

Descuento atómico de stock en la venta: si no hay existencia suficiente, la transacción falla y no se registra nada

09

Historial de ventas filtrable por rango de fechas y grupo, con total del filtro

10

Anulación de venta por la administradora, que devuelve las unidades al stock

11

Fiados: cliente, producto entregado, cantidad, total calculado, abono inicial y fecha promesa obligatoria no pasada

12

Registro de abonos con atajos de Mitad y Saldar todo, y validación contra el saldo leído del servidor

13

Marcado automático como Liquidado cuando el saldo llega a cero

14

Detalle de fiado con historial de pagos y anulación (solo administradora), que devuelve el producto al stock

15

Dashboard con KPIs animados (ingresos del mes, vendido hoy, unidades en stock, valor de inventario)

16

Gráfico de dona de ingresos por método de pago y gráfico de barras de ventas por día del mes

17

Tarjeta de cuentas por cobrar con deuda total y contador de fiados vencidos, con salto directo a la pestaña de Fiados

18

Cierre de caja por fecha con totales de Efectivo, Pago Móvil y Zelle

19

Vista previa del mensaje de WhatsApp en un bloque estilo chat, con botón de copiar al portapapeles

20

Reporte por período con filtro multiselección de grupos, exportado a PDF paginado

21

Exportación CSV/Excel del período con BOM UTF-8 y fila de total

22

Códigos secuenciales seguros PROD-0001 / V-0001 / F-0001 generados por transacción sobre meta/counters

23

Toasts, modales tipo bottom-sheet y estados vacíos ilustrados en toda la app

24

Respeto de prefers-reduced-motion: todas las animaciones se anulan para quien lo pide

09 / Los materiales

Con qué está cosida

Plan Spark, sin Cloud Functions: todo el peso lo llevan el cliente y las reglas de seguridad.

01

Frontend

React 19Vite 8JavaScript (ESM)CSS custom properties (theme.css propio, sin framework)
02

Datos y backend

Firebase 12Firebase Authentication (Email/Contraseña)Cloud Firestore en tiempo real (onSnapshot)persistentLocalCache + persistentMultipleTabManager (offline)runTransaction y writeBatchReglas de seguridad de Firestore basadas en rolFirebase Hosting (SPA rewrite a index.html)
03

Gráficos y documentos

Recharts 3 (PieChart, BarChart)jsPDF 4jspdf-autotable 5
04

Tipografía y marca

Fraunces (titulares y cifras)Poppins (interfaz)Google Fonts con preconnect
05

Tooling y aprovisionamiento

ESLint 10 con eslint-plugin-react-hooks y eslint-plugin-react-refreshScript Node de aprovisionamiento (scripts/setup-auth.mjs) contra Identity Toolkit Admin API y Firestore RESTFirebase CLI y gcloud para crear la base y desplegar reglas
10 / Bajo el mostrador

Arquitectura y lo que costó

SPA de React 19 montada por Vite, sin router: App decide entre Login y AppShell según el estado de autenticación, y AppShell conmuta pantallas por estado local con dos juegos de pestañas (cinco para vendedora, cinco para administradora). Dos contextos sostienen todo: AuthContext escucha onAuthStateChanged, lee el perfil de users/{uid} y expone isAdmin; DataContext abre tres listeners onSnapshot (inventory, sales, credits) ordenados por createdAt y expone las acciones de dominio. Toda escritura que toque stock pasa por runTransaction: las ventas, los fiados, los abonos, las anulaciones y el ajuste rápido de cantidad leen el documento del servidor dentro de la transacción antes de decidir, y los códigos secuenciales se sacan de meta/counters también transaccionalmente, de modo que dos teléfonos vendiendo a la vez no pisan el mismo número ni sobrevenden. Ventas y fiados guardan un snap del producto (grupo, nombre, precio) para congelar el histórico. La lógica pura vive en src/lib: format.js concentra formato de dinero, fechas ancladas a America/Caracas con Intl, el catálogo base, las reglas de emoji por producto y el cálculo de saldo y semáforo de fiados; cashclose.js concentra los cómputos de cierre y rango, el texto de WhatsApp y la construcción de los PDF. La seguridad se apoya en firestore.rules, que resuelve el rol leyendo el documento del usuario y reserva a admin las eliminaciones de ventas y fiados y la escritura de perfiles. No hay Cloud Functions: el proyecto vive en el plan Spark y toda la lógica es cliente + reglas.

Siete cosas que se rompieron primero

Se rompía · 01

Dos personas registrando ventas desde teléfonos distintos podían sobrevender la última unidad o repetir el mismo código de venta.

Se resolvió así

Cada venta, fiado, abono, anulación y ajuste de stock se ejecuta dentro de runTransaction: se relee el documento de inventario en el servidor, se valida la existencia y recién ahí se escribe la venta y se descuenta. Los códigos PROD-/V-/F- salen de una transacción propia sobre meta/counters.

Se rompía · 02

El internet de la tienda se cae y las ventas no pueden esperar.

Se resolvió así

Firestore se inicializa con persistentLocalCache y persistentMultipleTabManager, y la autenticación con browserLocalPersistence. La app sigue registrando contra la caché local y sincroniza al recuperar señal, sin que la vendedora tenga que hacer nada.

Se rompía · 03

Con serverTimestamp pendiente, las ventas recién registradas tenían createdAt en null y desaparecían de las listas y los totales del día durante unos instantes.

Se resolvió así

Cada documento guarda además createdAtLocal con el ISO del cliente, y los helpers whenDate/whenKey/whenMonth caen a ese campo cuando el timestamp del servidor todavía no llegó.

Se rompía · 04

Una venta a las once de la noche podía contarse en otro día (u otro mes fiscal) si el teléfono estaba configurado en otra zona horaria.

Se resolvió así

Todas las claves contables se derivan con Intl.DateTimeFormat fijado a America/Caracas, de modo que el día y el mes del reporte no dependen del reloj del dispositivo.

Se rompía · 05

El plan Spark no permite activar el proveedor Email/Contraseña por API gratuita, y había que crear los dos usuarios con sus roles sin trabajo manual repetido.

Se resolvió así

scripts/setup-auth.mjs automatiza todo lo automatizable: intenta habilitar el proveedor vía Identity Toolkit Admin API con el token de gcloud, crea (o reconoce si ya existen) las dos cuentas y escribe sus documentos de rol y el contador inicial vía Firestore REST. Es idempotente y se puede reejecutar. Solo queda un clic en consola documentado en el README.

Se rompía · 06

El desplegable nativo con 54 productos era inusable en un teléfono para registrar una venta rápida.

Se resolvió así

Se construyó un SearchSelect propio: un combobox con buscador integrado, cierre por click fuera y touchstart, lista de 240px con scroll táctil y opción resaltada, que filtra por nombre y por grupo mientras se escribe.

Se rompía · 07

La vendedora necesitaba operar todo el día pero no debía ver ganancias ni el resumen financiero.

Se resolvió así

El rol de users/{uid} define dos juegos de pestañas y dos vistas distintas del mismo dato: la vendedora entra directo a Inventario y no tiene acceso a Resumen ni SENIAT, y las reglas de Firestore reservan las eliminaciones a admin. El README documenta explícitamente el límite de este enfoque y la alternativa de mover los costos a una colección solo-admin.

11 / La paleta

Los colores de la tienda

Boutique cálida y femenina en modo diurno: fondo rosa empolvado, tarjetas blancas de esquinas muy redondeadas, rosa fucsia como color de acción, azul marino profundo reservado para el panel de marca y detalles dorados de vitrina. Titulares en Fraunces serif, interfaz en Poppins. Semántica de color viva para el semáforo de fiados: verde al día, ámbar por vencer, rojo vencido.

primary

#d4567a

secondary

#14142b

accent

#c9a35a

bg

#fbf2f4

surface

#ffffff

text

#1c1830

Degradado de marca

/Users/macbook/boutique-conny-app/src/theme.css (bloque :root — --rose #d4567a, --rose-d #b8385f, --navy #14142b, --gold #c9a35a, --bg #fbf2f4, --card #ffffff, --ink #1c1830, --pink #ec7f9b, --cream #f4ead2)

Sin capturas publicables: es la herramienta interna de una tienda con datos de clientas reales. Todas las pantallas de esta página están recreadas en HTML y CSS a partir de la interfaz real.

Aplicación web para una boutique multimarca real que se llevaba en cuaderno: registrar lo que entra, lo que se vende, lo que se fía y cuánto quedó en caja al final del día.

Dos roles con vistas distintas sobre los mismos datos: la vendedora (Marisabel) ve inventario, ventas, fiados y cierre; la administradora (Conny) ve además el resumen financiero con gráficos y el módulo contable para el SENIAT.

Todo corre sobre Cloud Firestore en tiempo real con caché persistente: si se cae el internet en la tienda, la app sigue registrando y sincroniza sola al volver la señal.

El cierre de caja diario genera un PDF con jsPDF y abre WhatsApp con el informe ya redactado hacia el teléfono de la dueña, que es como realmente circula la información en el negocio.

DamasCaballerosNiñosNiñasUnisexAccesorios54 productosrunTransactionoffline firstPDF + WhatsAppSENIATAmerica/CaracasDamasCaballerosNiñosNiñasUnisexAccesorios54 productosrunTransactionoffline firstPDF + WhatsAppSENIATAmerica/Caracas

Boutique Conny

¿Quieres algo así para tu producto?

Una tienda de barrio operando con transacciones atómicas, caché offline y contabilidad anclada a su zona horaria. Si tienes un negocio que todavía vive en un cuaderno, este es exactamente el terreno que conozco.