# Laravel apps

Besides hotsites and WordPress sites, the server runs **Laravel apps**. The
first one is **`suite`**, the PHP com Rapadura community site at
<https://phpcomrapadura.org> (the old WordPress site lives on at
`legacy.phpcomrapadura.org`, and `novo.phpcomrapadura.org` redirects to the
apex).

`rapadura artisan` gives you and your agent the app's `artisan`, the way
`rapadura wp` gives `wp-cli`: no SSH, no server password, a policy that lets
you inspect and operate the app without changing its code, its database or
its secrets, and every command in the audit log.

It does not deploy. Code changes go through the app's repository
([PHPcomRapadura/suite](https://github.com/PHPcomRapadura/suite)): a merge
to `main` deploys on its own, and that deploy runs the migrations right
after a database dump. `rapadura artisan` is for looking at the running app
and looking after it.

## Who can use it

- The **owner** uses every app.
- Anyone else uses the apps the owner granted them
  (`rapadura admin artisan-access suite --grant <login>`; see
  [Administration](admin.md#laravel-apps)).

```sh
rapadura artisan apps
```

```text
APP    URL                         ALSO                    MEMBERS
suite  https://phpcomrapadura.org  www.phpcomrapadura.org  -
```

An app you have no access to answers `not_found`, the same as one that does
not exist.

## Run artisan

Everything after `--` goes to `artisan`. It runs on the server as the app's
user, in the release that is live, without prompts (`--no-interaction`),
for at most 3 minutes.

```sh
rapadura artisan suite -- about
rapadura artisan suite -- route:list --path=cfp
rapadura artisan suite -- migrate:status
rapadura artisan suite -- db:show --counts
rapadura artisan suite -- config:cache
rapadura artisan suite -- cache:clear
rapadura artisan suite -- down --retry=60 --secret=let-me-in
rapadura artisan suite -- up
```

```sh
rapadura artisan suite -- about --only=environment
```

```text
  Environment ................................................................
  Application Name .......................................... PHP com Rapadura
  Laravel Version .................................................... 13.34.0
  PHP Version ......................................................... 8.4.23
  Composer Version .................................................... 2.10.2
  Environment ..................................................... production
  Debug Mode ............................................................. OFF
  URL ..................................................... phpcomrapadura.org
  Maintenance Mode ....................................................... OFF
  Timezone ............................................................... UTC
  Locale ............................................................... pt_BR
```

You can name the app by any of its hosts too
(`rapadura artisan phpcomrapadura.org -- about`). The name `suite` stays
the same whatever the hosts become, so scripts and prompts should use it.

Output and exit status are artisan's own. With `--json` you get `stdout`,
`stderr` and `exit_code` separately. Through MCP the tools are `list_apps`
and `artisan` (`{"app": "suite", "args": ["route:list", "--json"]}`).

### What is allowed

| for | commands |
|---|---|
| looking at the app | `about`, `env`, `list`, `help`, `inspire`, `route:list`, `migrate:status`, `schedule:list`, `event:list`, `db:show`, `db:table` |
| caches | `optimize`, `optimize:clear`, `config:cache`, `config:clear`, `route:cache`, `route:clear`, `view:cache`, `view:clear`, `event:cache`, `event:clear`, `clear-compiled`, `cache:clear`, `cache:forget` |
| maintenance mode | `down` (with `--retry=`, `--refresh=`, `--secret=`, `--with-secret` and `--redirect=/a-path-on-the-site`), `up` |
| housekeeping | `auth:clear-resets`, `sanctum:prune-expired` |

Command names must be written in full: artisan accepts abbreviations
(`tink` runs `tinker`), rapadura does not.

Always refused, with the reason in the error:

| commands | why |
|---|---|
| `tinker`, `invoke-serialized-closure` | they run arbitrary PHP |
| `migrate` and `migrate:*` (except `migrate:status`), `db:seed`, `db:wipe`, `model:prune` | they change the database outside a deploy; deploys run migrations after a dump |
| `db` | an interactive database shell; `db:show` and `db:table` describe the database |
| `config:show`, `key:generate`, `env:encrypt`, `env:decrypt` | they read or change secrets (`config:show` prints passwords) |
| `make:*`, `install:*`, `vendor:publish` and the other `*:publish`, `storage:link`, `schema:dump`, `package:discover` | they write code or files into the release; changes go through the repository |
| `serve`, `dev`, `queue:*`, `schedule:*` (except `schedule:list`) | long-running processes; the server runs the app, and it has no queue workers or scheduler |
| `model:show` | it instantiates any class by name |
| any argument starting with `--env` (`--env=local`, `schedule:list --environment=…`) | Laravel reads it as the environment, which the server fixes |
| `migrate:status --path`, `--realpath` | they read migrations from another directory |
| `down --redirect=<another site>`, `down --refresh=<anything but seconds>`, `down --render`, `down --status` | the site would send every visitor elsewhere; options are written with `=` |
| `cache:clear <store>`, `cache:clear --locks` | only the default cache store; `--locks` also empties the database that holds the sessions (everyone is logged out) |

A command that is on neither list is refused until the owner adds it
(`artisan_refused`, with the list in the hint). The policy binds the owner
too: anything beyond it is done on the server.

## Good to know

- **Changing `.env`.** Secrets never travel through rapadura: the
  administrator edits `.env` on the server. Then anyone with access applies
  it with `rapadura artisan suite -- config:cache`.
- **Maintenance mode.** `down` takes the site offline for everyone with a
  503. With `--secret=<word>`, visiting `https://<host>/<word>` once lets
  your browser through. Every deploy ends with `up`, so a merge to `main`
  brings the site back even if someone put it down by hand.
- **No secrets in the output.** `about`, `db:show` and `db:table` show
  drivers, the database name, host, user and table sizes, not passwords.
- **Audit.** Every command, refused or not, lands in the audit log as
  `artisan.run`, with the values of `--secret=` and similar flags hidden.

## Prompts to try

```prompt
Is the community site healthy? With rapadura artisan on suite, show me the environment, whether maintenance mode is on and whether any migration is pending.
```

```prompt
The administrator changed .env on the community site. Apply it with rapadura artisan (config:cache on suite) and confirm https://phpcomrapadura.org still answers.
```

```prompt
Put the suite in maintenance mode with a secret bypass word, give me the bypass URL, and bring it back up only when I tell you to.
```

## Errors

| code | when |
|---|---|
| `artisan_refused` | the command is outside the policy; the message says why, the hint what to do |
| `not_found` | no such app, or you have no access to it; `rapadura artisan apps` |
| `forbidden` | your token is read-only |
| `artisan_unavailable` | the Laravel lane is off on this gateway, or the server's list of apps is broken; tell the administrator |

All codes: [error codes](../errors.md).
