Proyecto_INTEGRADOR_V2
🎂 Proyecto Integrador — Sweet Cream Rose / SweetCreamPink
Repostería artesanal — Sistema web fullstack
📋 Resumen General
| Aspecto | Detalle |
|---|
| Nombre del proyecto | Sweet Cream Rose (también mencionado como Sweet Kiss / SweetCreamPink) |
| Backend | Java 17 + Spring Boot 3.4.1 |
| Frontend | React (Create React App) |
| Base de datos | MySQL 8.0.45 |
| Seguridad | JWT + Spring Security + BCrypt |
| Build tool | Maven |
| Puerto backend | 8080 (por defecto Spring Boot) |
🗂️ Estructura del Proyecto
Proyecto_INTEGRADOR_V3/
├── demoSpringBoot/ ← Backend Spring Boot
│ ├── src/main/java/
│ │ ├── Config/ ← Configuración de seguridad y CORS
│ │ ├── Controlador/ ← Endpoints REST (API)
│ │ ├── DAO/ ← Acceso a datos (patrón DAO)
│ │ ├── DTO/ ← Objetos de transferencia de datos
│ │ ├── Modelo/ ← Entidades JPA (tablas de la BD)
│ │ ├── Repositorio/ ← Interfaces Spring Data JPA
│ │ ├── Security/ ← JWT y autenticación
│ │ └── service/ ← Lógica de negocio
│ ├── logback.xml ← Configuración de logs
│ ├── nbactions.xml ← Acciones NetBeans (run/debug)
│ └── pom.xml ← Dependencias Maven
├── frontend-pink-sweet/ ← Frontend React
│ └── src/
│ ├── App.jsx ← Componente raíz + enrutamiento
│ ├── Login.js ← Pantalla de login
│ ├── Registro.js ← Registro de clientes
│ ├── Carrito.js ← Carrito de compras
│ ├── Productos.js ← Catálogo de productos
│ ├── Ofertas.js ← Sección de ofertas
│ ├── Perfil.js ← Perfil del usuario
│ ├── DashboardAdmin.js← Panel de administrador
│ ├── Recibo.js/2/3 ← Comprobantes de pago (variantes de diseño)
│ ├── Boletas.js ← Generador de boletas
│ └── CambiarPassword1-4.js ← Flujo de recuperación de contraseña
└── Dump20260427.sql ← Volcado completo de la base de datos
🗄️ Base de Datos (reposteria)
Tablas principales
| Tabla | Descripción |
|---|
usuario | Clientes registrados (nombre, correo, contraseña BCrypt, teléfono, rol) |
rol | Solo 2 valores: Admin (1) y Cliente (2) |
categoria | 10 categorías: Cupcakes, Galletas, Tortas, Alfajores, Trufas, etc. |
producto | Productos del catálogo, asociados a una categoría |
producto_variantes | Sabores/tamaños de cada producto con precio adicional |
orden | Pedidos del cliente: estado, dirección de entrega, método de pago, total |
detalles_orden | Líneas de cada orden (producto, variante, cantidad, precio, subtotal) |
materia_prima | Inventario de insumos (harina, azúcar, huevos, etc.) con stock |
receta_fija | Cuánto insumo usa cada variante de producto |
insumos_personalizados_orden | Insumos extra para pedidos personalizados |
productos | Segunda tabla de catálogo con imagen binaria (tabla legacy) |
comentarios | Reseñas de clientes con flag de aprobación |
Triggers automáticos en MySQL
-- 1. tr_calculo_subtotal
-- Al insertar un detalle de orden, calcula automáticamente el subtotal
-- (cantidad × precio) sin que el backend lo tenga que hacer.
BEFORE INSERT ON detalles_orden
SET NEW.detoSubTotal = NEW.detoCantidad * NEW.detoPrecio;
-- 2. tr_descuento_stock_estandar
-- Al confirmar un pedido estándar, descuenta del stock de materia_prima
-- usando la receta_fija de cada variante pedida.
AFTER INSERT ON detalles_orden
UPDATE materia_prima ... JOIN receta_fija ...
-- 3. tr_actualizar_total_orden
-- Cada vez que se agrega un detalle, recalcula el total de la orden
-- sumando todos los subtotales.
AFTER INSERT ON detalles_orden
UPDATE orden SET ordTotal = SUM(detoSubTotal) ...
-- 4. tr_reponer_stock_borrado
-- Si se borra un detalle de orden (cancelación), devuelve el stock
-- de materia prima que se había descontado.
AFTER DELETE ON detalles_orden
UPDATE materia_prima ... (suma de vuelta)
-- 5. tr_descuento_stock_personalizado
-- Para pedidos personalizados, descuenta los insumos específicos
-- registrados en insumos_personalizados_orden.
AFTER INSERT ON insumos_personalizados_orden
UPDATE materia_prima SET matStock = matStock - NEW.cantidad_usada
☕ Backend — Spring Boot
Dependencias clave (pom.xml)
<!-- Spring Boot Core: servidor web, JPA, seguridad, validación y email -->
<dependency>spring-boot-starter-web</dependency>
<dependency>spring-boot-starter-data-jpa</dependency>
<dependency>spring-boot-starter-security</dependency>
<dependency>spring-boot-starter-validation</dependency>
<dependency>spring-boot-starter-mail</dependency>
<!-- Conecta con MySQL -->
<dependency>mysql-connector-j</dependency>
<!-- JWT para tokens de autenticación (versión 0.11.5) -->
<dependency>jjwt-api / jjwt-impl / jjwt-jackson</dependency>
<!-- Google Guava: utilidades de colecciones -->
<dependency>guava</dependency>
<!-- Apache Commons: utilidades de texto y validación -->
<dependency>commons-lang3 / commons-validator / commons-collections4</dependency>
<!-- Apache POI: exportar reportes a Excel (.xlsx) -->
<dependency>poi / poi-ooxml</dependency>
<!-- Lombok: genera getters/setters/constructores automáticamente -->
<dependency>lombok</dependency>
<!-- H2: base de datos en memoria solo para tests -->
<dependency>h2 (scope test)</dependency>
🔐 Seguridad — SecurityConfig.java
/**
* Configura toda la seguridad HTTP de la aplicación.
* Conecta con: JwtAuthFilter (intercepta cada request) y
* CustomUserDetailsService (carga el usuario desde la BD).
*
* Sin sesiones en servidor — usa JWT stateless.
* CSRF desactivado porque el frontend es React (no forms HTML tradicionales).
*
* CORS: acepta solicitudes solo del origen configurado en application.properties
* (variable cors.allowed-origins), típicamente http://localhost:3000.
*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // habilita @PreAuthorize en los controladores
public class SecurityConfig {
// Rutas completamente públicas (sin token):
// POST /api/auth/registro, /login, /olvide-contrasena, /restablecer-contrasena
// POST /api/admin/auth/verificar-admin, /pin ← login de 2 pasos del admin
// GET /api/productos/**, /api/comentarios/aprobados/**, /api/ofertas/vigentes
// GET /uploads/** ← imágenes subidas
// Solo ADMIN (rol=1):
// /api/admin/**
// DELETE/POST/PUT /api/productos/**
// PUT /api/comentarios/*/aprobar
// CLIENTE o ADMIN autenticados (con JWT válido):
// /api/perfil/**, /api/direcciones/**, /api/metodos-pago/**
// /api/ordenes/**, POST /api/comentarios/**
// Contraseñas hasheadas con BCrypt (sin texto plano en ningún momento)
@Bean
public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
}
🔑 Seguridad JWT — Security/
// ── JwtUtil.java ──────────────────────────────────────────────
// Genera y valida tokens JWT.
// La clave secreta se lee de application.properties (jwt.secret).
// Expiración configurable (jwt.expiration-ms, por defecto 24h).
// Extrae el correo del usuario desde el token para identificarlo.
// ── JwtAuthFilter.java ────────────────────────────────────────
// Filtro que corre ANTES de cada request HTTP.
// Lee el header "Authorization: Bearer <token>".
// Si el token es válido, carga el usuario y lo pone en el contexto
// de seguridad de Spring — así los controladores saben quién hizo la petición.
// ── CustomUserDetailsService.java ─────────────────────────────
// Implementa UserDetailsService de Spring Security.
// Conecta con UsuarioRepository para buscar el usuario por correo.
// Convierte la entidad Usuario en un UserDetails que Spring entiende,
// incluyendo el rol como autoridad (ROLE_ADMIN o ROLE_CLIENTE).
📦 Modelos / Entidades — Modelo/
// ── Usuario.java ──────────────────────────────────────────────
// Tabla: usuario
// Campos clave: correo (único), contrasena (BCrypt), resetToken (recuperación)
// Relaciones:
// → ManyToOne con Rol (Admin o Cliente)
// → OneToMany con Direccion (varias direcciones de envío)
// → OneToMany con MetodoPago (varios métodos guardados)
// → OneToMany con Orden (historial de compras)
// ── Producto.java ─────────────────────────────────────────────
// Tabla: producto
// Un producto (ej: "Cupcakes Especiales") pertenece a una Categoría
// y tiene N variantes (sabores/tamaños) en ProductoVariante.
// También tiene campos de catálogo: descripción, precio, imagenUrl.
// ── ProductoVariante.java ─────────────────────────────────────
// Tabla: producto_variantes
// Cada variante (ej: "Chocolate S/ 7.50") tiene un precioAdicional
// y está ligada a la receta de insumos en receta_fija.
// ── Orden.java ───────────────────────────────────────────────
// Tabla: orden
// Representa un pedido completo del cliente.
// Estados: Pendiente → Preparando → Enviado → Entregado | Cancelado
// Métodos de pago aceptados: Efectivo, Transferencia, Tarjeta, Yape
// → OneToMany con DetalleOrden (los productos del pedido)
// ── Personal.java ─────────────────────────────────────────────
// Tabla: personal
// Empleados del negocio: Administrador, Repostero, Repartidor, Atencion, Caja
// → OneToMany con HorarioPersonal (turnos asignados)
// ── Comentario.java ───────────────────────────────────────────
// Tabla: comentarios
// Reseña de un cliente. Empieza sin aprobar.
// El admin la revisa y la aprueba — solo entonces se muestra en el frontend.
🎮 Controladores REST — Controlador/
// ── AuthController.java ───────────────────────────────────────
// Ruta base: /api/auth
// Conecta con: AuthService (lógica), AuthServiceImpl
//
// POST /registro → registra nuevo cliente, hashea contraseña, asigna rol=Cliente
// POST /login → valida credenciales con BCrypt, devuelve JWT
// POST /olvide-contrasena → genera token de recuperación y lo envía por email
// POST /restablecer-contrasena → cambia la contraseña usando el token del email
// ── AdminAuthController.java ──────────────────────────────────
// Ruta base: /api/admin/auth
// Login en 2 pasos para el administrador:
// Paso 1: POST /verificar-admin → verifica que sea ADMIN válido (correo + contraseña)
// Paso 2: POST /pin → valida el PIN de 2do factor, emite JWT con rol ADMIN
// ── ProductoController.java ───────────────────────────────────
// Ruta base: /api/productos
// Conecta con: ProductoRepository (directo a BD)
//
// GET / → lista todos los productos (público)
// GET /{id} → detalle de un producto (público)
// GET /buscar?q= → busca por nombre, case-insensitive (público)
// GET /categoria/{catId} → filtra por categoría (público)
// POST /guardar → crea producto con imagen (solo ADMIN)
// ↳ Guarda la imagen en disco (directorio configurado en uploads.directory)
// ↳ Registra la URL "/uploads/nombreArchivo" en la BD
// PUT /{id} → actualiza nombre/precio/descripción (solo ADMIN)
// DELETE /{id} → elimina producto (solo ADMIN, registra log de warning)
// ── CarritoController.java ────────────────────────────────────
// Ruta base: /api/carrito
// IMPORTANTE: el carrito se guarda en memoria del servidor (lista estática),
// no en BD. Se pierde si el servidor reinicia.
//
// GET / → devuelve los ítems actuales del carrito
// POST /agregar → agrega producto; si ya existe, incrementa cantidad
// POST /pagar → confirma el pago y vacía el carrito
// DELETE /limpiar → vacía el carrito sin pagar
// ── OrdenController.java ─────────────────────────────────────
// Ruta base: /api/ordenes
// Conecta con: OrdenService → OrdenRepository + UsuarioRepository
//
// POST / → crea una nueva orden (cli