# Production dashboard authentication

The production dashboard uses Laravel's `web` guard and the existing database-backed users, sessions, tenants, and tenant memberships. There is no public registration or password-reset UI.

## Production settings

Set the public URL to the exact HTTPS deployment URL, including any subdirectory. Use secure, HTTP-only session cookies and keep the same-site policy at `lax` unless the deployment has a reviewed reason to change it.

```dotenv
APP_ENV=production
APP_DEBUG=false
APP_URL=https://gateway.example.org/smsgateway/public
SESSION_DRIVER=database
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
SESSION_PATH=/smsgateway/public
SESSION_DOMAIN=null
LOCAL_BROWSER_AUTH_ENABLED=false
```

Use `SESSION_PATH=/` when the application is deployed at the host root. Run configuration caching only after the environment has been reviewed. Never commit the production environment file.

## Provision the first authorized user

Use an interactive Tinker session on the server. Select an existing active tenant and create both the user and active membership. The password prompt below is hidden; do not place plaintext passwords in a command argument, source file, ticket, or shell history.

```bash
php artisan tinker
```

```php
use App\Domain\Authorization\Enums\TenantRole;
use App\Domain\Tenancy\Enums\TenantStatus;
use App\Models\Tenant;
use App\Models\TenantMembership;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use function Laravel\Prompts\password;

$tenant = Tenant::query()->where('public_id', 'REPLACE_WITH_TENANT_ULID')->where('status', TenantStatus::Active->value)->sole();
$secret = password('Initial password', required: true);
$user = User::query()->create(['name' => 'Administrator Name', 'email' => mb_strtolower(trim('admin@example.org')), 'password' => Hash::make($secret)]);
unset($secret);
TenantMembership::query()->create(['tenant_id' => $tenant->id, 'user_id' => $user->id, 'role' => TenantRole::TenantAdmin, 'status' => 'active', 'joined_at' => now()]);
```

Use a unique named account for each administrator. Confirm the selected tenant before creating the membership. Do not assign `platform_role` unless the operator has separately approved platform-wide access.

## Deployment and smoke test

1. Back up the environment and database according to the deployment runbook.
2. Deploy the reviewed commit and run the normal Laravel cache-clear/cache-build sequence. No migration is required by this milestone.
3. Confirm `GET /login`, `POST /login`, and `POST /logout` in `php artisan route:list` and confirm there is no registration route.
4. In a private browser window, open the public HTTPS root. Confirm it redirects to the login form on the same host and base path.
5. Sign in with an authorized test administrator. Confirm the correct tenant opens (or the selector appears for multiple workspaces), then sign out and confirm the protected workspace is no longer accessible.
6. Submit an incorrect password repeatedly and confirm the generic error remains safe and attempts become throttled. Do not perform this against a shared administrator account.

Rollback consists of restoring the prior reviewed application release and clearing/rebuilding Laravel caches. The existing user and membership rows can remain; they are compatible with the prior schema. Disable an account's dashboard access by changing its tenant membership status through an approved administrative operation, not by deleting tenant data.
