# Operations and deployment

## Environment configuration

Minimum tenancy settings are:

```dotenv
APP_ENV=production
APP_URL=https://console.example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=matjari_central
DB_USERNAME=...
DB_PASSWORD=...

LEGACY_CENTRAL_SCHEMA=false
TENANCY_CENTRAL_CONNECTION=mysql
TENANCY_TEMPLATE_CONNECTION=mysql
TENANCY_CENTRAL_DOMAINS=console.example.com
TENANCY_PLATFORM_DOMAIN=stores.example.com
TENANCY_STORE_SESSION_COOKIE=matjari_store_session

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
```

Important rules:

- `LEGACY_CENTRAL_SCHEMA=false` is required in production.
- `CACHE_STORE` must be taggable (Redis is the supported production choice). The application fails fast during tenancy initialization when the cache store has no `tags()` method.
- Tenant database names are generated by Stancl from the tenant ID. Do not expose database credentials or arbitrary connection names in Filament forms, commands, or HTTP input.
- The central database user must be able to create/migrate/delete tenant databases, or the configured MySQL manager must use a controlled provisioning account.
- `db:seed` seeds only central authorization and company-admin records. It never
  writes tenant business or geography data.

If a migration review needs the old geography data, export it explicitly from
the configured `ysf` connection:

```bash
php artisan legacy:export-geography
```

The command writes CSV seed data under `database/seed-data/geography`; it does
not read from the YSF database during normal tenant provisioning. The CSV
seeders run only in `TenantDatabaseSeeder`, after a tenant connection has been
initialized.

## Initial deployment

The tenancy migration split is designed for a fresh-start deployment:

```bash
php artisan optimize:clear
php artisan migrate --force --no-interaction
php artisan db:seed --force --no-interaction
php artisan queue:work --queue=default
```

With `LEGACY_CENTRAL_SCHEMA=false`, central migration creates only control-plane tables. Tenant databases are created and migrated by provisioning; do not run tenant migrations against the central database.

After deploying workers, create a store through the console or command. Wait for `pending_admin`, create the first Admin, and verify the platform domain before handing over access.

## Tenant maintenance

Run tenant migrations and seeders through the wrappers so the tenant connection is selected safely:

```bash
php artisan tenant:migrate <tenant-id> --pretend
php artisan tenant:seed <tenant-id>
```

`tenant:seed` runs `TenantDatabaseSeeder`, which creates tenant authorization,
defaults, currencies, address types, geography, and delivery-time data. It is
safe to rerun because the seeders use idempotent upserts/default checks.

Review `TenantProvisioningRun` records after failures. A failed database is retained for diagnosis until an operator explicitly archives/cleans it.

## Backup and deletion policy

- Back up the central database and every tenant database independently.
- Include the tenant ID/database name mapping in protected operational metadata.
- Suspend a store before archiving it.
- Archive requires `--confirm`; database destruction additionally requires `--confirm` and is queued.
- `DeleteTenantDatabaseJob` rechecks that the tenant is still archived immediately before deletion. A reactivated tenant is not deleted by a stale job.
- Database deletion is irreversible; verify backups and tenant identity before dispatching it.

## Cache, files, queues, and sessions

Stancl bootstrappers scope database, cache, filesystem, and queue behavior after tenancy initialization. Store uploads use tenant-scoped storage roots. Keep console and store session cookies distinct; the store panel uses `TENANCY_STORE_SESSION_COOKIE` and `ScopeSessions`.

Every custom queued job that reads tenant models must carry the tenant ID and initialize tenancy before querying. Prefer `TenantConnectionManager` or Stancl's tenant-aware queue behavior. Never rely on a tenant context left by an earlier job in a long-running worker.

## Observability

Provisioning and domain verification failures are recorded on central provisioning/domain records and in activity logs. Add the tenant ID to structured log context for new services/jobs. Monitor:

- queued provisioning age and failure count;
- tenants stuck in `provisioning` or `pending_admin`;
- DNS verification failures;
- tenant database creation/migration errors;
- cache/queue worker health;
- central-to-tenant database connection latency.
