Installation & Local Configuration
End-to-end plan to install and configure EloSync 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 sibling repos next to each other (recommended layout):
EloSync/
├── EloSync-Backend/ # Laravel 13 API (Herd: elosync-backend.test)
├── EloSync-Frontend/ # React 19 + Vite SPA (localhost:5173)
├── EloSync-Docs/ # VitePress docs (docs:dev)
├── EloSync-Website/ # Marketing site (localhost:3000)
└── EloSync-Mobile/ # Expo mobile app| Repo | Role | Default local URL |
|---|---|---|
| EloSync-Backend | Central + Tenant APIs, queues, Reverb, scheduler | http://elosync-backend.test |
| EloSync-Frontend | Central admin + tenant workspace SPA | http://localhost:5173 |
| EloSync-Docs | Product / developer / ops documentation | http://localhost:5173 (separate process) |
| EloSync-Website | Marketing / Join Beta site | http://localhost:3000 |
| EloSync-Mobile | Expo tenant mobile client | Metro / device |
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 elosync-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 (EloSync-Backend)
1.1 Install dependencies and bootstrap
cd EloSync-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://elosync-backend.test (folder name EloSync-Backend → Herd site elosync-backend). 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="EloSync"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://elosync-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).
On local Vite (npm run dev), /central/login prefills these credentials.
1.6 Demo workspace (local seed)
When APP_ENV=local, php artisan migrate:fresh --seed also runs local:seed-demo and creates the shared demo tenant:
| Field | Value |
|---|---|
| Tenant URL | http://localhost:5173/login |
| Domain | demo-crm.localhost |
demo@demo.com | |
| Password | password |
/login prefills these credentials in local Vite. Re-seed or enlarge data anytime with php artisan local:seed-demo — see Local Demo Data. Aborts when APP_ENV=production.
2. Frontend (EloSync-Frontend)
2.1 Install and env
cd EloSync-Frontend
npm install
cp .env.example .envLocal Vite .env:
VITE_APP_NAME=EloSync
VITE_API_URL=http://elosync-backend.test
VITE_API_MODE=central
# VITE_CENTRAL_PATH_PREFIX=dc-s87s
VITE_REVERB_APP_KEY=elosync-reverb-key
VITE_REVERB_HOST=localhost
VITE_REVERB_PORT=8080
VITE_REVERB_SCHEME=http
# Optional marketing pixels — see /deployment/marketing-pixels
# VITE_GTM_ID=GTM-XXXXXXX
# VITE_META_PIXEL_ID=123456789012345
# VITE_LINKEDIN_PARTNER_ID=1234567
# VITE_X_PIXEL_ID=o1234| Variable | Purpose |
|---|---|
VITE_API_URL | Backend base URL (no trailing /api) |
VITE_API_MODE | central or tenant default context |
VITE_CENTRAL_PATH_PREFIX | Optional Central SPA HashRouter prefix (default central; match API CENTRAL_PATH_PREFIX) |
VITE_REVERB_* | Must match backend REVERB_* / public Echo settings |
VITE_GTM_ID | Optional Google Tag Manager container ID |
VITE_META_PIXEL_ID | Optional Meta Pixel ID |
VITE_LINKEDIN_PARTNER_ID | Optional LinkedIn Insight Tag partner ID |
VITE_X_PIXEL_ID | Optional X Pixel ID |
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_* / E2E_DEMO_* with your backend seed
npm run test:e2eTenant Playwright suites sign in to the shared demo workspace (demo@demo.com / demo-crm.localhost) created by local migrate:fresh --seed. Registration-only specs still create disposable workspaces.
3. Docs (EloSync-Docs)
cd EloSync-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=elosync
REVERB_APP_KEY=elosync-reverb-key
REVERB_APP_SECRET=elosync-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=elosync-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 EloSync-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 EloSync-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 FCM desktop push (optional locally)
Closed-browser push uses Firebase Cloud Messaging only. Without credentials, database + Reverb delivery still work; FCM is skipped gracefully.
FCM_PROJECT_ID=
FCM_CLIENT_EMAIL=
FCM_PRIVATE_KEY=
# Or: FCM_CREDENTIALS=/absolute/path/to/service-account.json
FCM_ICON=/brand/elosync-app-icon-light.png
FCM_BADGE=/brand/elosync-app-icon-light.pngSPA (.env / Forge config.js):
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_VAPID_KEY=VITE_FIREBASE_VAPID_KEY is the Firebase Console Web Push certificates key. See Notification System for the full ops checklist.
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). |
| Automation webhooks | Optional AUTOMATION_WEBHOOK_SECRET for default outbound HMAC when a workflow webhook action omits its own secret. |
| Nightwatch / Telescope / Sentry | Disabled by default in .env.example; enable intentionally. |
| Laravel Pulse | Enabled by default. Dashboard at /pulse on the central domain. Access: central roles superadmin, developer, tester — open from Central SPA Settings → Pulse (full-page redirect via signed session bridge). Not gated by Spatie permissions. |
| Laravel Horizon | Enabled when installed. Dashboard at /horizon on the central domain. Same role-only access as Pulse — open from Central SPA Settings → Horizon. Production queue workers run through Horizon (php artisan horizon); see Laravel Forge. |
Monitoring
- Pulse — In-app performance dashboard (slow requests, queries, jobs, server metrics). Operators with the roles above open Settings → Pulse in the Central SPA; Pulse opens in a new tab on the backend domain while Central stays on the dashboard. Use Back to Central in the Pulse header to return to the SPA. Run
php artisan pulse:checkas a persistent process so the Servers card receives metrics. In production preferPULSE_INGEST_DRIVER=redisplus aphp artisan pulse:workdaemon so request/queue workers do not write Pulse rows inline (see Laravel Forge). - Horizon — Redis queue dashboard (throughput, wait times, failed jobs, worker status). Same roles open Settings → Horizon in a new tab. Locally run
php artisan horizoninstead ofqueue:workwhen Horizon is installed. Production: one Forge daemon (php artisan horizon); remove separatequeue:workprocesses after cutover. - Nightwatch / Telescope — Optional; enable per environment policy.
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 | EloSync-Backend |
| 3 | php artisan horizon (or queue:work --queue=automations,emails,default without Horizon) | EloSync-Backend |
| 4 | php artisan schedule:work | EloSync-Backend (optional) |
| 5 | php artisan pulse:check | EloSync-Backend (optional; Servers card) |
| 6 | npm run dev | EloSync-Frontend |
| 7 | npm run docs:dev | EloSync-Docs (when editing docs) |
9. Verify the install
- [ ]
GET http://elosync-backend.test/upreturns 200 - [ ] Central login works with
superadmin@saas.com/password - [ ] Tenant login works with
demo@demo.com/password(local demo workspace) - [ ] 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 EloSync-Docs - [ ] Settings → Pulse opens Laravel Pulse in a new tab (superadmin / developer / tester); live cards update without 500 errors
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 (EloSync-Backend) | main | Composer, migrate --force, optimize, queue/Reverb restart |
SPA (EloSync-Frontend) | build-artifacts | Activate release + generate /config.js from site .env |
Docs (EloSync-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 |