Backend Spring Boot para el mini e-commerce TechStore Pro.
- Java 21
- Spring Boot 4
- Spring Security + JWT
- Spring Data JPA
- H2 en memoria para desarrollo
- SpringDoc OpenAPI / Swagger UI
- Maven Wrapper
El backend esta organizado por dominio y cada dominio separa su responsabilidad interna:
src/main/java/com/techstore/backend
|-- auth
| |-- api # Controladores y DTOs
| `-- application # Casos de uso de autenticacion
|-- cart
| |-- api
| |-- application
| |-- domain
| `-- infrastructure
|-- product
| |-- api
| |-- application
| |-- domain
| `-- infrastructure
|-- order
| |-- api
| |-- application
| |-- domain
| `-- infrastructure
|-- user
| |-- api
| |-- domain
| `-- infrastructure
|-- config # Security, OpenAPI, propiedades y seed data
`-- common # Excepciones y respuestas de error
.\mvnw.cmd spring-boot:runAPI local:
http://localhost:8080
Consola H2:
http://localhost:8080/h2-console
JDBC URL: jdbc:h2:mem:techstore
User: sa
Password:
Swagger UI:
http://localhost:8080/swagger-ui.html
OpenAPI JSON:
http://localhost:8080/v3/api-docs
El backend detecta PostgreSQL automaticamente cuando no defines un perfil explicito:
- Si PostgreSQL responde con las credenciales de
.env, usa PostgreSQL. - Si PostgreSQL no responde, usa H2 en memoria.
- Si defines
SPRING_PROFILES_ACTIVE, se respeta ese perfil y no se aplica la deteccion automatica.
Para usar PostgreSQL local en Docker:
- Crear el archivo local de variables:
Copy-Item .env.example .env- Levantar PostgreSQL:
docker compose up -d- Ejecutar el backend:
.\mvnw.cmd spring-boot:runSi quieres forzar PostgreSQL sin autodeteccion:
$env:SPRING_PROFILES_ACTIVE="postgres"
.\mvnw.cmd spring-boot:runSi quieres desactivar la autodeteccion y usar H2 aunque Docker este prendido:
$env:APP_DATASOURCE_AUTO_DETECT="false"
.\mvnw.cmd spring-boot:runComandos utiles:
docker compose ps
docker compose logs -f postgres
docker compose downPara borrar tambien los datos persistidos de PostgreSQL:
docker compose down -vAdmin:
email: admin@techstore.com
password: admin123
Cliente:
email: cliente@techstore.com
password: cliente123
POST /auth/register
POST /auth/loginBody de login:
{
"email": "cliente@techstore.com",
"password": "cliente123"
}La respuesta incluye un JWT. Para endpoints protegidos:
Authorization: Bearer <token>El login con Google usa variables de entorno. No guardar el Client Secret en el repositorio.
Variables:
$env:GOOGLE_CLIENT_ID="<tu-client-id>"
$env:GOOGLE_CLIENT_SECRET="<tu-client-secret>"
$env:OAUTH2_SUCCESS_REDIRECT_URI="http://localhost:4200/auth/oauth2/success"
$env:OAUTH2_FAILURE_REDIRECT_URI="http://localhost:4200/login"Tambien puedes poner esas variables en .env. El backend importa automaticamente ese archivo cuando se ejecuta desde la carpeta backend o desde la carpeta padre del proyecto.
En Google Cloud, el redirect URI autorizado debe ser:
http://localhost:8080/login/oauth2/code/google
Para iniciar el flujo desde Angular, redirigir el navegador a:
http://localhost:8080/oauth2/authorization/google
Si Google autentica correctamente, el backend crea o reutiliza el usuario por email, genera el JWT propio del sistema y redirige al frontend:
http://localhost:4200/auth/oauth2/success?token=<jwt>&tokenType=Bearer
El frontend debe tomar ese token y usarlo igual que el token devuelto por POST /auth/login.
GET /productos?page=0&size=10&sort=name,asc
GET /productos?q=mouse&category=Mouse&minPrice=50&maxPrice=120&stockStatus=IN_STOCK&page=0&size=10
GET /productos?includeInactive=true&active=false&page=0&size=10 ADMIN
GET /productos/{id}
POST /productos ADMIN
PUT /productos/{id} ADMIN
DELETE /productos/{id} ADMINGET /productos devuelve una pagina. La respuesta incluye content, totalElements, totalPages, size y page.
Filtros disponibles:
q Busca por nombre o descripcion
category Categoria exacta
minPrice Precio minimo
maxPrice Precio maximo
stockStatus IN_STOCK, OUT_OF_STOCK o LOW_STOCK
active true/false, solo administradores
includeInactive true/false, solo administradores
createdFrom Fecha inicial yyyy-MM-dd
createdTo Fecha final yyyy-MM-dd
page,size,sort Paginacion y ordenamiento
Body para crear/editar producto:
{
"name": "Teclado Gamer",
"category": "Teclados",
"description": "Teclado mecanico compacto",
"price": 149.9,
"stock": 15,
"active": true
}GET /carrito
PUT /carrito/items/{productId}
DELETE /carrito/items/{productId}
DELETE /carrito/itemsBody para crear o reemplazar la cantidad:
{
"quantity": 2
}POST /pedidos
GET /pedidos?page=0&size=10
GET /pedidos?status=CONFIRMED&productName=mouse&minTotal=50&maxTotal=120&page=0&size=10
GET /pedidos?scope=all&userEmail=cliente&from=2026-05-01&to=2026-05-31&page=0&size=10 ADMIN
GET /pedidos/{id}
PATCH /pedidos/{id}/status ADMINPOST /pedidos confirma el carrito actual, valida stock, descuenta inventario y limpia el carrito.
PATCH /pedidos/{id}/status permite cambiar el estado del pedido. Al cancelar devuelve stock; al reconfirmar valida stock y lo descuenta.
Filtros disponibles:
scope mine o all. all solo administradores
status CONFIRMED o CANCELLED
userName Busca por nombre de usuario, solo administradores
userEmail Busca por email de usuario, solo administradores
productName Busca pedidos que contengan un producto por nombre
productId Busca pedidos que contengan un producto por id
from Fecha inicial yyyy-MM-dd
to Fecha final yyyy-MM-dd
minTotal Total minimo
maxTotal Total maximo
page,size,sort Paginacion y ordenamiento
Body para cambiar estado:
{
"status": "CANCELLED"
}.\mvnw.cmd test