# Setup and maintenance

> Every runtime command of an application binary, with its flags and purpose, from migrations and the server to workers, admin accounts and realtime checks.

Every application binary carries the framework's runtime commands. The examples use a binary named `acme`; yours is named by `binary:` in `summer.yaml`.

## Migrations

| Command | Flags | Purpose |
|---------|-------|---------|
| `migrate` | none | Runs the framework migrations, then every plugin's migrations in dependency order. |
| `migrate:rollback` | `--plugin <id>` | Rolls back the last migration of the plugin; without the flag, of the last activated plugin that has migrations. |
| `migrate:status` | none | Prints a table of plugin, history table and applied migration IDs. |

```sh
./bin/acme migrate
./bin/acme migrate:status
./bin/acme migrate:rollback --plugin acme.blog
```

Each plugin keeps its own migration history table, so rolling back one plugin never touches another. The migrations are listed in [lagoon](/docs/api/lagoon.md).

## Application key

| Command | Flags | Purpose |
|---------|-------|---------|
| `key:generate` | none | Prints a fresh base64 32-byte key for `app.key`. It writes nothing and needs no database. |

```sh
./bin/acme key:generate
```

Copy the printed value into `SUMMER_APP__KEY`. When you rotate the key, keep the old one in `app.previous_keys` so existing encrypted columns can still be read.

## The HTTP server

| Command | Flags | Purpose |
|---------|-------|---------|
| `serve` | `--addr` (default `:8080`) | Opens the database and uploads bucket, builds the router, starts the in-process job worker and serves HTTP until SIGINT or SIGTERM, then shuts down within 10 seconds. |
| `route:list` | none | Builds the router the way `serve` does, without opening the database or listening, and prints every route with its method, pattern, plugin, middleware and raw flag. |

```sh
./bin/acme route:list
./bin/acme serve --addr 127.0.0.1:8080
```

The default `--addr` listens on every interface. Pass a loopback address during development, and put a reverse proxy in front of the binary in production. The routing options are in [surf](/docs/api/surf.md).

## Admin accounts

| Command | Arguments and flags | Purpose |
|---------|---------------------|---------|
| `admin:create` | `--email`, `--password` (both required), `--login`, `--role <code>`, `--superuser` | Creates an activated backend administrator. `--login` defaults to the lower-cased email. |
| `admin:reset-password` | `<identifier>` (login or email), `--password` | Sets a new password and revokes every token issued before the reset. |

```sh
./bin/acme admin:create --email admin@example.com --password '<secret>' --superuser
./bin/acme admin:reset-password admin@example.com --password '<secret>'
```

Passwords passed as flags end up in your shell history. Prefer reading them from a secrets manager into a variable. The admin is described in [cabana](/docs/api/cabana.md).

## Queues and the scheduler

| Command | Arguments and flags | Purpose |
|---------|---------------------|---------|
| `queue:work` | `--queue <name>`, repeatable | Runs a job worker in the foreground on the named queues (default: every known queue) until SIGINT or SIGTERM. An unknown queue is an error that lists the known ones. |
| `queue:clear` | `[queue]` (default `default`) | Deletes the waiting, scheduled and retryable jobs of one queue and prints how many it cleared. Running jobs are never touched. |
| `schedule:run` | `--once` | Without `--once`, runs a scheduler-only worker until stopped. With `--once`, runs the entries due in the current minute and exits, for system cron. |

```sh
./bin/acme queue:work --queue default --queue imports
./bin/acme queue:clear imports
./bin/acme schedule:run --once
```

`serve` runs a job worker in the same process unless `queue.work_in_serve` is `false`; set it to `false` when you run `queue:work` separately. [Task scheduling](/docs/plugins/scheduling.md) explains the scheduler, and [conga](/docs/api/conga.md) the queue settings.

## Realtime and push

These commands are not added by the generated `main`. An application that uses Centrifugo or Web Push appends them to the list one of its plugins returns from `pact.HasCommands`: `centrifugo.Commands` returns `websockets:health`, and `flare.Commands` returns the two push commands.

| Command | Arguments and flags | Purpose |
|---------|---------------------|---------|
| `websockets:health` | none | Calls the Centrifugo `info` API and prints the configuration. Exits 1 when the API key is missing or the call fails. The key itself is never printed. |
| `websockets:generate-vapid-keys` | `--update`, `--show-current` | Shows the configured VAPID keys, truncated, then generates a new pair. With `--update` it saves them to the environment's `overrides.yaml`; without it, it prints the variables to set by hand. |
| `websockets:test-push` | `<user_id>`, `--show-config` | Lists a user's push subscriptions and, after confirmation, sends one encrypted test notification to each. |

```sh
./bin/acme websockets:health
./bin/acme websockets:generate-vapid-keys --show-current
./bin/acme websockets:test-push 1
```

The settings are in [lighthouse](/docs/api/lighthouse.md) and [flare](/docs/api/flare.md).
