Skip to main content
The admin area is a set of server-rendered Blade views protected by Laravel’s built-in 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 in routes/web.php:
Route::middleware(['auth', 'verified'])->group(function () {
    // dashboard, quotes, blocks, profile
});
Attempting to access any admin URL without a valid session redirects to the login page. Attempting to access with an unverified email redirects to the email verification notice.

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:
VariableDescription
total_quotesAll-time quote count
total_blocksTotal quote blocks in the system
active_blocksQuote blocks where is_active = true
total_categoriesTotal block categories
monthly_quotesQuotes created this calendar month
last_month_quotesQuotes created last calendar month
monthly_incomeSum of total for this month’s quotes
last_month_incomeSum of total for last month’s quotes
monthly_hoursSum of total_hours for this month’s quotes
sent_this_monthQuotes 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:
Quote::selectRaw("
    DATE_FORMAT(created_at, '%b %Y') as month_label,
    YEAR(created_at)  as year_num,
    MONTH(created_at) as month_num,
    COUNT(*)          as total_quotes,
    SUM(total)        as total_income
")
->where('created_at', '>=', now()->subMonths(5)->startOfMonth())
->groupByRaw("year_num, month_num, month_label")
->orderByRaw("year_num ASC, month_num ASC")
->get();

Top 5 blocks ($topBlocks)

The five most-used quote blocks ranked by how many times they appear in quote_items:
FieldDescription
idBlock primary key
nameBlock display name
usage_countNumber of QuoteItem rows referencing this block
total_generatedSum 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):
EndpointMethodDescription
/api/v1/quotes/statisticsGETAggregate counts, totals, and top clients
/api/v1/quotes/recentGETMost recent quotes with their items
These endpoints require a valid Sanctum token (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

/admin/cotizaciones?status=sent&q=startup
Both parameters are applied together: the query first filters by status, then applies the search across the remaining results.

Quote detail

GET /admin/cotizaciones/{quote} renders admin.quotes.show. The controller eager-loads:
  • items.block — each QuoteItem with its originating QuoteBlock
  • replies — all QuoteReply records ordered by sent_at descending
From the detail view, admins can:
  • 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
See Quote Management for the full reply and status update flows.

Block management

Service blocks and their categories are managed at GET /bloques, which renders bloques.index. Block management is a standard Laravel resource controller (QuoteBlockController) registered as:
Route::resource('bloques', QuoteBlockController::class);
Admins can create, edit, and delete individual blocks. Each block belongs to a category.
FieldTypeRequiredNotes
namestringYesMax 255 chars
descriptiontextNo
category_idintegerYesMust exist in quote_block_categories
base_pricenumericYesMin 0
default_hoursintegerYesMin 0
is_activebooleanNoDefaults to true
config (extras)arrayNoKey-value pairs stored as JSON
New blocks are automatically assigned an order value of max(order) + 1 within their category.Blocks can be reordered via POST /bloques/reorder (handled by QuoteBlockController::reorder()), which accepts:
{
  "blocks": [
    { "id": 12, "order": 1 },
    { "id": 7,  "order": 2 }
  ]
}

Views reference

View pathRoute
dashboard.blade.phpGET /dashboard
admin/quotes/index.blade.phpGET /admin/cotizaciones
admin/quotes/show.blade.phpGET /admin/cotizaciones/{quote}
bloques/index.blade.phpGET /bloques
bloques/create.blade.phpGET /bloques/create
bloques/edit.blade.phpGET /bloques/{bloque}/edit

Admin route reference

MethodURIMiddlewareDescription
GET/dashboardauth, verifiedDashboard home
GET/admin/cotizacionesauth, verifiedQuote list
GET/admin/cotizaciones/{quote}auth, verifiedQuote detail
PATCH/admin/cotizaciones/{quote}/statusauth, verifiedUpdate status
POST/admin/cotizaciones/{quote}/replyauth, verifiedSend reply/meeting
GET/admin/cotizaciones/{quote}/pdfauth, verifiedDownload PDF
GET/bloquesauth, verifiedBlock list
GET/bloques/createauth, verifiedNew block form
POST/bloquesauth, verifiedStore new block
GET/bloques/{bloque}/editauth, verifiedEdit block form
PUT/PATCH/bloques/{bloque}auth, verifiedUpdate block
DELETE/bloques/{bloque}auth, verifiedDelete block
POST/bloques/categoriasauth, verifiedStore new category
GET/api/v1/quotes/statisticsauth:sanctumPipeline stats
GET/api/v1/quotes/recentauth:sanctumRecent quotes

Build docs developers (and LLMs) love