# Configuração: IAs, Stripe, worker e preview / Configuration: AI, Stripe, worker & preview

> Todas as chaves ficam **somente** no arquivo `.env` do servidor (fora do `public/`). Nunca no banco, no código ou no navegador.
> All keys live **only** in the server's `.env` file (outside `public/`). Never in the DB, code or browser.

Depois de editar o `.env`, não é preciso reiniciar nada no PHP embutido (cada requisição relê). Com PHP-FPM, recarregue o serviço.
After editing `.env`, the built-in PHP server picks it up on the next request; with PHP-FPM, reload the service.

---

## 1. Provedores de IA / AI providers

| Etapa / Step | Agente / Agent | Variável que escolhe o provedor | Padrão / Default |
|---|---|---|---|
| 1 · Estratégia / Strategy | `ProductArchitectAgent` | `AI_AGENT_STRATEGY` | `gemini` |
| 2 · Design | `UIUXAgent` | `AI_AGENT_DESIGN` | `openai` |
| 3 · Código / Code | `CoderAgent` | `AI_AGENT_CODE` | `anthropic` |

Valores possíveis / allowed: `gemini`, `openai`, `anthropic`. Você pode usar uma única IA para tudo (ex.: as três = `anthropic`).
You can use a single AI for everything (e.g. all three = `anthropic`).

### 1.1 Onde criar as chaves / Where to get keys

| Provedor | Onde / Where | `.env` | Modelo padrão (troque à vontade) |
|---|---|---|---|
| Google Gemini | https://aistudio.google.com/apikey | `GEMINI_API_KEY=` | `GEMINI_MODEL=gemini-3.8-flash` |
| OpenAI (GPT) | https://platform.openai.com/api-keys | `OPENAI_API_KEY=` | `OPENAI_MODEL=gpt-5-mini` |
| Anthropic (Claude) | https://console.anthropic.com/settings/keys | `ANTHROPIC_API_KEY=` | `ANTHROPIC_MODEL=claude-opus-5` |

```dotenv
AI_DEMO_MODE=off          # auto | off | force
AI_AGENT_STRATEGY=gemini
AI_AGENT_DESIGN=openai
AI_AGENT_CODE=anthropic
GEMINI_API_KEY=AIza...
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
```

- **`AI_DEMO_MODE=auto`** (dev): agente sem chave roda em modo demonstração (gerador local, sem custo). / agents without a key run in demo mode.
- **`off`** (produção): chave faltando → o build falha com mensagem clara e os créditos são estornados. / missing key → build fails and credits are refunded.
- **`force`**: nunca chama IA externa. / never calls external AI.

Teste: **Integrações → Testar conexão** (somente admin; faz 1 chamada mínima). / Test: **Integrations → Test connection** (admin only).

### 1.2 Como cada provedor é chamado / How each provider is called

Tudo via HTTPS com cURL (sem SDK/Composer), em `app/AI/Providers/`:
- **Claude**: `POST /v1/messages`, `anthropic-version: 2023-06-01`, *adaptive thinking*, saída estruturada `output_config.format = json_schema`; nos modelos Opus 5 envia `fallbacks: "default"` (beta `server-side-fallback-2026-07-01`) para, se um classificador de segurança recusar, a própria API refazer em outro modelo. / on Opus 5 the request opts into server-side refusal fallbacks.
- **OpenAI**: `POST /v1/chat/completions` com `response_format = json_schema (strict)`.
- **Gemini**: `POST /v1beta/models/{modelo}:generateContent` com `responseMimeType: application/json`.

A resposta de **qualquer** IA passa pelo mesmo caminho: JSON estrito → `normalize()` do agente → `AIActionValidator` (caminho, extensão, tamanho, *scanner* de código perigoso) → `php -l` → gravação pelo `ProjectFileService` → QA abrindo cada página do preview (página com erro é trocada pelo scaffold seguro).

### 1.3 Custos / Costs

Cada chamada grava tokens e custo estimado em `ai_usage` (tabela de preços em `config/ai.php` → `pricing`, US$ por 1M tokens — confira no site de cada provedor). Resumo em **Integrações** (admin).

---

## 2. Stripe (planos e créditos / plans & credits)

Planos, pacotes e custos ficam em **`config/billing.php`** (preços em centavos, BRL). / Plans, packs and costs live in `config/billing.php`.

| Plano | BRL/mês | USD/mês | Créditos/mês | Domínios |
|---|---|---|---|---|
| Free | R$ 0 | $0 | 200 | 1 |
| Starter | R$ 99 | $19 | 2.000 | 3 |
| Pro | R$ 199 | $39 | 6.000 | 10 |
| Business | R$ 499 | $99 | 20.000 | 50 |

Sem limite de projetos: com créditos, cria. Preços em BRL quando o idioma é português; USD em inglês/espanhol.

Pacotes avulsos: 2.000 = R$ 39 · 5.000 = R$ 89 · 15.000 = R$ 229. Criar site/landing = **150**, SaaS/app/outros = **300** créditos; ajustes no chat = **30** (site) / **60** (SaaS/app). Se a Estratégia concluir outro tipo, a diferença é estornada/cobrada. Build com falha = estorno automático.

### 2.1 Chaves / Keys
1. https://dashboard.stripe.com/test/apikeys → copie a **Secret key** (`sk_test_...`) para `STRIPE_SECRET_KEY`.
2. Não é preciso criar produtos/preços no painel: o checkout usa `price_data` com os valores de `config/billing.php`. / No products needed in the dashboard.
3. Webhook:
   - **Produção**: Developers → Webhooks → *Add endpoint* → `https://SEU_DOMINIO/webhooks/stripe`, eventos: `checkout.session.completed`, `checkout.session.async_payment_succeeded`, `invoice.paid`, `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`. Copie o *Signing secret* (`whsec_...`) para `STRIPE_WEBHOOK_SECRET`.
   - **Local**: instale a Stripe CLI e rode:
     ```bash
     stripe listen --forward-to localhost:8080/webhooks/stripe
     ```
     Ela imprime um `whsec_...` → coloque em `STRIPE_WEBHOOK_SECRET`.
4. Cartão de teste: `4242 4242 4242 4242`, qualquer data futura e CVC.
5. (Opcional) Ative o **Customer Portal** em Settings → Billing → Customer portal (botão "Gerenciar assinatura").

Segurança: créditos só entram por **webhook com assinatura verificada** (HMAC + tolerância de 5 min), cada evento é processado uma única vez (`stripe_events`) e cada crédito tem chave de idempotência (`stripe:invoice:…`, `stripe:checkout:…`). A página de sucesso **não** credita nada.

Ajuste manual (CLI, auditado): `php bin/credits.php email@x.com 1000`

---

## 3. Worker (fila de jobs / job queue)

Os builds rodam fora da requisição web. / Builds run outside the web request.

- **Dev**: `WORKER_AUTOSPAWN=true` — a plataforma inicia `php bin/worker.php --until-empty` quando necessário. `WORKER_PHP_BINARY` = caminho do `php` CLI.
- **Produção** (systemd), com `WORKER_AUTOSPAWN=false`:
  ```ini
  # /etc/systemd/system/saasfactory-worker.service
  [Service]
  User=saasfactory
  WorkingDirectory=/var/www/saas-factory
  ExecStart=/usr/bin/php bin/worker.php
  Restart=always
  [Install]
  WantedBy=multi-user.target
  ```

## 4. Preview

Todos os projetos rodam em **um único gateway**: `http://PREVIEW_HOST:PREVIEW_PORT/project/{nome}/` (ex.: `http://127.0.0.1:8090/project/olamundo/`; nome repetido ganha 2 dígitos aleatórios, ex. `olamundo22`). Não há acesso por número sequencial. Domínios verificados abrem o projeto na raiz.
A plataforma inicia o gateway sozinha (`preview/gateway.php`). A cada requisição ele resolve o projeto pelo nome/domínio, resolve a pasta com `realpath` e **restringe o `open_basedir` à pasta daquele projeto** antes de executar qualquer código gerado; funções de shell/rede ficam desativadas no processo inteiro. Só `index.php`, `login.php` e `logout.php` executam; `config/`, `includes/`, `pages/` e `project.json` nunca são servidos diretamente.

O `PREVIEW_HOST` **deve ser diferente** do host da plataforma (ex.: plataforma em `localhost`, preview em `127.0.0.1`) para os cookies da plataforma nunca chegarem ao código gerado.

> Produção: como todos os previews dividem a mesma origem, use **um subdomínio por projeto** (`{id}.preview.seudominio.com`) com Nginx + um pool PHP-FPM por projeto — isolamento total entre clientes.

## 4.1 Imagens do layout (etapa Design)

`AI_IMAGE_PROVIDER=openai` (`OPENAI_IMAGE_MODEL=gpt-image-2`) ou `gemini` (`GEMINI_IMAGE_MODEL=gemini-3.1-flash-image`). `AI_IMAGE_QUALITY=low|medium|high`. Sem chave ou em caso de erro, a plataforma desenha um wireframe SVG com as mesmas cores.

## 5. Banco por projeto / Per-project database

`DB_PROVISIONER_USERNAME/PASSWORD`: conta MySQL usada **só pelo worker** para `CREATE DATABASE`, `CREATE USER` e `GRANT`. Exemplo de conta dedicada em produção:
```sql
CREATE USER 'sf_provisioner'@'localhost' IDENTIFIED BY '<senha-forte>';
GRANT CREATE, DROP ON `sf\_p\_%`.* TO 'sf_provisioner'@'localhost';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, REFERENCES ON `sf\_p\_%`.* TO 'sf_provisioner'@'localhost' WITH GRANT OPTION;
GRANT CREATE USER ON *.* TO 'sf_provisioner'@'localhost';
```
Cada projeto recebe o banco `sf_p_xxxxxxxxxx` e o usuário `sf_u_xxxxxxxxxx` com permissão **só** nesse banco; a senha fica cifrada (libsodium, `APP_KEY`) em `project_databases`.

## 6. Tema claro/escuro, Rádio Vibers e domínios (v0.5)

- **Tema**: botão ☀/🌙 no menu do site e seletor Claro/Escuro/Auto no menu do usuário da plataforma. Logado → salvo em `users.theme` (Auto = `NULL`); visitante → cookie `sf_theme`. Sem escolha, `public/assets/js/theme.js` usa claro das 06h às 18h e escuro à noite (horário do próprio visitante).
- **Rádio Vibers** (`/radio`): botão ▶ ao lado do usuário/menu. Abre numa janelinha própria, então navegar ou atualizar a página não para a música. Usa o player oficial embutível da Suno (`suno.com/embed/{id}`); as páginas/rádio da própria Suno não podem ser embutidas em outros sites. Faixas em `config/radio.php` ou, para trocar tudo, no `.env`:
  ```dotenv
  RADIO_TRACKS=id-da-musica-1,id-da-musica-2
  ```
  O id vem da URL `suno.com/song/<id>`. Se o navegador bloquear o autoplay, basta tocar no ▶ do player uma vez.
- **Domínios**: o registro de verificação agora é `TXT _vibers.{dominio}` = `vibers-verify={token}` (o antigo `_saasfactory` continua aceito).

## 7. Agentes e Tarefas (v0.6)

| Quadro | Papel | Variável | Padrão |
|---|---|---|---|
| 1 | Gestor de projetos (análise do negócio + plano; depois conversa e encaminha edições) | `AI_AGENT_STRATEGY` | `gemini` |
| 2 | Designer | `AI_AGENT_DESIGN` | `openai` |
| 3 | Programador (código + preview) | `AI_AGENT_CODE` | `anthropic` |
| 4 | Marketing (plano + tarefas, uma vez por projeto) | `AI_AGENT_MARKETING` | `openai` |

- Conversar com o Gestor ou com o Marketing custa `CREDITS_CHAT` (padrão 5). Quando o Gestor encaminha trabalho ao Designer ou ao Programador, cobra o custo de ajuste (30 site / 60 SaaS); se o ajuste falhar, o crédito é estornado.
- **Tarefas** (`/tasks`): uma coluna por projeto (+ "Geral"). As tarefas sugeridas pelo Marketing entram pelo botão "Salvar em Minhas Tarefas".

## 8. Produção (Google Cloud + vibers.codes)

Passo a passo completo em **docs/DEPLOY.md** (`deploy/install.sh`, `deploy/Caddyfile`, serviços systemd). Domínios dos vibers: registro **A → 136.119.227.200** (`DOMAIN_A_RECORD_IP`) + TXT `_vibers`.
