Development

This guide covers the development workflow, tests, demo mode, project structure, and deployment process for the SaaS Template.

Development Commands

Server & Assets

# PHP server, queue listener, Pail logs, and Vite together
composer dev

Database

php artisan migrate

Stripe & Queue

stripe listen --forward-to localhost:8000/stripe/webhook

Custom Artisan Commands

php artisan app:add-permissions-to-new-modules

Testing & Code Quality

The PHP suite uses Pest 4 on an in-memory SQLite database. Subscription tests live in tests/Feature/Subscription and cover the billing page, the Subscribed middleware, and the Product model. Demo mode tests live in tests/Feature/Demo.

composer test

GitHub Actions run Pint, the frontend format and lint scripts, and the test suite on pushes and pull requests to develop and main.

Demo Mode

Demo mode turns an instance into a public, resettable live demo. It exists on the feature/demo-mode branch and is off unless DEMO_MODE=true.

What It Does

  • Banner — A bar at the top of the panel (login page included) reads "Live demo — data resets every night" and links to the product page set in DEMO_PRODUCT_URL.
  • Demo accounts — demo:seed creates an admin (admin@demo.omega-studio-software.com, role Super Admin) and a user (user@demo.omega-studio-software.com, role Customer). Their shared password is defined in config/demo.php.
  • Seed data — Roles, permissions (if missing), role-permission assignments, and the three plans from ProductSeeder.
  • Guarded credentials — Demo accounts cannot have their password or email changed, from the profile page or the Users resource, and cannot be deleted.
  • Mail — The mail driver is forced to log.
  • Uploads — Demo::uploadMaxKilobytes() caps uploads at 2 MB in demo mode.
  • Stripe keys — demo:seed warns when STRIPE_SECRET starts with sk_live_. Use test keys on demo instances. Plans without a stripe_id are created in Stripe by ProductSeeder.

Commands

php artisan demo:seed

Both commands fail when DEMO_MODE is off, and refuse to run unless APP_URL has a host starting with demo- or DEMO_ALLOW_RESET=true is set. When demo mode is on and the host allows it, demo:reset is scheduled daily at 03:00.

Configuration

  • Name
    DEMO_MODE
    Type
    boolean
    Description

    Enable demo mode. Default: false

  • Name
    DEMO_ALLOW_RESET
    Type
    boolean
    Description

    Override the demo- host check. Default: false

  • Name
    DEMO_PRODUCT_URL
    Type
    string
    Description

    Link target in the banner.

Project Structure

Application Core

  • app/Models/ — User, Product, Role, Permission, Activity, Email, Sms.
  • app/Policies/ — AbstractPolicy and per-model policies, including ProductPolicy.
  • app/Observers/ — UserObserver, ProductObserver.
  • app/Listeners/ — AddUserFreeTrialOnUserCreation, StripeEventListener, FilamentEmailLogger.
  • app/Traits/ — HasSubscriptionAttributes, ImplementSubscriptionFunctions.
  • app/Support/ — Demo and DemoSchedule.

HTTP Layer

  • app/Http/Controllers/ — SubscriptionController.
  • app/Http/Middleware/ — Subscribed, Customer.
  • routes/web.php — Redirect from / and the subscription.* routes.

Filament Admin Panel

  • app/Filament/Resources/ — Products, Users, Roles, Activities, Emails, Sms.
  • app/Filament/Pages/ — BillingInformation, HealthCheckResults, ViewLog.
  • app/Filament/Auth/ — EditProfile.
  • resources/views/filament/pages/ — Billing page view with plan cards.

Database & Config

  • database/ — Migrations, factories (User, Email, Product), and seeders.
  • config/ — Includes cashier.php, permission.php, activitylog.php, backup.php, health.php, sentry.php, and demo.php.

Tests, CI & Deploy

  • tests/Feature/Subscription/ and tests/Feature/Demo/ — Pest tests.
  • .github/workflows/ — lint.yml and tests.yml.
  • Envoy.blade.php — Deployment tasks.

Deployment

Using Laravel Envoy

Set DEPLOY_USER, DEPLOY_HOST, DEPLOY_REPOSITORY, and DEPLOY_APP_DIR (and optionally DEPLOY_BRANCH, default main), then run:

envoy run deploy

The deploy story runs pull-repository (git fetch and git pull), run-composer (composer install, composer dump-autoload, php artisan migrate --force, php artisan optimize:clear), and run-node (npm install and npm run build) on the target server.

Post-Deployment Steps

  1. Stripe webhook — Create an endpoint in the Stripe Dashboard pointing to https://yourdomain.com/stripe/webhook and set STRIPE_WEBHOOK_SECRET.
  2. Queue worker — Run php artisan queue:work under a process manager. Webhook events are processed by a queued listener.
  3. Scheduler — Add the Laravel scheduler to cron:
* * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1
  1. Web server — Point the document root to public/ and make storage/ and bootstrap/cache/ writable.
  2. Products — Create plans in the Products resource (or run the product seeder) so Stripe products and prices exist before users register.
  3. Verify — Run php artisan health:check and open Health Check Results.

Was this page helpful?