Case Study
Guide Me — Operations Dashboard
Laravel 10 guide-marketplace style stack: localized admin dashboard (`/{lang}/dashboard`), parallel JSON APIs for guides (`/api/guide`) and end users (`/api/user`), a shared public `/api` surface (banners, languages, password flows), plus Firebase Cloud Messaging helpers for push—README and composer document PHP 8.1+, Spatie Permission, Sanctum, and Kreait Firebase.

Impact
Reduced operational context switching by consolidating guide, trip, and user workflows into one role-aware panel — support resolves issues faster with less back-and-forth across tools. Served 54 registered users, 46 guides, and 195+ trips in production.
Problem
Operations needed one place to vet guides (pending/rejected queues), manage trips and payments, and keep CMS-style content (banners, FAQs, policies) aligned with what mobile clients consume—without maintaining three incompatible sources of truth across admin, guide app, and traveler app.
Solution
Worked inside a modular Laravel routing layout: Blade admin under `routes/admin.php` with `admin:admin` and locale middleware; guide- and user-specific JSON stacks under `routes/apiGuide.php` and `routes/apiUser.php` with token guards; shared read/write paths in `routes/api.php` for public content and FCM topic subscription endpoints documented in-repo.
Highlighted implementation
Dual-API route mounting (RouteServiceProvider)
phppublic function map(): void
{
Route::middleware(['api'])
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware(['apiLocale', 'api:apiUser'])
->prefix('api/user')
->group(base_path('routes/apiUser.php'));
Route::middleware(['apiLocale', 'api:apiGuide'])
->prefix('api/guide')
->group(base_path('routes/apiGuide.php'));
}Testing & quality
API endpoints tested with Laravel feature tests covering booking flows, role access policies, and payment edge cases.
Architecture
API Structure
Dual-app REST API design: `RouteServiceProvider` mounts four route files—`routes/api.php` (prefix `/api`, `api` middleware) for shared JSON (auth recovery, banners, languages, contact, FCM batch/topic routes); `routes/apiUser.php` at `/api/user` and `routes/apiGuide.php` at `/api/guide`, each behind `apiLocale` then `api:apiUser` or `api:apiGuide`—so travelers, guides, and admins never share the same token contract or payload shape by accident. `routes/admin.php` loads web middleware with `/{lang}/dashboard` resources for admins vs operational staff vs content roles, with Spatie-backed policies enforcing role-based access for guides vs travelers vs admins at the route and controller layer.
Data Flow
Mobile clients hit prefixed JSON on the guide and user stacks; admins sign in at `admin/signin` then work under localized dashboard URLs (`/en/dashboard`, etc.). Controllers under `App\Http\Controllers\Dashboard\*` persist guides, trips, payments, and settings to MySQL; `Api\Guide\*` and `Api\User\*` expose GPS tracking endpoints and live location reads/writes tailored to each persona's trip lifecycle. Firebase Firestore real-time sync complements MySQL for booking and presence-style fields that would otherwise require constant polling, while Kreait/Firebase covers push. Firebase helper code issues OAuth access tokens for Google IID/FCM calls used by topic subscribe routes in `api.php`.
Backend Decisions
The dual-app REST split keeps authorization and payloads purpose-built per client—narrow contracts for booking, tracking, and profile instead of one overloaded `/api` mega-resource. Spatie Laravel Permission backs admin RBAC per README stack, with the same guide vs traveler vs admin boundaries reflected in middleware, policies, and dashboard navigation. Push and broadcast paths lean on Kreait/Firebase and explicit HTTP calls rather than hiding network behavior; admin forms use Laravel Collective HTML and Flashy for fast operational feedback while domain rules stay in controllers and models familiar to Laravel contributors.
Challenges
Trip state machines span two mobile personas (guide vs. traveler): keeping dashboard listings, search, and soft-delete flows consistent with what each API exposes is ongoing work. FCM and topic routes must stay compatible with Google API changes. Multi-language admin URLs add an extra dimension to every link and redirect test. Keeping mobile API latency low under concurrent booking and tracking requests means the dual REST surfaces must stay responsive—indexing, eager loading, and avoiding N+1 on trip timelines when many guides and travelers hit booking and live GPS endpoints at once.
Technical Decisions
Stayed within Laravel 10 conventions from the project baseline (resource routes, middleware groups, Sanctum where configured for API tokens) instead of introducing a second framework. Chose clear route files per audience so new endpoints land in the smallest possible surface—easier to reason about than one giant `api.php` for every actor.