Getting Started

Follow these steps to run the SaaS Template locally with Stripe test mode. This guide covers installation, Stripe configuration, authentication, and how subscriptions work.

Installation

git clone https://github.com/feraandrei1/template-saas-app.git
cd template-saas-app

composer setup installs dependencies, copies .env.example to .env, generates the app key, runs migrations, and builds assets. Set the database and Stripe values in .env first. composer dev runs the PHP server, a queue listener, Pail, and Vite together. The panel is at http://localhost:8000/app.

Configuration

  1. Set database credentials in .env.
  2. Add Stripe keys from the Stripe Dashboard (Developers, API keys): STRIPE_KEY and STRIPE_SECRET.
  3. Forward webhooks locally and copy the signing secret into STRIPE_WEBHOOK_SECRET:
stripe listen --forward-to localhost:8000/stripe/webhook
  1. For production, create a webhook endpoint in the Stripe Dashboard pointing to https://yourdomain.com/stripe/webhook.
  2. Configure mail, and optionally Sentry, AWS S3, Vonage, and the DEPLOY_* variables.

Environment Variables

  • Name
    APP_NAME / APP_ENV / APP_KEY / APP_DEBUG / APP_URL
    Type
    string
    Description

    Standard Laravel settings. Defaults: Laravel, local, empty (generated), true, http://localhost.

  • Name
    DB_CONNECTION
    Type
    string
    Description

    Database driver. Default: mysql

  • Name
    DB_HOST / DB_PORT / DB_DATABASE
    Type
    string
    Description

    Defaults: 127.0.0.1, 3306, template_laravel_app.

  • Name
    DB_USERNAME / DB_PASSWORD
    Type
    string
    Description

    Database credentials. Defaults: root and empty.

  • Name
    SESSION_DRIVER / QUEUE_CONNECTION / CACHE_STORE
    Type
    string
    Description

    All default to database.

  • Name
    STRIPE_KEY
    Type
    string
    Description

    Stripe publishable key. Required for billing.

  • Name
    STRIPE_SECRET
    Type
    string
    Description

    Stripe secret key. Required for checkout, the billing portal, product sync, and trials.

  • Name
    STRIPE_WEBHOOK_SECRET
    Type
    string
    Description

    Webhook signing secret used to verify Stripe payloads.

  • Name
    CASHIER_CURRENCY
    Type
    string
    Description

    Default Cashier currency. Default: usd. Product prices created by the observer are always in usd.

  • Name
    CASHIER_PATH
    Type
    string
    Description

    Base path of Cashier routes, including the webhook. Default: stripe

  • Name
    MAIL_MAILER / MAIL_HOST / MAIL_PORT
    Type
    string
    Description

    Mail settings. Defaults: smtp, 127.0.0.1, 1025.

  • Name
    MAIL_FROM_ADDRESS / MAIL_FROM_NAME / CONTACT_TO_ADDRESS
    Type
    string
    Description

    Sender and contact addresses. Defaults: hello@example.com, ${APP_NAME}, contact@example.com.

  • Name
    AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION / AWS_BUCKET / AWS_ROOT
    Type
    string
    Description

    S3 storage. Optional.

  • Name
    SENTRY_LARAVEL_DSN / VITE_SENTRY_DSN_PUBLIC
    Type
    string
    Description

    Sentry DSNs for backend and browser. Optional.

  • Name
    VONAGE_KEY / VONAGE_SECRET
    Type
    string
    Description

    Vonage SMS credentials read by config/services.php.

  • Name
    DEPLOY_USER / DEPLOY_HOST / DEPLOY_REPOSITORY / DEPLOY_APP_DIR / DEPLOY_BRANCH
    Type
    string
    Description

    Envoy deployment settings. The branch defaults to main.

  • Name
    DEMO_MODE
    Type
    boolean
    Description

    Enables the live demo mode. Default: false. Present on the feature/demo-mode branch.

  • Name
    DEMO_ALLOW_RESET
    Type
    boolean
    Description

    Allows demo seed and reset on hosts that do not start with demo-. Default: false.

  • Name
    DEMO_PRODUCT_URL
    Type
    string
    Description

    Link target of the demo banner.

Authentication & Roles

The panel at /app offers login, registration, and profile editing.

  • Super Admin — Full access through a Gate::before hook, no subscription required. Sees the Products, Users, Roles, Activity Log, Health, and Log pages.
  • Customer — Assigned automatically to every new user by UserObserver. Customers are subject to subscription gating and see a Billing item in the user menu.
  • Policies extend AbstractPolicy and map abilities to <Model>.view, .create, .update, and .delete permissions, generated for each model by PermissionSeeder.
  • php artisan db:seed creates a Super Admin with email test@example.com and password password. Change or remove it before any real deployment.

Payments & Subscriptions

Flow

  1. Register at /app/register. A listener on Filament's Registered event calls addTrial(30), which creates a default subscription with a 30-day trial on the first product's monthly Stripe price. Stripe checkout needs trials of at least 2 days, so shorter values are raised to 2.
  2. Use the app during the trial. The Subscribed middleware lets Customers through while hasActiveTrial or hasPaidActiveSubscription is true.
  3. Without a trial or subscription, Customers are redirected to the billing page (/app/billing-information), which lists the products.
  4. Choose a plan. Each product links to /subscription/buy/{slug}, which creates a Stripe Checkout session. Success returns to the dashboard with ?checkout=success, cancel to the billing page with ?checkout=cancelled.
  5. Manage billing. Active subscribers and trial users who open the billing page are redirected to /subscription/billing-portal, the Stripe-hosted portal.

An unauthenticated visitor who opens a buy link gets a temporary guest account (role Customer), limited to 3 per IP address per hour, and continues to checkout.

Products

Products are managed in the panel (Shop group) with stripe_id, name, slug, description, features (tags), and price. A ProductObserver creates the Stripe product and a monthly recurring price in usd when a product is created, adds a new price when the price changes, renames the Stripe product on update, and deactivates it on delete. Products use soft deletes and are routed by slug.

Webhooks

Cashier serves the webhook at /stripe/webhook. StripeEventListener is queued and handles:

  • Name
    customer.subscription.updated
    Type
    Event
    Description

    Syncs ends_at from cancel_at_period_end or cancel_at, and clears it for resumed subscriptions.

  • Name
    customer.subscription.deleted
    Type
    Event
    Description

    Marks the subscription canceled and sets ends_at to now.

  • Name
    invoice.payment_succeeded
    Type
    Event
    Description

    Logs the paid invoice.

  • Name
    invoice.payment_failed
    Type
    Event
    Description

    Logs a warning for the failed invoice.

Basic Usage Flow

  1. Run php artisan db:seed and sign in as the seeded Super Admin.
  2. Review the three seeded plans under Products.
  3. Start the Stripe CLI listener and a queue worker (composer dev includes the queue listener).
  4. Register a new account in a private window to receive the 30-day trial.
  5. Open Billing from the user menu, choose a plan, and pay with a Stripe test card.
  6. Check Users, the Activity Log, and the Health Check Results as Super Admin.

Was this page helpful?