# Handoff: Etapa 7 — Google OAuth

**Objetivo:** Permitir que o usuário entre no Prumo com a conta Google ("Login com
Google"), sem precisar criar senha. Usa Authlib (já no `requirements.txt`) com o
fluxo OIDC padrão. Ao final: botão "Entrar com Google" nas páginas de login e
registro funcionando em dev e produção.

> ## Como usar este arquivo (protocolo de execução)
> - Executar **uma etapa por vez**, na ordem. Cada etapa é **estanque** e tem como
>   verificar no fim.
> - Ao concluir uma etapa: marcar `[x]` (etapa e sub-itens), **preencher "Notas de
>   execução"**, salvar este arquivo e **PARAR**.
> - **Esperar o aval** do usuário **ou** a correção de erros. Erros → corrigir na
>   mesma etapa e parar de novo.
> - **No aval:** fazer **commit + push** dos arquivos da etapa (incluindo este
>   handoff e os untracked relevantes). Depois **esperar a liberação** para iniciar a
>   **próxima** etapa.
> - **Entrega é do Claude; deploy/teste costuma ser do usuário.** Onde disser
>   "Verificar", o Claude entrega e descreve o teste; se não der para rodar aqui, o
>   usuário roda e retorna o comportamento (ou os erros/logs).

---

## Decisões (já acordadas)

1. Usar **Authlib** (`authlib.integrations.flask_client`) — já está no `requirements.txt`.
2. Padrão **OIDC** via `server_metadata_url` do Google (discovery automático).
3. Scope: `openid email profile` — captura `email`, `name` e `sub` (google_id).
4. Se o e-mail já existir no banco (conta email/senha), **logar e vincular o `google_id`** — sem criar duplicata.
5. Se for usuário novo, **criar registro** com `name`, `email`, `google_id` e `password_hash=NULL`.
6. O objeto `oauth` segue o mesmo padrão de `db`: instanciado em `oauth.py`, inicializado em `create_app()`.
7. Callback URLs a registrar no Google Cloud Console:
   - Dev: `http://localhost:5000/auth/google/callback`
   - Prod: `https://app.prumoboard.com/auth/google/callback`

---

## Estado atual (pontos de toque)

- @app/app.py — factory; aqui o `oauth` será inicializado
- @app/database.py — padrão a seguir para `oauth.py`
- @app/config.py — já expõe `GOOGLE_CLIENT_ID` e `GOOGLE_CLIENT_SECRET`
- @app/routes/auth/auth.py — blueprint onde as rotas Google serão adicionadas
- @app/services/auth_service.py — service onde `find_or_create_google_user` será adicionado
- @app/templates/auth/login.html — receberá botão "Entrar com Google"
- @app/templates/auth/register.html — receberá botão "Entrar com Google"

---

## Etapas

### [x] Etapa 1 — Criar oauth.py e inicializar em create_app

**Objetivo:** Registrar o cliente Google no Authlib e inicializar no factory, sem ainda expor nenhuma rota.

Arquivos: @app/oauth.py (novo), @app/app.py

- [x] Criar `app/oauth.py` com `oauth = OAuth()` e `init_oauth(app)` (registra cliente Google)
- [x] Em `app/app.py`: importar `init_oauth` e chamar após `init_db`

**Verificar:** `flask --app app run --debug` sobe sem erro. Nenhuma rota nova ainda.

_Notas de execução:_
- Criado `app/oauth.py` com `oauth = OAuth()` e `init_oauth(app)` registrando o cliente Google via discovery OIDC.
- `app/app.py` atualizado: importa `init_oauth` e chama após `init_db`.
- `requests` não estava no venv — instalado (`requests` é dependência transitiva do Authlib não listada no `requirements.txt`; adicionar ao `requirements.txt` é boa prática mas não é escopo desta etapa).
- Verificado: `create_app()` retorna sem erros.

---

### [x] Etapa 2 — Service + rotas Google OAuth

**Objetivo:** Implementar o fluxo completo: redirect para o Google e callback que loga/cria o usuário.

Arquivos: @app/services/auth_service.py, @app/routes/auth/auth.py

- [x] Em `auth_service.py`: adicionar `find_or_create_google_user(userinfo)` — localiza por `google_id` ou `email`; vincula `google_id` se já existe; cria se não existe
- [x] Em `auth.py`: importar `oauth` de `oauth.py`
  - [x] Adicionar `GET /auth/google/login` — chama `oauth.google.authorize_redirect(callback_uri)`
  - [x] Adicionar `GET /auth/google/callback` — troca token, chama `find_or_create_google_user`, faz `login_user` e redireciona para dashboard

**Verificar:** Usuário acessar `http://localhost:5000/auth/google/login` → redireciona para tela de consentimento do Google → volta ao app logado no dashboard. (Requer `GOOGLE_CLIENT_ID` e `GOOGLE_CLIENT_SECRET` válidos no `.env` local.)

_Notas de execução:_
- `find_or_create_google_user` adicionado ao `auth_service.py`: busca por `google_id`, depois por `email` (vincula se achar), cria novo se não encontrar.
- Rotas `GET /auth/google/login` e `GET /auth/google/callback` adicionadas ao blueprint `auth`.
- `create_app()` inicializa sem erros.

---

### [x] Etapa 3 — Botão "Entrar com Google" nos templates

**Objetivo:** Expor o fluxo OAuth na UI das páginas de login e registro.

Arquivos: @app/templates/auth/login.html, @app/templates/auth/register.html

- [x] Em `login.html`: adicionar botão/link para `url_for('auth.google_login')` abaixo do formulário
- [x] Em `register.html`: idem
- [x] Separador visual entre o formulário email/senha e o botão Google (ex.: "— ou —")

**Verificar:** Abrir `/login` e `/register` — botão "Entrar com Google" aparece e ao clicar inicia o fluxo OAuth.

_Notas de execução:_
- Botão "Entrar com Google" (`.btn-google`) adicionado em `login.html` e `register.html` com separador `— ou —`.
- `.btn-google` já existia no CSS; adicionada apenas `.divider` para o separador.
- `create_app()` inicializa sem erros.

---

## Riscos / observações

- **Callback URLs no Google Cloud Console** precisam estar cadastradas antes de testar — tanto a de dev quanto a de produção. Sem isso o Google retorna `redirect_uri_mismatch`.
- **`google_id` como vínculo:** o campo já existe na tabela `users` (Etapa 4), não precisa de migration.
- **Usuário sem senha:** ao logar via Google, `password_hash` fica `NULL`; o `check_password` já trata esse caso retornando `False` (nenhum risco de bypass).
- **Ordem das etapas:** Etapa 1 não quebra nada se o `GOOGLE_CLIENT_ID` estiver vazio (Authlib só falha na hora de redirecionar, não na inicialização).
