Installation & Local Configuration
End-to-end plan to install and configure SaleOS on a developer machine: backend API, React SPA, VitePress docs, Laravel Reverb, email, queues, and related services.
| Audience | Go here |
|---|---|
| Local development | This page |
| Production on Laravel Forge | Laravel Forge Deployment |
| Go-live checklist | Production Runbook |
| Realtime / Redis / Web Push | Notification System |
Repositories
Clone the three sibling repos next to each other (recommended layout):
DC-SaaS/
├── SaaS-Backend/ # Laravel 13 API (Herd: saas-backend.test)
├── SaaS-Frontend/ # React 19 + Vite SPA (localhost:5173)
└── SaaS-Docs/ # VitePress docs (docs:dev)| Repo | Role | Default local URL |
|---|---|---|
| SaaS-Backend | Central + Tenant APIs, queues, Reverb, scheduler | http://saas-backend.test |
| SaaS-Frontend | Central admin + tenant workspace SPA | http://localhost:5173 |
| SaaS-Docs | Product / developer / ops documentation | http://localhost:5173 (separate process) |
Prerequisites
| Tool | Version / notes |
|---|---|
| PHP | 8.3+ (project targets 8.4 via Herd) |
| Composer | 2.x |
| MySQL | 8+ (or MariaDB / PostgreSQL / SQLite for experiments) |
| Node.js | 20+ LTS |
| npm | 10+ |
| Laravel Herd | Recommended on Windows/macOS — serves saas-backend.test with PHP-FPM |
| Redis | Optional locally; required in production for cache/queue/Reverb scale |
Optional: Stripe CLI (billing webhooks), Mailpit/Mailhog (SMTP catcher), ngrok (provider webhooks).
1. Backend (SaaS-Backend)
1.1 Install dependencies and bootstrap
cd SaaS-Backend
composer install
cp .env.example .env
php artisan key:generateOr use the Composer setup script (install + .env + key + migrate):
composer run setupLink public storage for local uploads:
php artisan storage:link1.2 Point Herd at the app
With Laravel Herd installed, park or link the project so it resolves as http://saas-backend.test (folder name saas-backend → Herd site). Confirm:
herd sitesDo not rely on php artisan serve for day-to-day work unless Herd is unavailable.
1.3 Core .env (local)
Backend .env.example is production-shaped (api.example.com / app.example.com / reverb.example.com, Redis + Reverb). After cp .env.example .env, override for local:
APP_NAME="SaleOS"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://saas-backend.test
FRONTEND_URL=http://localhost:5173
CORS_ALLOWED_ORIGINS=http://localhost:5173
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=saas_backend
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=database
SESSION_ENCRYPT=false
SESSION_SECURE_COOKIE=false
QUEUE_CONNECTION=database
CACHE_STORE=database
FILESYSTEM_DISK=public
BROADCAST_CONNECTION=reverb
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_ALLOWED_ORIGINS=http://localhost:5173
PLATFORM_DOMAIN_SUFFIXES=localhost| Variable | Purpose |
|---|---|
APP_URL | API public URL (Herd site) |
FRONTEND_URL | SPA origin for password-reset / invite links and CORS |
CORS_ALLOWED_ORIGINS | Extra SPA origins (e.g. http://127.0.0.1:5173 for Windows E2E) |
PLATFORM_DOMAIN_SUFFIXES | Platform subdomain suffixes (local: localhost) |
Local cache/queue on database is fine. Production requires Redis with Reverb — Laravel Forge · Production Runbook.
1.4 Migrate and seed (local / greenfield only)
php artisan migrate
php artisan db:seed --class=Database\\Seeders\\Central\\CentralDatabaseSeederFresh wipe (destroys data):
php artisan migrate:fresh --seedNever run db:seed / catalog seeders on production. Modules and permissions ship via migrate-only data migrations (Upgrade Guide).
1.5 Default central login
After seeding:
| Field | Value |
|---|---|
| Central URL | http://localhost:5173/central/login (SPA) |
superadmin@saas.com | |
| Password | password |
Also seeded: tester@saas.com, developer@saas.com, admin@saas.com (same password).
1.6 Optional CRM demo data
php artisan local:seed-demoSee Local Demo Data. Aborts when APP_ENV=production.
2. Frontend (SaaS-Frontend)
2.1 Install and env
cd SaaS-Frontend
npm install
cp .env.example .envLocal Vite .env:
VITE_APP_NAME=SaleOS
VITE_API_URL=http://saas-backend.test
VITE_API_MODE=central
VITE_REVERB_APP_KEY=saleos-reverb-key
VITE_REVERB_HOST=localhost
VITE_REVERB_PORT=8080
VITE_REVERB_SCHEME=http| Variable | Purpose |
|---|---|
VITE_API_URL | Backend base URL (no trailing /api) |
VITE_API_MODE | central or tenant default context |
VITE_REVERB_* | Must match backend REVERB_* / public Echo settings |
Production does not bake these into CI artifacts. Forge generates /config.js → window.env from the site .env at deploy time (frontend build artifacts).
2.2 Run the SPA
npm run devOpen the URL Vite prints (default http://localhost:5173).
- Central admin:
/central/login - Tenant workspace:
/login(Workspace slug or domain)
2.3 Playwright (optional)
cp .env.e2e.example .env.e2e
# Align E2E_API_URL / E2E_ADMIN_* with your backend seed
npm run test:e2e3. Docs (SaaS-Docs)
cd SaaS-Docs
npm ci
npm run docs:devOpen the printed URL. Production docs deploy from the build-artifacts branch (CI builds VitePress; Forge only activates the release) — Laravel Forge Deployment.
Local production build check:
npm run docs:build
npm run docs:preview4. Reverb (realtime)
Realtime notifications use Laravel Reverb → Echo in the SPA. Align keys on both repos.
4.1 Backend .env
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=saleos
REVERB_APP_KEY=saleos-reverb-key
REVERB_APP_SECRET=saleos-reverb-secret
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_ALLOWED_ORIGINS=http://localhost:5173
REVERB_APP_ACCEPT_CLIENT_EVENTS_FROM=noneEcho private-channel auth uses POST /broadcasting/auth (already in CORS paths).
4.2 Frontend .env
VITE_REVERB_APP_KEY=saleos-reverb-key
VITE_REVERB_HOST=localhost
VITE_REVERB_PORT=8080
VITE_REVERB_SCHEME=httpOmit VITE_REVERB_* only if you intentionally disable Echo.
4.3 Start Reverb
In a dedicated terminal:
cd SaaS-Backend
php artisan reverb:startProduction: supervised process behind TLS, SPA origin pinned — Notification System runbook.
5. Email
5.1 Local default (log driver)
Keep MAIL_MAILER=log locally (also the template default until Settings → Mail is configured):
MAIL_MAILER=log
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"Messages are written to storage/logs/laravel.log — enough for password-reset link debugging without an SMTP server.
5.2 Local SMTP catcher (optional)
Point Laravel at Mailpit / Mailhog / similar:
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_SCHEME=nullKeep FRONTEND_URL=http://localhost:5173 so reset/invite links open the SPA.
5.3 Central / Tenant Settings (preferred for real providers)
Runtime mail is driven by Central and Tenant settings (SMTP, Postmark, Mailgun), not only .env:
- Sign in as central superadmin → Settings → Mail
- Choose provider, save credentials, Send test
- Tenant workspaces inherit Central (
mail_mode=system) or use custom credentials
Env fallbacks when DB secrets are empty: POSTMARK_API_KEY, MAILGUN_DOMAIN, MAILGUN_SECRET, etc.
Details: Multi-Provider Email, Email Webhooks, Authentication ops.
5.4 Email queue
Outbound mail / mail notifications use the emails queue. Always process it:
php artisan queue:work --queue=emails,default --sleep=1 --tries=3Restart workers after changing mail credentials (php artisan queue:restart).
6. Queues, scheduler, and Web Push
6.1 Queue worker (required for mail + notifications)
cd SaaS-Backend
php artisan queue:work --queue=emails,defaultLocal QUEUE_CONNECTION=database is fine. Production should use Redis.
6.2 Scheduler (local)
Laravel schedule (pruning, CRM due digests, subscription expiry, etc.) needs a one-minute tick:
php artisan schedule:workOr a cron entry pointing at php artisan schedule:run.
6.3 Web Push (optional locally)
Generate VAPID keys once (do not commit real keys):
php artisan tinker --execute "print_r(Minishlink\WebPush\VAPID::createVapidKeys());"VAPID_SUBJECT=mailto:admin@example.com
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=VAPID_SUBJECT must be a mailto: or https: URI. Without keys, database + Reverb delivery still work; Web Push is skipped gracefully.
7. Optional integrations
Configure only what you are actively developing.
| Integration | Local setup |
|---|---|
| Stripe / Cashier | Set STRIPE_KEY, STRIPE_SECRET, STRIPE_WEBHOOK_SECRET; forward webhooks with Stripe CLI to /webhooks/stripe (or Cashier path). See Stripe / Cashier. |
| Creem | Prefer Central Payment Gateways UI; env CREEM_* as fallback. |
| Object storage | Local: FILESYSTEM_DISK=public. Production: S3-compatible AWS_* — Object Storage. |
| Branded domains | Set BRANDED_SERVER_IPV4 (and optional CNAME) before verifying custom hosts. |
| Meta Lead Ads | Central integrations / META_LEAD_ADS_* — Meta App Setup (operator) · Meta Lead Ads (architecture). |
| Nightwatch / Telescope / Sentry | Disabled by default in .env.example; enable intentionally. |
8. Recommended terminal layout
Run these processes while developing (Herd serves PHP; you still need workers and SPA):
| Terminal | Command | Repo |
|---|---|---|
| 1 | (Herd — no command) | Backend site live |
| 2 | php artisan reverb:start | SaaS-Backend |
| 3 | php artisan queue:work --queue=emails,default | SaaS-Backend |
| 4 | php artisan schedule:work | SaaS-Backend (optional) |
| 5 | npm run dev | SaaS-Frontend |
| 6 | npm run docs:dev | SaaS-Docs (when editing docs) |
9. Verify the install
- [ ]
GET http://saas-backend.test/upreturns 200 - [ ] Central login works with
superadmin@saas.com/password - [ ] SPA calls API (
VITE_API_URLmatches Herd host; no CORS errors) - [ ] Password-reset mail appears in log / Mailpit when requested
- [ ] Queue worker processes a test mail / notification job
- [ ] Reverb is running; SPA has matching
VITE_REVERB_*(notification bell updates live when Echo is enabled) - [ ]
php artisan local:seed-demo(optional) creates demo workspacedemo-crm.localhost - [ ] Docs site builds:
npm run docs:buildin SaaS-Docs
10. Production (Laravel Forge)
Do not treat local Herd + npm run dev as a production recipe. On Forge you run three sites:
| Site | Branch | What Forge runs |
|---|---|---|
API (SaaS-Backend) | main | Composer, migrate --force, optimize, queue/Reverb restart |
SPA (SaaS-Frontend) | build-artifacts | Activate release + generate /config.js from site .env |
Docs (SaaS-Docs) | build-artifacts | Activate release only (no Node) |
Required in production (not optional like local): Redis cache/queue, supervised queue + Reverb, TLS, real mail (Central Settings), Stripe webhook secrets for active gateways, migrate-only upgrades (never db:seed).
Canonical guide: Laravel Forge Deployment — site settings, .env, deploy scripts, daemons, scheduler, email, and go-live checklist.
Also: Production Runbook · Upgrade Guide
Related docs
| Topic | Link |
|---|---|
| Laravel Forge (production) | Laravel Forge Deployment |
| Local demo CRM data | Local Demo Data |
| Platform freeze | Platform Freeze |
| Multi-provider email | Developer Guide |
| Notifications / Reverb / Web Push | Deployment |
| Auth / mail ops | Authentication |
| Frontend CI artifacts | Frontend Build Artifacts |
| Documentation governance | Same-PR rule |