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.
php artisan db:seed also runs ProductSeeder, which creates three plans (Starter, Professional, Enterprise) and a matching Stripe product and monthly price for each. It needs a working STRIPE_SECRET.
Configuration
- Set database credentials in
.env. - Add Stripe keys from the Stripe Dashboard (Developers, API keys):
STRIPE_KEYandSTRIPE_SECRET. - Forward webhooks locally and copy the signing secret into
STRIPE_WEBHOOK_SECRET:
stripe listen --forward-to localhost:8000/stripe/webhook
- For production, create a webhook endpoint in the Stripe Dashboard pointing to
https://yourdomain.com/stripe/webhook. - 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:
rootand 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 inusd.
- 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 thefeature/demo-modebranch.
- 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.
Use only placeholder or test-mode Stripe values in .env.example, and never commit live keys.
Authentication & Roles
The panel at /app offers login, registration, and profile editing.
- Super Admin — Full access through a
Gate::beforehook, 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
AbstractPolicyand map abilities to<Model>.view,.create,.update, and.deletepermissions, generated for each model byPermissionSeeder. php artisan db:seedcreates a Super Admin with emailtest@example.comand passwordpassword. Change or remove it before any real deployment.
Payments & Subscriptions
Flow
- Register at
/app/register. A listener on Filament'sRegisteredevent callsaddTrial(30), which creates adefaultsubscription 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. - Use the app during the trial. The
Subscribedmiddleware lets Customers through whilehasActiveTrialorhasPaidActiveSubscriptionis true. - Without a trial or subscription, Customers are redirected to the billing page (
/app/billing-information), which lists the products. - 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. - 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_atfromcancel_at_period_endorcancel_at, and clears it for resumed subscriptions.
- Name
customer.subscription.deleted- Type
- Event
- Description
Marks the subscription
canceledand setsends_atto 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
- Run
php artisan db:seedand sign in as the seeded Super Admin. - Review the three seeded plans under Products.
- Start the Stripe CLI listener and a queue worker (
composer devincludes the queue listener). - Register a new account in a private window to receive the 30-day trial.
- Open Billing from the user menu, choose a plan, and pay with a Stripe test card.
- Check Users, the Activity Log, and the Health Check Results as Super Admin.