Skip to content

Application Architecture & Codebase

Developer

The application is architected as a standard Laravel monolith: a single unified codebase covering web routes, the administrative back-office, vendor/store portals, and a versioned API layer (Api/v1, Api/v2) utilized by the native mobile applications. There is no structural module or domain decoupling; the system adheres to conventional standard Laravel directory design, routing logic through standard structures under app/ (Http/Controllers, Models, Services).

The Api/v1 and Api/v2 controllers serve the mobile applications exclusively. These surfaces were completely outside the scope of this engagement, were not modified, and are not covered in detail within this documentation.

Blade serves as the exclusive template rendering engine across the web application ecosystem; alternative interactive libraries (such as React, Vue, or Alpine) are not utilized. Prior to this engagement, the inherited codebase did not leverage a centralized reusable component framework, relying instead on direct view templates and partial includes.

To improve consistency, V&B introduced the project’s first dedicated suite of reusable Blade components (App\View\Components). This follows standard engineering design choices to isolate layout elements with distinct, typed inputs.

The WashCardTemplate is the primary example of this pattern: a single unified component that accepts a stateful mode parameter (index vs. dashboard). It dynamically renders either a public facing service plan card or a logged in dashboard order entity using the same underlying code structure, eliminating structural markup duplication.

The application’s data model was originally built around the assumption that every order belongs to a real, registered user; there was no concept of a booking made by someone who isn’t logged in. The guest first booking flow required by this engagement (see Project History) needed exactly that, so a workaround was introduced to make it possible without changing how orders are modelled everywhere else in the application.

The mechanism: a single reserved “ghost” user. A GhostUserSeeder creates one fixed user record (id = 999) specifically to own guest orders:

DB::table('users')->insert([
'id' => 999,
'first_name' => 'Guest',
'last_name' => 'User',
'name' => 'Guest User',
'email' => 'zeyn10@gmail.com',
'phone' => '0000000000',
'active' => 0,
'deleted' => 0,
'role' => 0,
// ...
]);

When a guest completes a Stripe payment, the order is created and attached to user_id = 999 like any other order, satisfying the existing foreign key and application logic that expects every order to have a user. The guest’s actual contact details are stored separately on the order itself, via columns added in two migrations: guest_phone, guest_name, guest_email, guest_token (added in AddGuestPhoneToOrdersTable), and guest_address, address_notes, guest_lat, guest_lng (added in AddGuestLocationToOrdersTable).

The order creation step itself, in GuestOrderController::stripeRedirect(), verifies the Stripe session server side before creating anything, wraps the vehicle and order inserts in a database transaction, and applies any coupon via the existing ApplyCouponService:

if ($coupon) {
$couponResult = app(ApplyCouponService::class)->applyCoupon($coupon, $planPrice);
$couponDiscount = $couponResult['discount'];
$totalPrice = $couponResult['final_total'];
}

This is the practical reason ApplyCouponService exists as a standalone, callable service rather than inline logic: this guest flow needed coupon calculation, and the service made that possible without duplicating or depending on the legacy coupon code path. The companion class, ValidateCouponService, is used earlier in the same controller (applyCoupon()) to check a code before it’s stored in the session.

GuestOrderController is a dedicated controller for the entire unauthenticated flow: vehicle selection, location and time, OTP verification, Stripe session creation, order creation, and the optional account creation step at the end. A separate, parallel UserOrderController drives the equivalent flow for already logged in users. The two controllers are distinct, but several of the Blade views they render are shared between them. This is covered in more detail in Guest Views and Logged-in Views.

Guest identity verification. Before payment, a guest’s phone number is verified through Firebase phone authentication (reCAPTCHA plus an SMS code), confirmed server side in GuestOrderController::verifyOTP(). For local development only, a fixed code (000000) bypasses the real Firebase flow on both the client and the server; this is explicitly marked for removal before production and is not present in the production environment.

Why the admin panel needed a small change. Because guest orders are attached to the same user ID (999) every time, the admin order detail view needed to know to display the order’s own guest_* fields instead of looking up a customer record. Otherwise every guest order would simply show as belonging to “Guest User” with no contact or delivery information visible. The admin view checks for this directly:

@if($order->user_id == 999)
{{ $order->guest_name ?? 'Guest' }}
@else
{{ $order->customer->name ?? 'N/A' }}
@endif

This is the specific, additive admin change referenced in Admin Views. Guest contact details, address, and notes are shown only when an order belongs to the ghost user; every other admin order view behaves exactly as it did before.

A second compatibility step. After the order is created, the flow also checks for and creates a TempUser record matching the guest’s phone number, so that if the guest later registers a real account, there’s a path to associate their guest order history with it rather than losing it.

The platform’s current state is a hybrid architecture: a large inherited foundation left largely untouched due to scope bounds, alongside specialized, modernized service abstractions introduced during this contract window.

  • Controller Architecture. Controllers across the front end, administrative, vendor, and store spaces are traditionally heavy, embedding transactional business logic directly within HTTP endpoints rather than delegating tasks to a decoupled service layer. This reflects the historical design pattern of the original app.
  • Data Models & Unused Domains. The app/Models space contains a large number of database models matching product classifications that do not appear to be active in the live application ecosystem (e.g. configurations pointing to pet grooming, food delivery, and fashion items). These were left intact; pruning or archiving these models was treated as an out of scope technical risk since their historical structural dependencies could not be safely audited without downstream impacts.
  • Layout Implementations. Outside of the newly introduced modular components, layout templates frequently duplicate code structures and internal logic, consistent with systems built prior to a centralized component paradigm.
  • State Interaction Flow. The customer booking and checkout sequence operates as a hybrid of server rendered Blade templates and selective AJAX operations. Page frameworks are loaded server side, while specific state modifications, such as validation checks on coupon codes or order initialization steps, utilize localized inline JavaScript to send asynchronous AJAX requests.
  • Authentication Foundations. Customer authorization relies entirely on a mobile number OTP (One Time Password) mechanism, using Google Firebase as the authoritative validation engine. This specific infrastructure implementation predated V&B’s involvement and was not modified during this engagement.

Controllers are separated cleanly by system namespace rather than individual domain boundaries:

  • App\Http\Controllers\front. Handles public entry points and authenticated customer facing sequences, including the homepage, booking funnels, checkout operations, and user profiles.
  • App\Http\Controllers\admin. Powers the central administrative portal. This represents the largest namespace in the system, managing back office entities like products, categorizations, listings, and core system configurations.
  • App\Http\Controllers\vendor. Exposes a focused, parallel subset of administrative workflows scoped strictly to specific third party vendor access profiles.
  • App\Http\Controllers\store. Provides localized store manager dashboards with highly restricted management capabilities.
  • App\Http\Controllers\Api\v1 / Api\v2. The native mobile app communication layer. Pre-existing, out of scope, and unmodified.
  • Root Level System Elements. Isolated, top level handlers, such as PaymentController, AjaxContoller, and MediaConverterController, manage cross cutting concerns and generalized AJAX request response pipelines.

The codebase exposes two distinct data communication surfaces:

  1. Mobile App API Routing (Api/v1 and Api/v2). The communication paths utilized by native clients. These predate the current engagement, remained completely out of scope, and were not adjusted.
  2. Internal Communication Endpoints. Web based endpoints embedded within the web route files (front, admin, vendor). These return JSON responses directly to inline frontend scripts to update cart contents, load active calendar slots, or check coupon values dynamically without triggering full page reloads. These are built as plain Laravel routes and do not form a formal, versioned API layer.

The native smartphone applications interface entirely via the Api/v1 and Api/v2 endpoints. This operational logic was inherited intact from the previous development cycles and was not a part of the contracted engineering scope.

  • Stripe. Manages core transaction processing and secure asynchronous webhook reception for both the new guest and registered user booking paths deployed during this engagement. A separate, legacy token based membership file exists within the system (Api/v1/MembershipController), but it does not represent a true recursive subscription engine and was not extended during this work.
  • Google Maps API. Provisions geographical location services, driving spatial lookups against a polygon based delivery coverage module (PolygonModel utilizing PostGIS spatial features).
  • Google Firebase. Serves as the authoritative infrastructure for routing transactional push notifications and managing user mobile OTP validation steps.
  • D7 Networks. Embedded as the infrastructure provider for generating SMS and WhatsApp tracking updates, running via back office configurations inherited from the previous team.
  • Xero. An accounting data service package present inside the application (XeroService, XeroController), but completely unassociated with this specific engagement.

The platform originally executed on a MySQL database topology. Following the critical regional cloud outage that impacted the original AWS environment, the database engine was migrated to a PostgreSQL deployment, establishing an isolated, performant configuration on the current DigitalOcean infrastructure.

The core application relies on a single database design. Content management assets and user uploaded media files are hosted externally within an Amazon S3 container. This S3 asset container represents a legacy data structure that remained completely outside the scope of the migration; incoming maintainers should note that future maintenance cycles should evaluate this container dependency independently from the core database/compute hosting layer.

As noted above, a large number of model classes correspond to product domains not in active use. This is treated as inherited technical debt rather than something introduced during this engagement, and a full audit of which models are genuinely dead code is recommended before removing any of them.

Infrastructure Coupling & Background Processing

Section titled “Infrastructure Coupling & Background Processing”

An analysis of the application directory structure revealed a distinct, recurring operational pattern where background tasks are managed via direct asynchronous shell execution lines to the artisan CLI tool, rather than passing through standard Laravel queue structures.

This structural pattern is implemented over fifty times across mobile endpoints, administrative handlers, and system event handlers:

exec("php " . base_path() . "/artisan update:firebase_node " . $user_id . " > /dev/null 2>&1 & ");

This mechanism processes critical asynchronous side effects, including dispatching user verification emails, synchronizing Firebase data targets, confirming bookings, and assigning drivers.

This implementation also predates the V and Bruno engagement and is part of the inherited system architecture. It was not introduced, modified, or standardized as part of this work.

  • Server Environment Dependency. This pattern requires a valid php CLI binary to be continuously accessible within the $PATH profile of the system user executing the web server engine. This configuration must be verified independently following any server migrations or server profile adjustments.
  • Loss of Operational Error Logs. The execution string > /dev/null 2>&1 & background processes the job while completely discarding standard output logs and error logs. If an underlying artisan script catches a runtime error (e.g. missing parameter, model validation failure), the event will fail silently without generating a visible system exception or automatic retry sequence.
  • Bypass of Standard Queue Engines. This execution model completely bypasses Laravel’s core database queue structures, despite the application already possessing the necessary underlying data structures (jobs and failed_jobs tables).

This fire and forget shell model explains why a missing or inactive Laravel queue worker would not surface as an obvious system break: legacy asynchronous work continues to fire via exec() statements regardless of worker status, while any newer, strictly queue dependent workflows would silently stall without processor access.

No hardcoded absolute filesystem paths (e.g. /home/..., /var/www/...) or hardcoded localhost/port references were found in app/ outside of this pattern.

The software layers introduced by V&B adhere to standard DRY (Don’t Repeat Yourself) and SOLID design choices, prioritizing structural decoupling from the surrounding inherited code blocks to preserve system safety.

Dedicated modern managers, such as ValidateCouponService and ApplyCouponService, the modular WashCardTemplate component, and the ghost user pattern for guest checkout, represent these standards. Each is single purpose, fully isolated, explicitly documented about what it does and doesn’t cover, and designed for reuse across multiple application domains rather than requiring a rewrite of the surrounding data model.

The surrounding legacy codebase was left intact to prevent structural regressions and maintain contract scope boundaries, resulting in a hybrid codebase featuring localized modern abstractions alongside a larger, controller heavy legacy architecture.

  • Reference Modern Architecture Rules. Treat the newly deployed Blade components and standalone service classes as the standard blueprints for subsequent software iterations, avoiding the duplication of older controller nested logic patterns.
  • Perform Safe Code Audits Before Pruning. Prior to removing any data models, controllers, or web routes that appear inactive (see Data & Storage Layers), perform a comprehensive validation check across the system; several elements represent legacy leftovers from previous business models rather than current live dead code.
  • Build Subscription Logic Fresh. The inherited token based membership component serves as an identification script rather than a standard billing tool; recursive subscription plans should be developed independently rather than attempting to extend the old logic block.
  • Migrate Asynchronous Task Dispatches. Consider transitioning the exec("php artisan...") task patterns over to authentic queued Laravel Job classes to leverage standard system visibility, exception tracking, and automated retry logic. See Infrastructure Coupling & Background Processing.
  • Validate the S3 Asset Dependency Separately. Treat the Amazon S3 image bucket as an independent exterior infrastructure entity that should be evaluated independently from the database/compute servers during future maintenance reviews.