group(function () { // Passenger Route::post('/passenger/login', [AuthController::class, 'passengerLogin']); Route::post('/passenger/register', [AuthController::class, 'passengerRegister']); Route::post('/passenger/wallet-login', [AuthController::class, 'passengerWalletLogin']); Route::get('/passenger/login-google', [AuthController::class, 'passengerLoginGoogle']); // Driver Route::match(['get', 'post'], '/driver/login', [AuthController::class, 'driverLogin']); Route::post('/driver/register', [AuthController::class, 'driverRegister']); Route::post('/driver/wallet-login', [AuthController::class, 'driverWalletLogin']); Route::match(['get', 'post'], '/driver/login-google', [AuthController::class, 'driverLoginGoogle']); // Admin & Service Route::post('/admin/login', [AuthController::class, 'adminLogin']); // Silent JWT Handshake (Compatibility with V1 background flow) Route::post('/passenger/login-jwt', [AuthController::class, 'passengerJwtHandshake']); Route::post('/driver/login-jwt', [AuthController::class, 'driverJwtHandshake']); Route::post('/driver/wallet-token', [AuthController::class, 'getWalletToken']); }); // Admin Error Logging (public — accepts error reports from Flutter apps) Route::post('v2/admin/errors', [MiscController::class, 'logClientError']); // OTP (public, but rate-limited) Route::prefix('v2/otp')->middleware('throttle:10,1')->group(function () { Route::post('/send', [OtpController::class, 'send']); Route::post('/verify', [OtpController::class, 'verify']); // Dedicated Driver OTP Endpoints (matches V1 sendOtpMessageDriver.php) Route::post('/driver/send', [OtpController::class, 'sendDriver']); Route::post('/driver/verify', [OtpController::class, 'verifyDriver']); Route::post('/email/send', [OtpController::class, 'sendEmail']); Route::post('/email/verify', [OtpController::class, 'verifyEmail']); Route::match(['get', 'post'], '/check-phone', [OtpController::class, 'checkPhone']); }); // ══════════════════════════════════════════════ // PROTECTED — Require JWT + HMAC // ══════════════════════════════════════════════ Route::prefix('v2')->middleware(['hmac.auth', 'jwt.auth'])->group(function () { // ── Rides ── Route::post('/rides', [RideController::class, 'store']); Route::get('/rides', [RideController::class, 'index']); Route::match(['get', 'post'], '/rides/active', [RideController::class, 'active']); Route::get('/rides/{id}', [RideController::class, 'show']); Route::post('/rides/{id}/accept', [RideController::class, 'accept']); Route::post('/rides/{id}/arrive', [RideController::class, 'arrive']); Route::post('/rides/{id}/start', [RideController::class, 'start']); Route::post('/rides/{id}/finish', [RideController::class, 'finish']); Route::post('/rides/{id}/cancel/passenger', [RideController::class, 'cancelByPassenger']); Route::post('/rides/{id}/cancel/driver', [RideController::class, 'cancelByDriver']); Route::post('/rides/{id}/retry', [RideController::class, 'retrySearch']); Route::put('/rides/{id}', [RideController::class, 'update']); // ── Tracking ── Route::get('/tracking/driver/{rideId}', [TrackingController::class, 'driverLocation']); Route::get('/tracking/heatmap', [TrackingController::class, 'heatmap']); Route::get('/tracking/captain-stats', [TrackingController::class, 'captainStats']); // ── Profile ── Route::get('/profile/passenger', [ProfileController::class, 'passenger']); Route::get('/profile/driver', [ProfileController::class, 'driver']); Route::match(['post', 'put'], '/profile/passenger', [ProfileController::class, 'updatePassenger']); Route::match(['post', 'put'], '/profile/driver/email', [ProfileController::class, 'updateDriverEmail']); Route::post('/profile/driver/shamcash', [ProfileController::class, 'updateShamCash']); Route::match(['post', 'put'], '/profile/driver/car', [ProfileController::class, 'updateDriverCar']); // ── Wallet ── // All wallet operations (balance, funds, transactions) are handled by the // dedicated payment server. V2 only generates 60-second JWT tokens for it // via POST /v2/auth/passenger/wallet-login and /v2/auth/driver/wallet-login. // ── Ratings ── Route::post('/ratings/driver', [RatingController::class, 'rateDriver']); Route::get('/ratings/driver', [RatingController::class, 'getDriverRating']); Route::get('/ratings/driver/{id}', [RatingController::class, 'getDriverRating']); Route::post('/ratings/passenger', [RatingController::class, 'ratePassenger']); Route::get('/ratings/app', [RatingController::class, 'getAppFeedback']); Route::post('/ratings/app', [RatingController::class, 'storeAppFeedback']); Route::get('/ratings/passenger', [RatingController::class, 'passengerRating']); Route::get('/ratings/passenger/{id}', [RatingController::class, 'passengerRating']); // ── Promos ── Route::get('/promos', [PromoController::class, 'index']); Route::get('/promos/check', [PromoController::class, 'check']); Route::post('/promos', [PromoController::class, 'store']); Route::put('/promos/{id}', [PromoController::class, 'update']); Route::delete('/promos/{id}', [PromoController::class, 'destroy']); // ── Uploads ── Route::post('/uploads/card-image', [UploadController::class, 'cardImage']); Route::post('/uploads/profile-image', [UploadController::class, 'profileImage']); Route::post('/uploads/document', [UploadController::class, 'document']); Route::post('/uploads/id-front', [UploadController::class, 'idFront']); Route::post('/uploads/id-back', [UploadController::class, 'idBack']); Route::post('/uploads/audio', [UploadController::class, 'audio']); // ── Places ── Route::get('/places/search', [PlaceController::class, 'search']); Route::post('/places', [PlaceController::class, 'store']); // ── Notifications ── Route::get('/notifications', [NotificationController::class, 'index']); Route::get('/notifications/driver', [NotificationController::class, 'index']); Route::post('/notifications/update', [NotificationController::class, 'updateNotification']); Route::get('/notifications/token', [NotificationController::class, 'getToken']); Route::post('/notifications/token', [NotificationController::class, 'updateToken']); Route::match(['put', 'post'], '/notifications/driver/read', [NotificationController::class, 'updateNotification']); Route::match(['put', 'post'], '/notifications/{id}/read', [NotificationController::class, 'markRead']); // ── Misc ── Route::get('/misc/test', [MiscController::class, 'test']); Route::get('/misc/package-info', [MiscController::class, 'packageInfo']); Route::match(['get', 'post'], '/misc/kazan-percent', [MiscController::class, 'getKazanPercent']); Route::get('/misc/help-center', [MiscController::class, 'getHelpCenter']); Route::post('/misc/help-center', [MiscController::class, 'storeHelpCenter']); Route::get('/misc/tips', [MiscController::class, 'getTips']); Route::post('/misc/tips', [MiscController::class, 'storeTips']); Route::get('/misc/license', [MiscController::class, 'getLicense']); Route::get('/misc/api-key', [MiscController::class, 'getApiKey']); Route::post('/misc/egypt-phones', [MiscController::class, 'saveEgyptPhones']); // ── Invites ── Route::get('/invites/driver', [InviteController::class, 'index']); Route::post('/invites/driver', [InviteController::class, 'inviteDriver']); Route::post('/invites/passenger', [InviteController::class, 'invitePassenger']); Route::get('/invites/gift', [InviteController::class, 'checkGift']); // ── Driver Docs ── Route::get('/driver/registration-car', [DriverDocController::class, 'getCarReg']); Route::post('/driver/registration-car', [DriverDocController::class, 'storeCarReg']); Route::post('/driver/scams', [DriverDocController::class, 'reportScam']); // ── Support ── Route::post('/support/complaints', [SupportController::class, 'storeComplaint']); }); // ══════════════════════════════════════════════ // PUBLIC Tracking (special — uses hash auth like V1) // ══════════════════════════════════════════════ Route::get('v2/tracking/public/{rideId}', [TrackingController::class, 'publicTrack']); // ══════════════════════════════════════════════ // ADMIN ROUTES (require admin JWT) // ══════════════════════════════════════════════ Route::prefix('v2/admin')->middleware(['hmac.auth', 'jwt.auth', 'admin'])->group(function () { // Driver management Route::get('/drivers', [Admin\DriverManagementController::class, 'index']); Route::get('/drivers/search', [Admin\DriverManagementController::class, 'search']); Route::post('/drivers/{id}/activate', [Admin\DriverManagementController::class, 'activate']); Route::post('/drivers/{id}/deactivate', [Admin\DriverManagementController::class, 'deactivate']); Route::post('/drivers/{id}/add-car', [Admin\DriverManagementController::class, 'addCar']); Route::post('/drivers/{id}/notes', [Admin\DriverManagementController::class, 'addNote']); // Passenger management Route::get('/passengers', [Admin\PassengerManagementController::class, 'index']); Route::get('/passengers/search', [Admin\PassengerManagementController::class, 'search']); // Ride management Route::get('/rides', [Admin\RideManagementController::class, 'index']); Route::get('/rides/{id}', [Admin\RideManagementController::class, 'show']); // Stats Route::get('/stats/overview', [Admin\StatsController::class, 'overview']); Route::get('/stats/rides', [Admin\StatsController::class, 'rides']); Route::get('/stats/drivers-monthly', [Admin\StatsController::class, 'driversMonthly']); Route::get('/stats/employees', [Admin\StatsController::class, 'employees']); });