# Per-business API settings (Laravel 11)

The app is multi-tenant. AI provider API keys belong to each organization/workspace and are entered in **Settings → AI Providers**. Do not put customer AI keys in `.env` and do not use one customer's key for another organization.

## What stays in `.env`

Keep infrastructure secrets in `.env`: `APP_KEY`, database/Redis credentials, mail configuration, and deployment settings. Platform OAuth client credentials (Meta, TikTok, LinkedIn, Google/YouTube, X) are normally credentials for the Social Manager application registered with those platforms. Individual businesses authorize their own social accounts through OAuth; their access/refresh tokens must be stored per organization/account, encrypted, in the database. If you want each business to bring its own OAuth app Client ID/Secret too, that is a separate “Custom OAuth App” feature and each platform's redirect URI/review requirements must be handled.

## Install

1. Copy `app/Http/Controllers/AiProviderSettingsController.php`, `resources/views/social-manager/ai-providers.blade.php`, and `database/migrations/2026_10_10_000001_create_org_ai_providers_table.php` into the matching Laravel folders.
2. Merge `routes/ai-provider-settings.php` into `routes/web.php` (or copy its routes into the existing `auth` group).
3. Merge the `config/ai.php` changes from `config/ai.php.example` into your app's `config/ai.php`. Keep driver class mappings and model defaults; do not restore API keys from `env()`.
4. Confirm `Organization::aiProviders()` exists and `OrgAiProvider` uses `protected $hidden = ['credentials'];` and `protected $casts = ['credentials' => 'encrypted:array', 'is_enabled' => 'boolean'];`.
5. Confirm the signed-in user has a valid `current_organization_id` and organization membership. The controller permits only organization owners/admins to manage keys.
6. Run `php artisan migrate`, clear config cache (`php artisan config:clear`), then visit `/social-manager/settings/ai-providers`.

## Security / behavior

- API keys are encrypted at rest through Laravel's encrypted cast; never return them to the browser or log them.
- The form intentionally shows a blank key field when editing. Entering a new key replaces the stored key; leaving it blank preserves the current key. Use “Remove saved key” to delete it.
- Credentials are scoped by `organization_id`. Never query a provider record by ID alone or trust a client-submitted organization ID.
- Provider fallback only tries providers configured by the current organization, plus explicitly keyless/free providers. There is no silent fallback to another customer's credentials.
- Treat free providers as optional, subject to their current terms, limits, privacy policy and availability.
- Add tests for cross-tenant isolation and ensure provider request logs redact authorization headers and keys.

This is an integration patch for the supplied starter pack, not proof that every provider driver or social publisher has been end-to-end tested.
