Sistema web de gestión para un taller de reparación tecnológica: catálogo con compra real, flujo completo de servicio técnico con cotización y pago, comunidad, wiki de componentes y calculadora de compatibilidad. Proyecto productivo — Técnica en Programación de Software, SENA.
Desarrollar una aplicación web que permita a SERVI RKA gestionar de forma digital sus procesos de reparación de equipos, venta de componentes tecnológicos, seguimiento de solicitudes y atención al cliente, reemplazando el control manual por un sistema centralizado con base de datos real.
Fuera de alcance: pasarela de pago electrónico real (el pago se registra manualmente por el técnico, como ocurre hoy en el taller), facturación electrónica DIAN y notificaciones automáticas por correo/SMS (la comunicación se hace por el chat interno de cada solicitud).
Arquitectura sencilla y explicable, sin frameworks pesados, apropiada para el nivel técnico y fácil de sustentar.
Estructura semántica y formularios con validación nativa.
Variables CSS, Grid, Flexbox, animaciones y diseño responsive sin frameworks.
Vanilla JS: carrusel, carrito sin recarga (Fetch API), calculadora y chat con auto-scroll.
Lógica de servidor, sesiones, control de acceso por rol y procesamiento de formularios.
Motor InnoDB con llaves foráneas, índices y transacciones.
Consultas preparadas reales como protección contra inyección SQL.
Apache + MySQL + PHP para desarrollo y pruebas en local.
Servidor Linux con Apache y MySQL, dominio propio y acceso público real.
| Código | Descripción |
|---|---|
| RF01 | Registro y autenticación de clientes |
| RF02 | Control de acceso por rol (cliente / administrador) |
| RF03 | Registrar solicitud de servicio con código único |
| RF04 | Consultar estado de solicitudes en línea de tiempo |
| RF05 | Ver catálogo, buscar, filtrar y ver ficha de producto |
| RF06 | Carrito: agregar, modificar cantidades y eliminar |
| RF07 | Confirmar pedido, descontar stock y generar factura |
| RF08 | Registrar diagnóstico y cotización de una solicitud |
| RF09 | Aprobar o rechazar la cotización como cliente |
| RF10 | Registrar pagos (totales o parciales) de una solicitud |
| RF11 | Enviar y recibir mensajes dentro de cada solicitud |
| RF12 | CRUD de productos con galería de hasta 6 imágenes |
| RF13 | CRUD de categorías, servicios y usuarios |
| RF14 | Crear publicaciones y respuestas en la comunidad |
| RF15 | Moderación de contenido por el administrador |
| RF16 | Wiki de componentes con filtros por categoría y marca |
| RF17 | Calculadora de compatibilidad basada en reglas |
| RF18 | Asistente que arma una configuración recomendada |
| Código | Descripción |
|---|---|
| RNF01 | Contraseñas almacenadas con hash bcrypt, nunca en texto plano |
| RNF02 | Todas las consultas mediante sentencias preparadas (PDO) |
| RNF03 | Escape de toda salida de usuario (mitigación XSS) |
| RNF04 | Rutas administrativas protegidas del lado del servidor |
| RNF05 | Interfaz responsive de 320px a 1440px+ |
| RNF06 | Ejecutable en entorno estándar (Apache + PHP + MySQL) |
| RNF07 | Código organizado por carpetas con nombres descriptivos |
| RNF08 | Integridad referencial garantizada por llaves foráneas |
| RNF09 | Operaciones críticas dentro de transacciones (rollback ante error) |
| RNF10 | Accesibilidad: labels, foco visible y respeto a "reducir movimiento" |
| RNF11 | Acciones de escritura (agregar al carrito) sin recargar la página |
| RNF12 | La calculadora requiere sesión iniciada para usarse |
Arquitectura en tres capas sobre PHP, con la lógica de negocio separada por dominio en archivos reutilizables.
Archivos .php con HTML, más assets/css/style.css y JavaScript vanilla.
El layout compartido vive en includes/header.php y includes/footer.php.
Funciones agrupadas por dominio en /includes: auth.php (sesiones y roles),
carrito_funciones.php (carrito y checkout), solicitudes_funciones.php (estados,
diagnóstico, aprobación, pago y mensajería) y foro_funciones.php (publicaciones y respuestas).
Una única función conectarBD() en config/database.php devuelve la conexión
PDO reutilizable. Ningún archivo abre conexiones por su cuenta.
/ ├── admin/ Panel administrativo (protegido por rol) │ ├── dashboard.php Resumen con estadísticas reales │ ├── productos.php CRUD de productos + galería de hasta 6 fotos │ ├── categorias.php CRUD de categorías │ ├── servicios.php CRUD de servicios │ ├── solicitudes.php Diagnóstico, cotización, pagos, chat e historial │ ├── wiki.php CRUD de la wiki + imágenes por categoría │ ├── pedidos.php Gestión de pedidos │ └── usuarios.php CRUD de usuarios ├── assets/ │ ├── css/style.css Estilos globales (un solo archivo, sin frameworks) │ └── img/ Logo, carrusel y fondos temáticos ├── config/database.php Conexión PDO ├── includes/ Lógica de negocio + layout compartido ├── uploads/ productos/ wiki/ categorias/ — imágenes subidas ├── docs/ Documentación técnica completa ├── index.php Inicio ├── productos.php producto.php agregar_carrito.php ├── carrito.php checkout.php mis_pedidos.php ├── mis_solicitudes.php Seguimiento, aprobación, pago y chat del cliente ├── comunidad.php publicacion.php ├── wiki.php calculadora.php ├── login.php registro.php logout.php └── database.sql Script completo de la BD
No es solo una lista de estados: cada paso cambia el comportamiento de la interfaz para el cliente y para el técnico, y queda respaldado en la base de datos.
Registra el problema desde el formulario de inicio. El sistema genera un código único
(ORD-AAAA-####) y crea la primera entrada en el historial.
Desde el panel admin registra el hallazgo, agrega repuestos uno por uno (con cantidad y precio) y
define la mano de obra. El sistema suma el costo_total automáticamente.
Al guardar el diagnóstico, un mensaje automático llega al chat del cliente con el resumen completo: qué se encontró, qué cuesta y cuántos días tomará.
Ve el desglose de repuestos y mano de obra, y aprueba o rechaza con un clic. Si rechaza, puede explicar por qué; si aprueba, la solicitud avanza sola a "En reparación".
El técnico anota los abonos según entran (estado_pago: pendiente, parcial o pagado).
El cliente ve en todo momento cuánto ha pagado y cuánto falta.
En cualquier punto del proceso, cliente y taller se escriben desde la misma solicitud. Cada quien ve un contador de mensajes sin leer en su listado.
Base relacional en MySQL con integridad referencial, normalizada hasta la tercera forma normal. 21 tablas en total.
1FN —
Todos los campos son atómicos. Los repuestos de una cotización están en repuestos_solicitud,
no como texto libre dentro de la solicitud.
2FN —
Todas las tablas usan clave primaria simple autoincremental, por lo que no existen dependencias parciales.
precio_unitario vive en detalle_pedido porque depende del momento de la compra.
3FN —
Ningún atributo no clave depende de otro no clave. El nombre de la categoría nunca se copia dentro de
productos: se obtiene siempre por JOIN, evitando redundancia e inconsistencias.
detalle_pedido.precio_unitario guarda el precio al momento de comprar. Si mañana sube el precio del producto, los pedidos antiguos no se alteran.estados_solicitud es una tabla con orden, no texto libre. Evita errores de escritura y permite ordenar la línea de tiempo.solicitudes_servicio.aprobacion (pendiente/aprobada/rechazada) impide que se repare algo que el cliente no autorizó.estado_pago y monto_pagado admiten abonos, no solo pago total de una vez.historial_estados_solicitud, dejando trazabilidad completa.carrito_items está ligado al usuario, así que sobrevive al cierre del navegador.(id_usuario, id_producto) en el carrito impide filas duplicadas del mismo producto.producto_imagenes vive aparte de productos para no limitar a una sola foto ni forzar columnas imagen2, imagen3....password_hash() y password_verify() con bcrypt. Ninguna contraseña se guarda ni se compara en texto plano.
PDO con ATTR_EMULATE_PREPARES => false, forzando consultas preparadas reales del lado del motor.
Toda salida de datos de usuario pasa por htmlspecialchars() mediante la función limpiar().
requerirAdmin() bloquea el panel a nivel de servidor: escribir la URL directamente devuelve 403.
Aprobar o rechazar una cotización valida que la solicitud pertenezca al usuario que hace la petición, no solo que esté logueado.
session_regenerate_id(true) al iniciar sesión, generando un identificador nuevo.
Validación de extensión, tamaño máximo y verificación real con getimagesize(). Nombre aleatorio con random_bytes().
El parámetro volver tras login/registro solo acepta rutas que empiecen por /, evitando redirecciones a sitios externos.
Registro, login y logout con sesiones PHP, dos roles diferenciados y redirección de vuelta a la página de origen.
Búsqueda, filtro por categoría y precio, galería de hasta 6 fotos, especificaciones y productos relacionados.
Agregar productos actualiza el carrito con Fetch API; checkout con transacción y factura descargable.
Diagnóstico, cotización con repuestos, aprobación del cliente, registro de pagos y chat por solicitud.
CRUD de productos, categorías, servicios, usuarios, solicitudes, pedidos y wiki, todo protegido por rol.
Publicaciones por categoría, respuestas, búsqueda y moderación desde el panel.
120 fichas técnicas con filtros por categoría, marca y gama, e imágenes editables por el administrador.
Verifica compatibilidad regla por regla y ofrece 3 configuraciones comparables a partir de una pieza que ya tengas. Requiere cuenta.
Ejemplo de lógica defendible en sustentación — usa una transacción para garantizar que nunca queden datos inconsistentes:
1. Obtener los items del carrito del usuario
2. INICIAR TRANSACCIÓN
3. Para cada item:
SELECT stock ... FOR UPDATE (bloquea la fila)
Si stock insuficiente → ROLLBACK y avisar al cliente
4. Generar código PED-AAAA-#### sin duplicados
5. INSERT en pedidos (encabezado)
6. Para cada item:
INSERT en detalle_pedido (con precio histórico)
UPDATE productos SET stock = stock - cantidad
7. DELETE de carrito_items
8. COMMIT
9. Redirigir a la factura (evita reenvío accidental del formulario)
Si algo falla en cualquier punto, el ROLLBACK deshace todo: no se crea un pedido
a medias ni se descuenta stock de un pedido que no se completó.
Técnica en Programación de Software · Cúcuta, Norte de Santander · 2026
Volver al inicio