Browse the manual

CLI commands

Artisan commands for installing, updating, and maintaining Made with Pepper.

On this page

For: developers and system administrators managing Made with Pepper from the command line.

Made with Pepper does not require CLI access for daily use. The web installer handles setup. These commands are for developers, hosting administrators, and troubleshooting.

Installation and setup

Command Description
php artisan migrate Run database migrations
php artisan db:seed --class=DemoSeeder Unavailable; choose sample content during fresh web installation
php artisan demo:reset Unavailable, including with --force; leaves existing data unchanged

To explore sample content, create a separate disposable installation and enable Add demo data in the web installer. Samples belong to the owner account you create; no extra logins are added.

Disposable demo rebuild

demo:rebuild creates or rebuilds a separate disposable demo from a deployment script. It does not run the web installer.

Use a separate disposable database on MySQL 8.4. Keep APP_URL set to your demo's address. The command accepts any address and requires no extra URL setting. A first deployment can create the demo through the command; you do not need to open the web installer.

Rebuilding deletes all business records in the configured database. It keeps existing login credentials and supported roles. The encrypted recovery snapshot holds logins, not business records. Use this command only for a disposable demo.

  1. Set DEMO_MODE=true, APP_IS_INSTALLED=true and MAIL_MAILER=log in the demo's environment file.
  2. Keep the existing APP_KEY and database connection.
  3. Stop and drain the demo's cron jobs and queue workers.
  4. Keep storage shared across releases.
  5. Run these commands in the demo's application directory:
php artisan config:clear
php artisan down
php artisan demo:rebuild --force
php artisan cache:clear
php artisan optimize
php artisan storage:link

The command requires demo mode, installed state, maintenance and --force. It checks the live database version before any writes. MariaDB and MySQL versions other than 8.4 refuse. For an empty database, add --initialize to create the demo accounts and samples.

Existing accounts need credentials and owner, admin, accountant or employee roles. The demo must have one active owner. Unsupported custom roles refuse before the rebuild. Rebuilding creates new account IDs to invalidate old sessions. Old uploaded files remain in shared storage.

If all commands succeed, activate the new release. Run php artisan up. Resume cron jobs and queue workers. Check each existing login and the sample invoices.

First Forge installation

Use your dedicated empty MySQL 8.4 database. Set DEMO_MODE=true and APP_IS_INSTALLED=true in Forge. Keep your current APP_KEY and database settings. The command creates the tables and samples without changing the environment file or key. It uses an array mailer during setup, so your configured mail provider receives no messages.

Use this deployment script once:

set -eu

$CREATE_RELEASE()
cd "$FORGE_RELEASE_DIRECTORY"

composer dump-autoload --optimize --no-scripts
$FORGE_PHP artisan config:clear
$FORGE_PHP artisan down
$FORGE_PHP artisan demo:rebuild --initialize --force
$FORGE_PHP artisan cache:clear
$FORGE_PHP artisan optimize
$FORGE_PHP artisan storage:link

$ACTIVATE_RELEASE()
$RESTART_QUEUES()
$FORGE_PHP artisan up

The demo sign-in picker uses these public accounts. Each starts with password welcome3210:

Email Role
[email protected] Owner
[email protected] Admin
[email protected] Accountant
[email protected] Employee

Initialization checks only the configured database and refuses any existing table or view there. A matching encrypted snapshot permits retry of its own interrupted setup. It does not adopt an unknown partial installation. Keep cron jobs and queue workers stopped during deployment, and keep storage shared across releases.

After initialization succeeds, remove --initialize for later deployments. The normal rebuild keeps existing account passwords, including passwords you changed. You do not need to run the installer or copy an environment file back into Forge.

Forge deployment

Run the rebuild before activating the new release. Keep the normal dependency and frontend build stage. composer dump-autoload does not install dependencies or build assets.

set -eu

$CREATE_RELEASE()
cd "$FORGE_RELEASE_DIRECTORY"

composer dump-autoload --optimize --no-scripts
$FORGE_PHP artisan config:clear
$FORGE_PHP artisan down
$FORGE_PHP artisan demo:rebuild --force
$FORGE_PHP artisan cache:clear
$FORGE_PHP artisan optimize
$FORGE_PHP artisan storage:link

$ACTIVATE_RELEASE()
$RESTART_QUEUES()
$FORGE_PHP artisan up

Stop and drain cron jobs and queue workers before this script starts. Resume them after successful activation. Keep storage shared across releases.

Failed rebuild

A refusal or failure returns a nonzero exit code. Configuration refusals explain the missing condition. Database failures show the stage, SQLSTATE and driver error code. Unexpected failures also show the stage and exception type. Errors include the PHP source file and line when the source belongs to the application or its dependencies. Other source locations show unavailable. They do not print SQL, connection details, absolute server paths or account values.

If the command reports APP_IS_INSTALLED must be true, set APP_IS_INSTALLED=true in the demo environment. Run php artisan config:clear and retry. For a first deployment to an empty database, use --initialize --force.

If a login table is missing, the command names users, roles or model_has_roles. Verify that the release uses the existing demo database. For a new empty demo, use the first-deployment script above. Do not create empty login tables to bypass the check. An encrypted recovery snapshot allows a retry after an interrupted rebuild even if those tables are absent.

Keep maintenance active. Do not activate the new release. Keep storage/app/private/forge-demo/accounts.enc or initialize-accounts.enc if it exists. Keep the same APP_KEY, database connection and shared storage. Correct the reported condition, then rerun the same command. Retain --initialize when you retry an interrupted initialization. Initialization and normal rebuild share a lock and refuse while the other operation has a pending snapshot.

If failure occurs after table replacement, the previous business records are gone. Activating old code does not restore them. The retry recreates the demo's tables and views, even if the migration history table is missing. It restores logins from the encrypted snapshot and creates new samples. The operation stays within the configured database. Success removes that snapshot and leaves maintenance active.

Cache management

Command Description
php artisan config:cache Cache configuration (recommended for production)
php artisan config:clear Clear configuration cache
php artisan route:cache Cache routes (recommended for production)
php artisan route:clear Clear route cache
php artisan view:cache Cache compiled Blade views
php artisan view:clear Clear compiled Blade views
php artisan cache:clear Clear application cache

Maintenance

Command Description
php artisan down Put the application in maintenance mode
php artisan up Bring the application back online
php artisan storage:link Create the public storage symlink

For replacement recovery, run storage:link after down and before recovery:restore. It links public/storage to that replacement's storage/app/public.

Keep the storage directories as real directories. Follow the backup recovery steps or replacement update procedure.

Automation

These commands run automatically when you configure a cron job. You can also run them from the command line.

Command Description Schedule
php artisan outbox:process Send queued emails, retry temporary failures, and store missing issued originals Every minute
php artisan recurring:generate Generate invoices for all active recurring schedules that are due Daily at 06:00 in the business timezone
php artisan reminders:send Queue scheduled payment reminders for overdue and upcoming-due invoices Daily at 07:00 in the business timezone
php artisan backup:create Create a database and media backup Daily or weekly (configurable in Settings)
php artisan backup:clean Remove backups exceeding the retention limit Not scheduled; creating a backup applies retention

Recurring invoice generation runs first (06:00), then reminders (07:00), so Made with Pepper can check the new invoices when evaluating reminders.

Each recurring:generate run produces at most one invoice per schedule. If the server missed multiple days, subsequent runs catch up one invoice at a time.

The email outbox

Document emails, reminders and auto-sent recurring invoices go through an outbox in the database. outbox:process needs no queue worker. Each run does this:

  1. It marks an attempt that has been busy for more than 10 minutes as Email result unknown.
  2. It tries up to 50 emails that are due, oldest first.
  3. It stores up to 20 missing issued originals.

The command prints the number of attempts and stored originals. If an email waits more than 15 minutes past its time, the document page says "The scheduler has not run since {time}. Check the cron job." Set up email delivery explains the retries.

Backups

Create a backup

php artisan backup:create

Creates an authenticated database and media backup in storage/backups/. After success, it applies the configured retention limit.

Option Description
--encrypted Ask for a passphrase at a hidden prompt. Use at least 6 characters
--sealed Mark a final snapshot. Requires maintenance mode and --confirm-drained
--confirm-drained Confirm that HTTP requests, cron and queue workers have stopped and drained
--passphrase=SECRET Existing script option. Its value can appear in process arguments; prefer the hidden prompt
php artisan backup:create --encrypted

A sealed backup records your confirmation. It cannot independently prove that the host stopped all writers.

Recover or verify

Run recovery only in a separate directory with the original APP_KEY. Use an empty database on the same engine as the backup. MySQL backups need MySQL 8.4. MariaDB backups need MariaDB 10.11, 11.4 or 11.8. Keep the replacement in maintenance mode.

Command Purpose
php artisan recovery:restore /secure/backup.zip Restore an authenticated same-version backup into empty storage and database
php artisan recovery:restore /secure/backup.zip --encrypted Ask for the archive passphrase at a hidden prompt
php artisan recovery:restore /secure/backup.zip --upgrade Check target file integrity and the declared source version and schema, then migrate the replacement
php artisan recovery:verify Recheck the receipt, key, migrations and issued originals before activation
php artisan release:verify /secure/release.zip Check release file integrity and runtime compatibility against the manifest

You can combine --encrypted and --upgrade. Failed checks return a nonzero exit code. No recovery command exits maintenance or switches traffic.

Follow Backups for the complete recovery procedure and Updating for supported upgrades.

Clean old backups

php artisan backup:clean

Removes backups that exceed the retention limit. The command reads the retention count from Settings > Backups (default: 5) and keeps only the N most recent backups.

Options:

Option Description
--keep=N Override the retention count from settings. Accepts 1 to 100.

Example:

# Keep only the 3 most recent backups
php artisan backup:clean --keep=3

Cron setup

Made with Pepper uses Laravel's task scheduler. Add this cron entry to your server:

* * * * * cd /path-to-made-with-pepper && php artisan schedule:run >> /dev/null 2>&1

Replace /path-to-made-with-pepper with the absolute path to your Made with Pepper installation.

cPanel: Go to Cron Jobs, set the interval to "Once Per Minute (* * * * *)", and enter the command above.

Plesk: Go to Scheduled Tasks, add a new task with the command above, and set the schedule to every minute.

VPS / dedicated: Add the cron entry via crontab -e for the web server user (e.g. www-data).

Without cron, recurring invoices and automatic reminders do not run, and queued emails wait. You can still run the commands from the command line.

Queue

Scheduled tasks and document emails run without a queue worker. The outbox:process command sends document emails and reminders. User invitations send during the request after saving the invitation. You do not need queue:work or a QUEUE_CONNECTION change for these features.

Database

Command Description
php artisan migrate:status Check migration status

Do not use migrate:rollback or destructive database commands to recover an interrupted web installation. Fix the reported problem and retry the installer with the same database details. If installation stopped while it created the database tables, follow Failure recovery. Remove partial tables only from the new, empty target created by that failed attempt. Never remove existing business data. If Made with Pepper refuses the partial target, create a new empty database or contact support with the setup reference.

Production optimization

Run these after deploying or updating Made with Pepper:

php artisan config:cache
php artisan route:cache
php artisan view:cache

Need help with the product?

Contact support