Overview
The TechStore admin dashboard provides comprehensive tools for managing the store, tracking sales performance, and generating detailed reports. Administrators have full access to order management, user administration, and analytics.
All admin dashboard features require ROLE_ADMIN authentication. Ensure users are assigned the correct role.
Admin Access Control
The security configuration restricts sensitive operations to administrators:
. authorizeHttpRequests (auth -> auth
// Admin-only routes
. requestMatchers ( "/api/usuarios/**" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . GET , "/api/pedidos" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . PUT , "/api/pedidos/**" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . DELETE , "/api/pedidos/**" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . POST , "/api/productos/**" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . PUT , "/api/productos/**" ). hasAuthority ( "ROLE_ADMIN" )
. requestMatchers ( HttpMethod . DELETE , "/api/productos/**" ). hasAuthority ( "ROLE_ADMIN" )
. anyRequest (). authenticated ()
)
Sales Management
View All Orders
GET /api/pedidos
Authorization : Bearer {admin-token}
Returns all orders across all customers:
@ GetMapping
public List < Pedido > listarTodos () {
return pedidoService . obtenerTodosLosPedidos ();
}
Response Example :
[
{
"id" : 42 ,
"usuario" : {
"id" : 5 ,
"nombre" : "John Doe" ,
"email" : "john@example.com"
},
"fechaPedido" : "2026-03-05T10:30:00" ,
"estado" : "PENDIENTE" ,
"total" : 1599.99 ,
"detalles" : [
{
"producto" : { "nombre" : "MacBook Pro" },
"cantidad" : 1 ,
"precioUnitario" : 1599.99
}
]
},
...
]
Update Order Status
Admins can manage order fulfillment by updating statuses:
PUT /api/pedidos/{id}/estado?nuevoEstado={status}
Authorization : Bearer {admin-token}
Available Statuses :
PENDIENTE - Awaiting processing
PAGADO - Payment confirmed
ENVIADO - Shipped to customer
ENTREGADO - Successfully delivered
CANCELADO - Order cancelled (auto-restores stock)
Example : PUT /api/pedidos/42/estado?nuevoEstado=ENVIADO
@ PutMapping ( "/{id}/estado" )
public ResponseEntity < Pedido > actualizarEstado (
@ PathVariable Long id,
@ RequestParam String nuevoEstado
) {
Pedido pedidoActualizado = pedidoService . actualizarEstado (id, nuevoEstado);
return ResponseEntity . ok (pedidoActualizado);
}
Changing status to CANCELADO automatically returns products to inventory.
Delete Orders
DELETE /api/pedidos/{id}
Authorization : Bearer {admin-token}
Permanently removes an order from the system:
@ DeleteMapping ( "/{id}" )
public ResponseEntity < ? > eliminar (@ PathVariable Long id) {
try {
pedidoService . eliminarPedido (id);
return ResponseEntity . ok (). body ( "Pedido eliminado correctamente" );
} catch ( Exception e ) {
return ResponseEntity . status ( HttpStatus . INTERNAL_SERVER_ERROR )
. body ( "Error al eliminar el pedido" );
}
}
Deleting an order does NOT restore stock. Cancel the order first if inventory adjustment is needed.
Sales Analytics
Key Metrics Dashboard
Build your dashboard frontend by querying the orders API and calculating:
Total Revenue Sum of total field across all completed orders
Order Count Total number of orders in the system
Average Order Value Total revenue divided by number of orders
Orders by Status Count of orders grouped by status field
Example Analytics Calculations
// Fetch all orders
const orders = await fetch ( '/api/pedidos' , {
headers: { 'Authorization' : `Bearer ${ adminToken } ` }
}). then ( res => res . json ());
// Total Revenue
const totalRevenue = orders . reduce (( sum , order ) => sum + order . total , 0 );
// Average Order Value
const avgOrderValue = totalRevenue / orders . length ;
// Orders by Status
const statusCounts = orders . reduce (( acc , order ) => {
acc [ order . estado ] = ( acc [ order . estado ] || 0 ) + 1 ;
return acc ;
}, {});
// Recent Orders (last 30 days)
const thirtyDaysAgo = new Date ();
thirtyDaysAgo . setDate ( thirtyDaysAgo . getDate () - 30 );
const recentOrders = orders . filter ( order =>
new Date ( order . fechaPedido ) >= thirtyDaysAgo
);
// Top Products (requires aggregating order details)
const productSales = {};
orders . forEach ( order => {
order . detalles . forEach ( detalle => {
const prodName = detalle . producto . nombre ;
productSales [ prodName ] = ( productSales [ prodName ] || 0 ) + detalle . cantidad ;
});
});
PDF Sales Reports
Generate comprehensive sales reports in PDF format:
POST /api/pedidos/reporte/pdf
Authorization : Bearer {admin-token}
Content-Type : application/json
Request Body (send filtered orders):
[
{
"id" : 1 ,
"fechaPedido" : "2026-03-01T10:30:00" ,
"usuario" : {
"nombre" : "John" ,
"apellido" : "Doe" ,
"email" : "john@example.com"
},
"estado" : "ENTREGADO" ,
"total" : 1599.99
},
{
"id" : 2 ,
"fechaPedido" : "2026-03-02T14:15:00" ,
"usuario" : {
"nombre" : "Jane" ,
"apellido" : "Smith" ,
"email" : "jane@example.com"
},
"estado" : "ENVIADO" ,
"total" : 899.50
}
]
Implementation :
@ PostMapping ( "/reporte/pdf" )
public ResponseEntity < byte [] > descargarReporte (
@ RequestBody List < Pedido > pedidosFiltrados
) {
byte [] pdf = pedidoReporteService . generarReportePedidos (pedidosFiltrados);
HttpHeaders headers = new HttpHeaders ();
headers . setContentType ( MediaType . APPLICATION_PDF );
headers . setContentDispositionFormData ( "attachment" , "reporte-ventas.pdf" );
return new ResponseEntity <>(pdf, headers, HttpStatus . OK );
}
Report Contents
The PDF includes:
Header : “TECHSTORE - REPORTE DE VENTAS”
Order Table :
ID
Fecha (Order date)
Cliente (Customer name or email)
Estado (Order status)
Total (Order amount)
Summary : Grand total of all orders in the report
Filtering Reports
Date Range
By Status
By Customer
Revenue Threshold
Filter orders by date before sending to PDF endpoint: const startDate = new Date ( '2026-03-01' );
const endDate = new Date ( '2026-03-31' );
const filteredOrders = orders . filter ( order => {
const orderDate = new Date ( order . fechaPedido );
return orderDate >= startDate && orderDate <= endDate ;
});
// Send to PDF endpoint
const response = await fetch ( '/api/pedidos/reporte/pdf' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ adminToken } `
},
body: JSON . stringify ( filteredOrders )
});
const blob = await response . blob ();
const url = window . URL . createObjectURL ( blob );
const a = document . createElement ( 'a' );
a . href = url ;
a . download = 'sales-report-march-2026.pdf' ;
a . click ();
Generate reports for specific order statuses: const completedOrders = orders . filter ( order =>
order . estado === 'ENTREGADO'
);
// Generate PDF for completed orders only
Create customer-specific reports: const customerOrders = orders . filter ( order =>
order . usuario . id === customerId
);
// Generate PDF for specific customer
Filter high-value orders: const highValueOrders = orders . filter ( order =>
order . total >= 1000
);
// Generate PDF for orders over $1000
Always filter data client-side before sending to the PDF endpoint for maximum flexibility.
Product Management
Create Products
POST /api/productos
Authorization : Bearer {admin-token}
Add new products to the catalog:
{
"nombre" : "iPhone 15 Pro" ,
"descripcion" : "Latest flagship smartphone" ,
"precio" : 999.99 ,
"stock" : 50 ,
"imagenUrl" : "https://example.com/iphone.jpg" ,
"destacado" : true ,
"categoria" : { "id" : 1 }
}
Update Products
PUT /api/productos/{id}
Authorization : Bearer {admin-token}
Modify product details, pricing, or stock levels.
Manage Image Gallery
PUT /api/productos/{id}/galeria
Authorization : Bearer {admin-token}
Update product image galleries:
[
"https://example.com/image1.jpg" ,
"https://example.com/image2.jpg" ,
"https://example.com/image3.jpg"
]
Delete Products
DELETE /api/productos/{id}
Authorization : Bearer {admin-token}
Soft delete (marks as inactive):
DELETE /api/productos/{id}/definitivo
Permanent deletion.
User Management
List All Users
GET /api/usuarios
Authorization : Bearer {admin-token}
Returns all registered users:
@ GetMapping
public ResponseEntity < List < Usuario >> getAllUsers () {
return ResponseEntity . ok ( usuarioService . findAllUsers ());
}
Get User Details
GET /api/usuarios/{id}
Authorization : Bearer {admin-token}
View complete user profile including order history.
Delete User Account
DELETE /api/usuarios/{id}
Authorization : Bearer {admin-token}
Permanently removes a user account:
@ DeleteMapping ( "/{id}" )
public ResponseEntity < Void > deleteUser (@ PathVariable Long id) {
usuarioService . deleteUser (id);
return ResponseEntity . noContent (). build ();
}
Deleting users may impact related orders. Consider soft-delete alternatives for user accounts with order history.
Dashboard UI Recommendations
Overview Cards
Display key metrics: Total Revenue, Order Count, Average Order Value, Low Stock Products
Recent Orders Table
Show latest 10 orders with quick status update buttons
Charts & Graphs
Visualize:
Revenue over time (line chart)
Orders by status (pie chart)
Top selling products (bar chart)
Sales by category (donut chart)
Quick Actions
Buttons for:
Add New Product
Generate Report
View All Orders
Manage Users
Filters & Search
Date range pickers, status filters, customer search
Admin API Reference
Resource Method Endpoint Description Orders GET /api/pedidosList all orders GET /api/pedidos/{id}View order details PUT /api/pedidos/{id}/estadoUpdate order status DELETE /api/pedidos/{id}Delete order POST /api/pedidos/reporte/pdfGenerate PDF report Products POST /api/productosCreate product PUT /api/productos/{id}Update product PUT /api/productos/{id}/galeriaUpdate gallery DELETE /api/productos/{id}Soft delete DELETE /api/productos/{id}/definitivoHard delete Users GET /api/usuariosList all users GET /api/usuarios/{id}View user details DELETE /api/usuarios/{id}Delete user
All admin endpoints require the Authorization: Bearer {token} header with a valid admin token.
Best Practices
Role Verification Always verify admin role on both frontend and backend to prevent unauthorized access.
Audit Logging Log admin actions (order updates, deletions) for security and compliance.
Data Validation Validate all inputs before updating orders or products to maintain data integrity.
Report Caching Cache frequently generated reports to improve performance.
Security Considerations
Critical Security Measures :
Token Expiration : Admin tokens should expire after inactivity
IP Whitelisting : Consider restricting admin access to specific IPs
Two-Factor Authentication : Implement 2FA for admin accounts
Action Confirmation : Require confirmation for destructive operations
Session Management : Automatically log out inactive admin sessions
Example: Building a Sales Summary
class AdminDashboard {
constructor ( adminToken ) {
this . token = adminToken ;
this . baseUrl = '/api' ;
}
async fetchOrders () {
const response = await fetch ( ` ${ this . baseUrl } /pedidos` , {
headers: { 'Authorization' : `Bearer ${ this . token } ` }
});
return response . json ();
}
async getSalesSummary () {
const orders = await this . fetchOrders ();
return {
totalOrders: orders . length ,
totalRevenue: orders . reduce (( sum , o ) => sum + o . total , 0 ),
averageOrderValue: orders . reduce (( sum , o ) => sum + o . total , 0 ) / orders . length ,
ordersByStatus: orders . reduce (( acc , o ) => {
acc [ o . estado ] = ( acc [ o . estado ] || 0 ) + 1 ;
return acc ;
}, {}),
todaysOrders: orders . filter ( o =>
new Date ( o . fechaPedido ). toDateString () === new Date (). toDateString ()
). length ,
pendingOrders: orders . filter ( o => o . estado === 'PENDIENTE' ). length
};
}
async generateMonthlyReport ( year , month ) {
const orders = await this . fetchOrders ();
const filtered = orders . filter ( order => {
const date = new Date ( order . fechaPedido );
return date . getFullYear () === year && date . getMonth () === month ;
});
const response = await fetch ( ` ${ this . baseUrl } /pedidos/reporte/pdf` , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ this . token } `
},
body: JSON . stringify ( filtered )
});
return response . blob ();
}
}
// Usage
const dashboard = new AdminDashboard ( adminToken );
const summary = await dashboard . getSalesSummary ();
console . log ( `Total Revenue: $ ${ summary . totalRevenue . toFixed ( 2 ) } ` );
console . log ( `Pending Orders: ${ summary . pendingOrders } ` );