Environments
| Environment | Branch | Env file | SSR | Notes |
|---|---|---|---|---|
| Local | feature branches | .env from .env.example | Optional via Vite | npm run dev + @inertiajs/vite — no separate Node process |
| Staging | staging | .env on server (from .env.staging.example / CI secrets) | Off | Client-only on cPanel (INERTIA_SSR_ENABLED=false) |
| Production | main | server .env | Off | Client-only npm run build; APP_DEBUG=false |
Staging and production on cPanel stay client-rendered. Local Vite may still use Inertia’s built-in SSR during npm run dev only.
Staging checklist
- Subdomain e.g.
staging.sawtee.org→ document rootpublic/ - Separate MySQL database
- GitHub Environment
staging+STAGING_*secrets for app/DB/target dir; reuse prodSSH_*,MAIL_*, andDB_PASSWORD(see main README) - Push to
staging→.github/workflows/deploy-staging.yml(no cPanel Node.js App required)
TEMPORARY: responsive-image backfill
Staging and production deploys currently run php artisan sawtee:backfill-responsive-images after migrate so existing uploads get Spatie width variants and tiny placeholders. The command isolates each small batch in its own PHP process so cPanel’s 128MB CLI limit cannot accumulate across 1,000+ images.
Remove those TEMPORARY workflow steps from .github/workflows/deploy-staging.yml and .github/workflows/deploy.yml after the command has succeeded once on each environment. New uploads generate variants on their own; leaving the step in place is cheap (it skips items that already have variants) but still unnecessary.
Env files in the repo
| File | Committed? | Role |
|---|---|---|
.env.example | Yes | Fresh Laravel-style defaults for new installs |
.env.staging.example | Yes | Staging template (no secrets) |
.env / .env.staging | No | Real secrets; never commit |
Copy templates:
cp .env.example .env
cp .env.staging.example .env.stagingAnalytics (optional)
First-party page views are controlled in config/analytics.php. Staging checklist keys (also in .env.staging.example):
| Variable | Default | Purpose |
|---|---|---|
ANALYTICS_ENABLED | true | Record public page views |
ANALYTICS_DEDUPE_MINUTES | 30 | Same session + path not counted again within this window |
ANALYTICS_HASH_SALT | falls back to APP_KEY | Salt for IP / user-agent hashes — set a dedicated value in production |
Admin paths are never recorded. Dashboard analytics load as a deferred Inertia prop.
Branded errors vs debug
With APP_DEBUG=true in local or development, Laravel’s detailed exception UI is kept (branded Inertia error pages are skipped). Staging/production should run APP_DEBUG=false so visitors see the branded Errors/Error page for common statuses (403, 404, 500, 503). Visitor-facing strings on that page are edited in Site Settings → Error pages.
Session cookies on HTTPS
Set SESSION_SECURE_COOKIE=true on Herd, staging, and production so the session cookie is only sent over HTTPS (required for a trustworthy PWA install surface). Leave unset only if you deliberately run plain HTTP locally.
Progressive Web App
Production client builds emit a service worker and web manifest (npm run build). Deploy health checks should confirm public/sw.js and public/manifest.webmanifest exist after build. The PWA is public-site only — it does not extend admin sessions or cache /admin.