High-level overview
MVC with service layer
Controllers are thin. All business logic lives in service classes underapp/Services/.
| Layer | Responsibility |
|---|---|
| Controller | Parse the HTTP request, validate input, call a service, return a response |
| Service | Orchestrate business operations — availability checks, price calculation, payment dispatch, notification dispatch |
| Model | Eloquent model with relationships, scopes, and attribute casting |
| Job | Heavy or async work dispatched to the queue (email sends, webhook processing, CSS generation) |
Code organisation
User roles
The platform has three distinct user segments sharing a single database. Access is enforced by separate auth guards and middleware.- Traveler — browses packages, books tours, submits reviews, chats with guides.
- Guide / vendor — creates and manages tour packages, accepts or rejects bookings, manages payouts. Requires KYC verification before full access.
- Administrator — full platform control via
/admin: approves packages and KYC submissions, configures payment gateways, edits notification templates, manages site appearance.
kyc middleware blocks guide-specific routes until identity verification is approved by an admin.
Event-driven architecture
Laravel’s event system decouples side-effects from core operations. Controllers fire an event; multiple listeners respond independently.API structure
All API routes are prefixed/api/v1 and return JSON. Rate limiting is declared in routes/api.php:
| Endpoint group | Auth required | Rate limit |
|---|---|---|
POST /api/v1/auth/register | No | 10 req/min |
POST /api/v1/auth/login | No | 10 req/min |
GET /api/v1/packages | No | 60 req/min |
GET /api/v1/destinations | No | 60 req/min |
GET /api/v1/bookings/availability | No | 60 req/min |
GET /api/v1/user/profile | Sanctum token | 60 req/min |
POST /api/v1/reviews | Sanctum token | 30 req/min |
POST /api/v1/bookings/{uid}/cancel | Sanctum token | 30 req/min |
Booking flow
Payment webhook routes (/api/payment/{code}/{trx?}/{type?}) are unauthenticated — they are called directly by external payment providers.
Package approval flow
Guides can also use the Gemini AI integration (POST /user/generate-with-ai) to draft package descriptions and generate images before submission.
Caching strategy
The application supports multiple cache drivers, with Redis recommended for production.| Cache layer | Driver | Purpose |
|---|---|---|
| Application data | Redis | Computed results, heavy query output |
| Sessions | Redis (production) / file (dev) | User session state across requests |
| Dynamic CSS | File | Generated theme CSS written to public/assets/ |
CACHE_DRIVER=redis and SESSION_DRIVER=redis in .env for production.
Queue system
Background jobs are dispatched to the queue to keep HTTP responses fast. SetQUEUE_CONNECTION=database (default) or redis (recommended for production).
Key jobs dispatched by the system:
Horizontal scaling
The application is designed to run on multiple servers behind a load balancer:- Stateless application — store sessions in Redis (
SESSION_DRIVER=redis) so any node can serve any request. - Shared file storage — switch
FILESYSTEM_DISKtos3(AWS S3 or DigitalOcean Spaces) so uploaded files are accessible to all nodes. - Read replicas — Laravel’s database configuration supports separate
readandwriteconnections for MySQL. - Queue workers — run additional workers on separate servers; they pull from the same Redis/database queue.
Security architecture
Authentication
| Context | Mechanism |
|---|---|
| Web (traveler / guide) | Laravel session guard with auth middleware |
| API (mobile / external) | Laravel Sanctum bearer token |
| Admin panel | Separate admin guard |
Security measures applied
| Threat | Mitigation |
|---|---|
| CSRF | All state-changing web routes use POST; Laravel CSRF middleware active on all web routes |
| IDOR (insecure direct object reference) | Booking ownership verified before accept / reject / complete / refund |
| Brute-force login | throttle:5,1 on POST /login |
| Coupon code leakage | POST /coupon/check (was GET — codes would appear in server logs) |
| Unauthenticated DB writes | /trans route removed; /queue-work and /schedule-run moved behind admin auth |
| SQL injection | Eloquent ORM used throughout; raw queries avoided |
| XSS | Input sanitised via stevebauman/purify before persistence |
| Rate limiting on payments | throttle:10,1 on POST /make-payment |
| 2FA | TOTP via pragmarx/google2fa available to all users |
| reCAPTCHA | Google reCAPTCHA on registration and login forms |