auth and verified middleware. Only authenticated users with a verified email address can access these routes.
Access control
All admin routes are wrapped in the following middleware group defined inroutes/web.php:
Dashboard overview
GET /dashboard is handled by DashboardController@index and renders dashboard.blade.php. The dashboard is the landing page after login.
The controller gathers four datasets — all cached for 5 minutes (300 seconds) — and passes them to the view:
KPI statistics ($stats)
Core business metrics comparing the current month against the previous month:
| Variable | Description |
|---|---|
total_quotes | All-time quote count |
total_blocks | Total quote blocks in the system |
active_blocks | Quote blocks where is_active = true |
total_categories | Total block categories |
monthly_quotes | Quotes created this calendar month |
last_month_quotes | Quotes created last calendar month |
monthly_income | Sum of total for this month’s quotes |
last_month_income | Sum of total for last month’s quotes |
monthly_hours | Sum of total_hours for this month’s quotes |
sent_this_month | Quotes with a sent_at timestamp in the current month |
6-month chart data ($chartData)
Aggregated per-month quote counts and revenue for the last 6 calendar months, suitable for rendering a bar or line chart:
Top 5 blocks ($topBlocks)
The five most-used quote blocks ranked by how many times they appear in quote_items:
| Field | Description |
|---|---|
id | Block primary key |
name | Block display name |
usage_count | Number of QuoteItem rows referencing this block |
total_generated | Sum of total_price across all items for this block |
Recent activity ($recentQuotes)
The 5 most recently created quotes, containing: id, reference, client_name, client_email, total, status, created_at.
Statistics API
The dashboard Blade view can optionally fetch live stats via the Sanctum-protected JSON API (useful for SPA-style dashboard widgets):| Endpoint | Method | Description |
|---|---|---|
/api/v1/quotes/statistics | GET | Aggregate counts, totals, and top clients |
/api/v1/quotes/recent | GET | Most recent quotes with their items |
auth:sanctum middleware). See Admin Quotes API for full response shapes.
Quote list
GET /admin/cotizaciones renders admin.quotes.index. It supports filtering and search via query parameters.
Filter by status
Append
?status=draft, ?status=sent, ?status=accepted, ?status=rejected, or ?status=expired to narrow the list to a single status.Search
Append
?q=text to search across client_name, client_email, and reference using a LIKE query.Pagination
Results are paginated at 15 records per page, ordered by
created_at descending. The query string is preserved across pages.Item count
Each row includes the number of line items on the quote via
withCount('items').Combining filters
Quote detail
GET /admin/cotizaciones/{quote} renders admin.quotes.show. The controller eager-loads:
items.block— eachQuoteItemwith its originatingQuoteBlockreplies— allQuoteReplyrecords ordered bysent_atdescending
- Update the quote status via
PATCH /admin/cotizaciones/{quote}/status - Schedule a meeting and send an email reply via
POST /admin/cotizaciones/{quote}/reply - Download the quote PDF via
GET /admin/cotizaciones/{quote}/pdf
Block management
Service blocks and their categories are managed atGET /bloques, which renders bloques.index. Block management is a standard Laravel resource controller (QuoteBlockController) registered as:
- Blocks
- Categories
Admins can create, edit, and delete individual blocks. Each block belongs to a category.
New blocks are automatically assigned an
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Max 255 chars |
description | text | No | — |
category_id | integer | Yes | Must exist in quote_block_categories |
base_price | numeric | Yes | Min 0 |
default_hours | integer | Yes | Min 0 |
is_active | boolean | No | Defaults to true |
config (extras) | array | No | Key-value pairs stored as JSON |
order value of max(order) + 1 within their category.Blocks can be reordered via POST /bloques/reorder (handled by QuoteBlockController::reorder()), which accepts:Views reference
| View path | Route |
|---|---|
dashboard.blade.php | GET /dashboard |
admin/quotes/index.blade.php | GET /admin/cotizaciones |
admin/quotes/show.blade.php | GET /admin/cotizaciones/{quote} |
bloques/index.blade.php | GET /bloques |
bloques/create.blade.php | GET /bloques/create |
bloques/edit.blade.php | GET /bloques/{bloque}/edit |
Admin route reference
| Method | URI | Middleware | Description |
|---|---|---|---|
GET | /dashboard | auth, verified | Dashboard home |
GET | /admin/cotizaciones | auth, verified | Quote list |
GET | /admin/cotizaciones/{quote} | auth, verified | Quote detail |
PATCH | /admin/cotizaciones/{quote}/status | auth, verified | Update status |
POST | /admin/cotizaciones/{quote}/reply | auth, verified | Send reply/meeting |
GET | /admin/cotizaciones/{quote}/pdf | auth, verified | Download PDF |
GET | /bloques | auth, verified | Block list |
GET | /bloques/create | auth, verified | New block form |
POST | /bloques | auth, verified | Store new block |
GET | /bloques/{bloque}/edit | auth, verified | Edit block form |
PUT/PATCH | /bloques/{bloque} | auth, verified | Update block |
DELETE | /bloques/{bloque} | auth, verified | Delete block |
POST | /bloques/categorias | auth, verified | Store new category |
GET | /api/v1/quotes/statistics | auth:sanctum | Pipeline stats |
GET | /api/v1/quotes/recent | auth:sanctum | Recent quotes |