UPF El Sabor de Birongo · Higuerote, Venezuela
STO
Online Store
Tienda + panel en un solo PHPCacao en grano · 1 kg
Bs 1.240,00
Bolivares
En stock: 42
Bs 1.240,00
-15%Chocolate artesanal 70%
Bs 980,50
Bolivares
En stock: 18
Bs 980,50
-10%Nibs de cacao · 250 g
Bs 640,00
Bolivares
En stock: 27
Bs 640,00
-5%Manteca de cacao
Bs 1.870,00
Bolivares
En stock: 9
Bs 1.870,00
-20%Cacao en polvo · 500 g
Bs 720,25
Bolivares
En stock: 34
Bs 720,25
-8%Bombones de licor
Bs 2.150,00
Bolivares
En stock: 6
Bs 2.150,00
-12%Tienda en línea y panel de gestión en un solo PHP: catálogo, carrito, pedidos e inventario para una empresa local de Higuerote.
Desarrollo full-stack: modelo de datos MySQL, backend PHP con patrón MVC propio, capa AJAX y toda la interfaz.
Arrastra la vitrina o pasa el cursor por encima para detenerla.
Del cuaderno a la vitrina
Una unidad de producción familiar que vendía por catálogo informal necesitaba, a la vez, una tienda que mirara hacia afuera y un control que mirara hacia adentro.
El problema
Precios y stock en cuadernos
Una unidad de producción familiar en Higuerote vendía por catálogo informal: los precios y el stock vivían en cuadernos y mensajes sueltos, no había forma de que un cliente viera el inventario disponible ni de dejar un pedido registrado, y el control de qué se despachó, quién pagó y con qué referencia dependía de la memoria del encargado. Tampoco existía un reporte que permitiera cerrar el día o la semana.
La solución
Dos caras servidas por el mismo enrutador
Una aplicación PHP/MySQL de dos caras servida por el mismo enrutador. Hacia afuera, un escaparate con banner rotativo, catálogo paginado filtrable por categoría, buscador, ordenamiento por nombre o precio, ficha de producto con galería en lightbox, carrito y lista de favoritos. Hacia adentro, un dashboard con inventario, alertas de stock mínimo, alta de productos con portada y galería, gestión de clientes y administradores, pedidos pendientes y realizados, registro del medio de pago y su número de referencia, notificaciones, bitácora de últimas visitas y exportación de pedidos entregados a PDF por día, semana o mes.
Estado del repositorio
Proyecto publicado con licencia MIT en un único commit. Corre sobre un entorno LAMP local (`SERVERURL` apunta a `http://localhost/tienda/`). El snapshot publicado no incluye `controladores/pedidoControlador.php` ni `vistas/js/añadir.js` y `vistas/js/carrito.js`, referenciados por `ajax/pedidoAjax.php` y `vistas/inc/scripts.php`.
Lo que hay dentro del repositorio
105
archivos PHP en el repositorio
14.878
líneas de PHP
42
vistas de contenido en español
40
rutas en la lista blanca del router
12
controladores
11
endpoints AJAX
11
tablas MySQL
26
funciones en el modelo base
Seis decisiones que sostienen las dos caras
Dos aplicaciones, un solo punto de entrada
`index.php` carga `vistas/plantilla.php`, que compara el primer segmento de la URL contra la constante `DASHBOARD` y decide si arma la tienda pública (header + vista + footer) o el panel (nav lateral fijo + navbar + vista), ramificando además según el cargo guardado en sesión.
Enrutado propio con lista blanca
El `.htaccess` reescribe cualquier ruta a `index.php?views=...`; `vistasControlador` la parte por `/` y `vistasModelo` la valida contra un arreglo de 40 vistas permitidas antes de tocar el disco. Todo lo que no esté en la lista cae en la vista 404.
Identificadores cifrados en la URL
`mainModel::encryption()` / `decryption()` cifran cada id con AES-256-CBC usando una clave `sha256(SECRET_KEY)` y un IV derivado de `SECRET_IV`, de modo que las URLs de detalle, edición y notificaciones nunca exponen el id numérico de la fila.
Formularios AJAX con confirmación
Cualquier `<form class="FormularioAjax">` es interceptado por `vistas/js/ajax.js`: lanza un diálogo SweetAlert2 cuyo texto depende del atributo `data-form` (save, update, delete, search), envía con `fetch` a un endpoint de `ajax/` y pinta la respuesta JSON del controlador sin recargar la página.
Reportes de pedidos en PDF
`dashboard-reportes.php` deja elegir Día, Semana o Mes y envía a `modelos/export.php`, que extiende FPDF para generar el «Reporte de Pedidos Entregados» con columnas de cliente, producto, cantidad, pago, tipo de pago, referencia y fecha, más numeración de páginas.
Notificaciones y bitácora de visitas
La tabla `notificaciones` guarda receptor, concepto, asunto y estado (`Sin leer`), y el header pinta un badge con el conteo en vivo; la tabla `visitas` registra cliente, estado y `ultima_visita`, que el panel lista paginada de cinco en cinco.
El escaparate que ve el cliente
Banner rotativo, catálogo paginado con filtros y ordenamiento, y una ficha de producto con galería en lightbox. Todo servido por el mismo index.php.
Nuestros servicios
Envío
Despacho a domicilio dentro de Higuerote y alrededores.
Inventario
Stock actualizado y alerta cuando baja del mínimo.
Tienda
Catálogo completo, favoritos y pedidos en línea.
Crea tu cuenta
Inicio de la tienda
Productos en tienda
Todos los productos habilitados y con existencia disponible en la tienda.
Cacao en grano · 1 kg
Bs 1.240,00
Bolivares
En stock: 42
Chocolate artesanal 70%
Bs 980,50
Bolivares
En stock: 18
Nibs de cacao · 250 g
Bs 640,00
Bolivares
En stock: 27
Catálogo de productos
Detalles del producto
VolverCacao en grano · 1 kg
Descripción:
Grano fermentado y secado al sol en Birongo, seleccionado a mano y empacado en sacos de un kilo. Trazabilidad por lote y disponibilidad sujeta a la cosecha de la temporada.
Precio: Bs 1.240,00
Costo del envío: Bs 95,00
Galería de imágenes
Detalle de producto
El identificador del producto nunca viaja en claro: la URL lleva el token que devuelve mainModel::encryption(), y el controlador lo descifra antes de consultar.
El backoffice que ve el encargado
La misma plantilla, otro layout: nav lateral de 300 px, navbar de 50 px y una rejilla de mosaicos con los conteos reales leídos de la base.
Arturo Sojo
Administrador
Panel de control
¡Bienvenido ARTURO SOJO!
Categorías
8 Registradas
Clientes
46 Registrados
Productos
132 Registrados
Administradores
3 Registrados
Pedidos
57 Registrados
Dashboard del administrador
Login del panel
La frontera
El único momento oscuro
Toda la aplicación vive en gris muy claro con tarjetas blancas. El login es la excepción: un degradado violeta-noche a pantalla completa que marca visualmente dónde termina la tienda y dónde empieza el panel. Los errores no se pintan en el formulario, llegan como modales de SweetAlert2 disparados desde PHP.
Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.
De la URL a la consulta
Siete escalones entre lo que escribe el navegador y lo que devuelve MySQL. Ninguno de ellos toca el disco antes de que la ruta pase por la lista blanca.
Una sola RewriteRule con Options All -Indexes canaliza cualquier ruta hacia index.php?views=$1.
Único punto de entrada: carga config/APP.php con las constantes de negocio y llama a vistasControlador.
Abre la sesión, parte la URL por «/» y compara el primer segmento contra la constante DASHBOARD.
vistasModelo valida el nombre contra 40 rutas permitidas y comprueba con is_file() que la vista exista.
12 controladores con 38 funciones; las escrituras entran por los 11 endpoints de ajax/ y devuelven JSON.
26 funciones compartidas: guardar, actualizar, eliminar, limpiar, validar, cifrar ids y paginar tablas.
Consultas preparadas sobre 11 tablas, con SQL_CALC_FOUND_ROWS y FOUND_ROWS() para el paginador.
Arquitectura completa
Patrón MVC artesanal de tres capas. `index.php` es el único punto de entrada: carga `config/APP.php` (constantes de negocio) y `vistasControlador`, que devuelve `vistas/plantilla.php`. La plantilla abre la sesión, parte `$_GET['views']` por `/` y, si el primer segmento coincide con la constante `DASHBOARD`, entra al panel; de lo contrario arma la web pública envolviendo la vista entre `header.php` y `footer.php`. La resolución de vistas pasa por `vistasModelo::obtener_vistas_modelo()`, que valida el nombre contra una lista blanca de 40 rutas y comprueba con `is_file()` que exista `vistas/contenidos/<lang>/<modulo>-<vista>.php`; cualquier otra cosa se resuelve como 404. Todos los controladores (12 archivos, 38 funciones) extienden `mainModel`, que centraliza en 26 funciones la conexión PDO, los helpers `guardar_datos`, `actualizar_datos`, `eliminar_registro` y `datos_tabla`, la limpieza de cadenas, la validación por expresiones regulares, el cifrado/descifrado de ids y el paginador de tablas. Las escrituras no viajan por formularios tradicionales sino por los 11 endpoints de `ajax/`, cada uno un despachador que instancia su controlador y ejecuta la acción indicada en un campo `modulo_*` del POST, devolviendo JSON que `ajax.js` convierte en un modal de SweetAlert2. Los listados se generan en el servidor: los controladores construyen el HTML de tarjetas y tablas como string y lo devuelven a la vista, apoyándose en `SQL_CALC_FOUND_ROWS` + `FOUND_ROWS()` para paginar. Deuda técnica visible en el código: las contraseñas se guardan con el mismo cifrado reversible `encryption()` en lugar de un hash unidireccional, y varios paginadores interpolan variables ya saneadas directamente en la consulta en vez de enlazarlas.
El mosaico completo
Los mismos mosaicos cuadrados del panel, uno por funcionalidad. Al pasar el cursor se rellenan de rojo, igual que el elemento activo del menú lateral.
Catálogo público paginado de 10 productos por página, filtrable por categoría habilitada y ordenable A-Z, Z-A, precio menor a mayor y precio mayor a menor.
Buscador de productos en modal que persiste el término en sesión (`busqueda_tienda`) y se limpia con un botón dedicado.
Ficha de producto con portada, tipo, stock, fabricante, modelo, descripción, precio con descuento aplicado, costo de envío y galería de imágenes en lightbox (fslightbox).
Carrito de compras por cliente con alta, actualización de cantidad y eliminación por AJAX, y contador en el header.
Lista de favoritos por cliente con su propio contador y paginador.
Registro y autenticación de clientes y de personal, con estado de cuenta (`Activa`) y token de sesión generado en el login.
Dos roles diferenciados: `Administrador` (categorías, administradores, empresa, alta de productos) y `Usuario`, con menús y vistas condicionadas.
Inventario con alta, edición, borrado, portada, galería y ficha de información por producto, incluyendo código de barras y SKU.
Vista de productos en stock mínimo, apoyada en los campos `producto_stock` y `producto_stock_minimo`.
Gestión de pedidos separada en pendientes y realizados, con búsqueda y ficha de detalle.
Registro del pago de un pedido: medio de pago y número de referencia, guardados por AJAX.
Exportación a PDF de los pedidos entregados por día, semana o mes.
Formulario de contacto que arma y envía el correo desde `correoControlador` con validación por expresiones regulares.
Ficha de empresa editable desde el panel y datos de contacto, país, dirección, teléfono y redes sociales centralizados en `config/APP.php`.
Selector de avatar entre 12 imágenes incluidas (variantes femeninas, masculinas y dos por defecto).
Configuración de negocio por constantes: símbolo y nombre de moneda, decimales, separadores, 7 tipos de documento de usuario, 7 de empresa, 14 unidades de producto y límites de peso para portada (3 MB) y galería (7 MB).
Scripts de respaldo e importación de la base de datos vía `mysqldump` / `mysql` desde `modelos/respaldar.php` e `import.php`.
Estructura multiidioma por carpeta (`vistas/contenidos/es/`, `vistas/inc/es/`) gobernada por la constante `LANG`.
Con qué está hecho
Sin framework, sin gestor de dependencias: cada librería está copiada dentro del repositorio.
Backend
Base de datos
Front-end
JavaScript
Reportes y servidor
Lo que costó resolver
Seis problemas concretos del código y la decisión que los cerró. Toca cada uno para abrirlo.
Solución
Un único `plantilla.php` decide por el primer segmento de la URL contra la constante `DASHBOARD` y, dentro del panel, vuelve a ramificar por `$_SESSION['cargo_sto']`: el administrador recibe `nav_lateral.php` + `nav_bar.php`, mientras que el rol `Usuario` reutiliza el header y el footer de la tienda.
Solución
Una sola `RewriteRule` en `.htaccess` canaliza todo hacia `index.php?views=$1` con `Options All -Indexes`; luego `vistasModelo` valida el nombre contra una lista blanca de 40 vistas y solo después compone la ruta del archivo, devolviendo 404 ante cualquier valor no previsto.
Solución
`encryption()` cifra cada id con AES-256-CBC (clave `sha256(SECRET_KEY)`, IV de 16 bytes derivado de `SECRET_IV`) y `datos_tabla()` lo descifra y sanea antes de consultar, de modo que la URL viaja siempre con un token opaco.
Solución
Una convención de una sola clase: cualquier formulario marcado como `FormularioAjax` es capturado por `ajax.js`, que arma un `FormData`, pide confirmación con SweetAlert2 —con el texto adaptado al `data-form` y al `data-lang`— y envía con `fetch` al endpoint de `ajax/`, mostrando la respuesta JSON sin salir de la vista.
Solución
`cliente_paginador_producto_controlador()` valida el orden contra la lista `[ASC, DESC, MAX, MIN]`, comprueba que la categoría exista y esté habilitada, traduce MAX/MIN a orden por `producto_precio_venta` y calcula el total con `SQL_CALC_FOUND_ROWS` en la misma consulta que trae la página, mostrando siempre solo productos habilitados con stock mayor que cero.
Solución
El pedido guarda medio de pago y número de referencia desde `dashboard-pedido-pay.php`, y `modelos/export.php` extiende FPDF con una cabecera de siete columnas para emitir el reporte de pedidos entregados del día, la semana o el mes en un clic.
STO Online Store
STO es una tienda en línea completa escrita en PHP plano sobre una arquitectura MVC hecha a mano: un único `index.php` levanta la plantilla y, según el primer segmento de la URL, sirve la tienda pública o el dashboard privado.
El repositorio está configurado para un cliente real: la constante `COMPANY` es «UPF El Sabor de Birongo», el país es Venezuela, la dirección «Higuerote-Birongo» y la moneda son bolívares con símbolo «Bs».
Cubre el ciclo comercial completo: catálogo con categorías, búsqueda y ordenamiento, ficha de producto con galería, carrito, favoritos, pedidos con registro de pago, notificaciones al cliente y reportes en PDF.
El backoffice maneja dos roles (`Administrador` y `Usuario`) que comparten plantilla pero reciben menús, vistas y permisos distintos; la seguridad de cada pantalla del panel se refuerza con el include `vistas/inc/admin_security.php`.
Todo el proyecto está internacionalizado por carpeta de idioma (`vistas/contenidos/<lang>/`) y la constante `LANG`, aunque el snapshot solo incluye el paquete `es`.
El repositorio se publicó en GitHub el 10 de enero de 2025 en un solo commit; la licencia MIT y la clave `SECRET_KEY = '$STO@2021'` en `config/SERVER.php` sitúan el desarrollo en 2021.
Comercio serio y ordenado: azul marino de administración, azul enlace para el precio y un rojo coral que marca lo activo. Grises muy claros, tarjetas blancas con esquinas de 10 px y sombra suave; el único momento oscuro es el degradado violeta-noche del login, que separa visualmente la tienda del panel.
STO Online Store
¿Quieres algo así para tu producto?
Una tienda y un panel completos sobre PHP plano: enrutado propio con lista blanca, ids cifrados en la URL, escrituras por AJAX y reportes en PDF. Si necesitas algo así —o migrarlo a algo moderno sin perder el negocio que ya funciona— es terreno conocido.