# CarScrets — Checkout (versão enxuta)

Stripe transparente (Elements), passo único, com dashboard simples e pixels Meta/Google.
Metadata enviada à Stripe descreve o produto/plano reais (curso digital). Recibo do
comprador ativo. Sessão no checkout serve apenas como proteção anti-bot/scraper —
não muda o conteúdo conforme quem acessa.

## Estrutura
```
api/
  config.php              conexão + settings + helpers
  create_intent.php       cria PaymentIntent (metadata verdadeira) — exige sessão+CSRF
  webhook.php             marca pago, grava fee/net, dispara Meta CAPI + UTMify
  admin/
    auth.php              login/logout/sessão do admin
    index.html            UI: dashboard + tela de pixels
    api/dashboard.php     bruto, líquido, nº vendas, taxas, por plano, últimas vendas
    api/settings.php      lê/grava pixels e dados do produto
checkout/
  entry.php               recebe POST da landing, cria sessão+CSRF, redireciona
  index.php               formulário único + Stripe Elements + pixels
  thank-you.php           confirma pagamento, dispara Purchase (pixel) + conversão Google
schema.sql                tabelas: plans, customers, orders, settings, admin_users
```
Coloque a pasta `vendor/` da Stripe (stripe-php) na raiz, como no projeto antigo.

## Passos
1. **Banco**: `mysql -u USER -p DB < schema.sql`
2. **Env** (em `../private/bootstrap_env.php` ou variáveis de ambiente):
   - `DB_HOST DB_NAME DB_USER DB_PASS`
   - `STRIPE_SECRET_KEY STRIPE_PUBLISHABLE_KEY STRIPE_WEBHOOK_SECRET`
   - `SITE_BASE_URL` (ex: https://meucheckout.com)
   - `UTMIFY_API_TOKEN` (opcional)
3. **Admin**: gere o hash e insira o usuário
   ```
   php -r "echo password_hash('SUA_SENHA', PASSWORD_DEFAULT).PHP_EOL;"
   INSERT INTO admin_users (username, password_hash) VALUES ('admin','<hash>');
   ```
4. **Webhook na Stripe**: aponte para `https://SEU_DOMINIO/api/webhook.php`
   Eventos: `payment_intent.succeeded`, `charge.refunded`, `charge.dispute.created`
5. **Pixels**: entre no admin (`/api/admin/`) → aba Pixels → preencha Meta Pixel ID +
   CAPI token e Google Conversion ID + Label.

## Como a landing chama o checkout
```html
<form action="https://SEU_DOMINIO/checkout/entry.php" method="POST">
  <input type="hidden" name="plan" value="plan001">
  <!-- repasse os UTMs reais capturados na URL -->
  <input type="hidden" name="utm_source"   value="...">
  <input type="hidden" name="utm_campaign" value="...">
  <input type="hidden" name="fbclid" value="..."> <input type="hidden" name="_fbp" value="...">
  <button type="submit">Comprar Starter — US$ 19,90</button>
</form>
```
`plan001` = Starter (US$ 19,90) · `plan002` = Complete (US$ 25,90).

## Criar um plano novo
```sql
INSERT INTO plans (code, label, price_cents, currency)
VALUES ('plan003', 'Nome do plano', 3990, 'usd');
```
O botão passa `plan=plan003`; o checkout resolve nome/valor sozinho.

## Dashboard
- **Bruto** = soma de `amount_cents` (vendas pagas)
- **Taxas** = soma de `fee_cents` (vem do `balance_transaction` real da Stripe)
- **Líquido** = soma de `net_cents`
- **Nº de vendas** = contagem de pedidos pagos
Filtro por data opcional.

## Atualização v6 (formulário de pagamento visível no load)
- O cartão (Stripe Elements) agora **monta assim que a página abre** — antes só aparecia
  depois de preencher nome+e-mail, deixando a caixa vazia.
- Fluxo: ao abrir, `create_intent.php` cria o PaymentIntent (só produto/plano, sem cliente) e
  monta o Elements. Ao clicar em "Pagar", o novo `save_customer.php` grava o cliente no banco,
  liga ao pedido e atualiza o PaymentIntent (dados do cliente + `receipt_email`); só então confirma.
- **Novo arquivo**: `api/save_customer.php` (vai junto na pasta `api/`).
- O endereço continua **não** indo para a Stripe; o cliente é gravado em `customers` no clique de pagar.
  Quem abandona antes de clicar não gera linha de cliente (o pedido fica `pending` sem `customer_id`).

## Atualização v5 (idioma por IP + assets + barra de carrinho)
- **Banco**: rode `migration_v5.sql` (liga a logo, a imagem do produto e a barra de 15 min).
- **Idioma automático por IP**: a ordem agora é `?lang=` (override) > **IP → país → idioma** >
  idioma do navegador > inglês. O resultado fica em cache na sessão (1 detecção por visitante).
  - Mapeamento: BR/PT → pt; ES/MX/AR/CO/CL/PE/etc → es; resto → en.
  - Por padrão usa o **ip-api.com** (grátis, sem chave). Para alto volume sem limite de taxa,
    use a base local **GeoLite2** (instruções no topo do `migration_v5.sql`): baixe o
    `GeoLite2-Country.mmdb`, `composer require geoip2/geoip2` e defina `GEOIP_DB` no env.
  - O seletor de idioma saiu do header (estava colidindo com a logo no mobile) e foi para o
    **rodapé**, como no Shopify. Continua disponível para troca manual.
- **Barra de carrinho (topo, vermelha)**: 15 min, nos 3 idiomas, avisando que o carrinho
  expira. Controlada pelas mesmas settings de timer (`timer_enabled`/`timer_minutes`) — global
  ou por oferta. Ao zerar, troca para a mensagem de carrinho expirado.
- **Assets criados** (em `/assets/uploads`): `logo-carsecrets.svg` (emblema de volante +
  wordmark) e `product-carsecrets.svg` (capa com velocímetro). Troque pelos seus quando tiver
  a arte real — pelo admin (logo e imagem por plano) ou apontando o `image_url`/`company_logo_url`.

## Atualização v4 (fidelidade visual Shopify)
- **Banco**: rode `migration_v4.sql` (adiciona `button_color` e `company_name`).
- Visual mais próximo do checkout nativo do Shopify: logo serifada centralizada no topo,
  resumo cinza à direita (full-bleed), rótulos flutuantes, bloco de pagamento com cabeçalho
  e bandeiras, botão "Pagar agora" verde-escuro.
- **No mobile o resumo começa fechado** — barra "Ver resumo do pedido" que abre ao tocar.
- **Cor do botão e nome da empresa** configuráveis no admin (aba Imagens & Timer → Marca).
  A cor padrão é o verde-escuro `#36453d`; troque pela cor da sua marca.

## Atualização v3 (visual Shopify + idioma automático + oferta por linha)
- **Banco**: rode `migration_v3.sql` (adiciona `offer_name`, `timer_enabled`, `timer_minutes`
  por plano e muda o idioma padrão para inglês).
- **Visual**: checkout no estilo Shopify (form à esquerda, resumo do pedido à direita com
  fundo claro, item com miniatura e selo de quantidade; no celular o resumo vira uma barra
  "Ver resumo do pedido" recolhível).
- **Idioma automático**: detecta pelo navegador (cabeçalho Accept-Language); se não der,
  abre em **inglês**. Ordem: `?lang=` > navegador > inglês. Seletor no canto superior.
  - Detecção por **IP/país** (ex.: forçar ES para quem está no México) precisa de um
    serviço de GeoIP. Posso ligar a um se quiser esse nível; hoje é pelo idioma do navegador.

### Oferta = uma linha em `plans` (tudo via schema)
Para criar uma oferta nova, um único INSERT:
```sql
INSERT INTO plans (code, label, offer_name, price_cents, currency, image_url, timer_enabled, timer_minutes)
VALUES ('plan003', 'Complete', 'CarSecrets — Oferta de Lançamento', 2590, 'usd',
        '/assets/uploads/plan_xxxx.jpg', 1, 20);
```
- `code` — o que o botão da página de vendas posta
- `label` — tag curta do plano (subtítulo do item no resumo)
- `offer_name` — nome de exibição da oferta (título no checkout). Vazio = usa o nome do produto
- `image_url` — imagem do produto desta oferta (suba pelo admin ou aponte um arquivo já em `/assets/uploads`)
- `timer_enabled` / `timer_minutes` — cronômetro só desta oferta. `NULL` = usa o global das settings

**Importante:** `offer_name` é só exibição. O metadado enviado à Stripe é **sempre fixo**
(`settings.product_name`, `product_category`…), descrevendo o produto real — nunca o nome
promocional da oferta. Toda oferta é o mesmo CarSecrets por baixo.

## Observações
- Confirme a grafia do produto: **CarScrets** vs CarSecrets (aparece no checkout e na Stripe).

## Atualização v2 (visual + idiomas + imagens + cronômetro)
- **Banco**: rode `migration_v2.sql` no banco já existente (adiciona endereço completo,
  imagem por plano, logo e settings do cronômetro). Instalação nova: o `schema.sql` já vem completo.
- **Pasta de uploads**: garanta que `<public_html>/assets/uploads` exista e tenha
  permissão de escrita pelo PHP (ex.: `chmod 755`, dono = usuário do PHP). Já vem com
  um `.htaccess` que impede execução de scripts ali.
- **Idiomas**: o checkout abre em PT/EN/ES. O seletor fica no topo; pode forçar via
  `?lang=en`. O idioma padrão é configurável no admin (aba Imagens & Timer).
- **Admin → aba "Imagens & Timer"**:
  - Logo da empresa (aparece no topo do checkout)
  - Imagem do produto **por plano** (cada plano tem a sua)
  - Cronômetro: ligar/desligar, duração em minutos, texto por idioma
- **Endereço completo** (país, CEP, rua, número, bairro, complemento, cidade, estado)
  é salvo no banco (tabela `customers`) e **não** é enviado à Stripe — produto digital
  não tem envio. O endereço de cobrança do cartão (AVS) a Stripe coleta no próprio campo.
- **Prévia visual**: abra `checkout-preview.html` no navegador para ver o layout, a troca
  de idioma e o cronômetro (o pagamento Stripe só carrega no servidor real).
- `thank-you.php` precisa terminar em `.php` (faz retrieve do PaymentIntent). O
  `return_url` no `index.php` aponta para `/checkout/thank-you.html`; ajuste para
  `/checkout/thank-you.php` ou crie um rewrite.
- Meta: dedup pixel↔CAPI pelo mesmo `event_id` (gerado no entry, usado nos dois lados).
- Google Ads: conversão client-side na thank-you (padrão). Server-side é possível mas
  exige Google Ads API + OAuth — não incluído por ser bem mais pesado.
```
