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
- Request entry – All web traffic hits
public/index.php, which boots Laravel (bootstrap/app.php). - Routing –
routes/web.php(not listed but present) maps URLs to controller actions or Livewire components. - Controller flow – A typical booking flow goes
CartController::addToCart()→App\Models\Cart(persisted via Eloquent) →App\Jobs\SendAppointmentConfirmationMailJob(queued). The job pulls theAppointmentmodel, creates aNotification(AppointmentConfirmationNotification) and dispatches it via the mailer configured inconfig/mail.php. - Livewire UI – Pages such as
resources/views/manage-services.blade.phpembed Livewire components (<livewire:manage-services>). The component classApp\Http\Livewire\ManageServices.phphandles CRUD, validates viaValidateRolemiddleware, and emits events (ServiceViewEvent) thatAnalyticsJobconsumes for analytics tracking. - Analytics –
App\Jobs\AnalyticsJobruns asynchronously, writing toservice_hitstable viaApp\Models\ServiceHit. The singletonAnalyticsSingletonprovides a shared client for external services if needed. - Queue – Laravel’s queue worker reads jobs from the
databasedriver (seeconfig/queue.php). The README points tophp artisan queue:workto process the email jobs. - Front‑end build –
npm installresolvespackage.json;npm run devtriggers Vite, which readsvite.config.jsand bundlesresources/js/app.jsintopublic/build/. Tailwind is configured intailwind.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/Dockerfileuses mutablephp: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.