The Problem

A small salon needs a single‑paneled system to manage customers, services, locations, appointments, and related email notifications. The codebase should let a developer spin up the app locally, extend the business rules, and keep the UI responsive without building a full‑stack solution from scratch.

What This Does

The repository implements a TALL‑stack (Tailwind, Alpine, Laravel, Livewire) booking and CRM system. Core domain objects live in app/Models/ – e.g. Appointment.php, Service.php, Location.php. Business actions such as creating a user or resetting a password are in app/Actions/Fortify/. HTTP entry points are the Laravel controllers under app/Http/Controllers/ (e.g. CartController.php, UserController.php) and Livewire components in app/Http/Livewire/ (e.g. ManageAppointments.php, CreateService.php). The front‑end bundle is built from resources/js/app.js and resources/css/app.css and compiled by Vite (vite.config.js).

How It Is Wired

  1. Request entry – All web traffic hits public/index.php, which boots Laravel (bootstrap/app.php).
  2. Routing – routes/web.php (not listed but present) maps URLs to controller actions or Livewire components.
  3. Controller flow – A typical booking flow goes CartController::addToCart() → App\Models\Cart (persisted via Eloquent) → App\Jobs\SendAppointmentConfirmationMailJob (queued). The job pulls the Appointment model, creates a Notification (AppointmentConfirmationNotification) and dispatches it via the mailer configured in config/mail.php.
  4. Livewire UI – Pages such as resources/views/manage-services.blade.php embed Livewire components (<livewire:manage-services>). The component class App\Http\Livewire\ManageServices.php handles CRUD, validates via ValidateRole middleware, and emits events (ServiceViewEvent) that AnalyticsJob consumes for analytics tracking.
  5. Analytics – App\Jobs\AnalyticsJob runs asynchronously, writing to service_hits table via App\Models\ServiceHit. The singleton AnalyticsSingleton provides a shared client for external services if needed.
  6. Queue – Laravel’s queue worker reads jobs from the database driver (see config/queue.php). The README points to php artisan queue:work to process the email jobs.
  7. Front‑end build – npm install resolves package.json; npm run dev triggers Vite, which reads vite.config.js and bundles resources/js/app.js into public/build/. Tailwind is configured in tailwind.config.js.

No circular import edges were found; the internal module graph contains five modules with a single import edge, indicating low coupling. The most connected JavaScript module is resources/js/app.js (imports one module, no inbound imports).

How To Use It

# Clone the repo
git clone https://github.com/moses-y/CRM-laravel.git
cd CRM-laravel

# Option A – Local PHP environment
composer install                     # install PHP deps (composer.lock present)
cp .env.example .env                  # create env file
php artisan key:generate             # set APP_KEY
php artisan migrate --seed           # run migrations and seeders (includes DB sqlite)
npm install                           # install front‑end deps
npm run dev                           # start Vite dev server (optional)
php artisan serve                     # launch Laravel dev server (http://127.0.0.1:8000)

# Option B – Docker (Dockerfile & docker-compose.yml exist)
docker compose up --build             # builds app image and starts services
# Inside the container
php artisan migrate --seed
php artisan queue:work               # process queued mail jobs

The .env.example defines required keys (DB_CONNECTION, MAIL_MAILER, etc.). No additional secret files were detected.

Real‑World Use

A salon employee logs in, creates a new service via the Livewire UI, and the system dispatches SendNewServicePromoMailJob. The job queues an email, which the queue worker sends through Mailtrap (as described in the README). The same action logs a ServiceViewEvent that AnalyticsJob records for later dashboard charts.

Code Health & Issues

Measured findings (static analysis):

  • HIGH – Deep nesting – 34 files, e.g. resources/views/api/api-token-manager.blade.php (max indent depth 11).
  • HIGH – Duplicated code – 131 repeated 6‑line blocks across 35 files (e.g. ManageServices.php, SendAppointmentConfirmationMailJob.php).

Health audit (provided by the pipeline):

  • HIGH – No LICENSE – repository root lacks a licence file.
  • HIGH – No CI/CD – no workflow to build or test on push/pull‑request.
  • HIGH – No build gate for Dockerfile – image never validated automatically.
  • HIGH – Committed SQLite dump – database/database.sqlite (9.5 MiB) stored in VCS.
  • MEDIUM – No Dependabot/Renovate – manifests (composer.json, package.json) lack auto‑update config.
  • MEDIUM – Base image not pinned – .devcontainer/Dockerfile uses mutable php:8.1-cli.
  • MEDIUM – No pre‑commit secret scan – repository has no secret‑gate.
  • MEDIUM – Large binary not in LFS – same SQLite file exceeds 5 MiB threshold.

No critical findings were reported.

The Bottom Line

The project delivers a functional Laravel‑based booking/CRM with a clear TALL‑stack implementation and ready‑to‑run Docker setup. Code quality suffers from deep nesting, duplicated snippets, and missing operational safeguards (license, CI, secret scanning). It is suitable for learning or rapid prototyping, but production use should first address the high‑severity health items and refactor the most tangled Blade templates.