# Save in Med BFF

BFF para a plataforma Save in Med, integrando serviços do Appwrite (Databases) e expondo rotas de categorias, subcategorias, usuários, empresas, endereços, produtos de catálogo, carrinhos, pedidos e pagamentos.

## Pré-requisitos
- Python 3.12+
- Docker (opcional)

## Configuração & Segurança
A aplicação utiliza variáveis de ambiente carregadas via arquivo `.env`. Utilize o arquivo `.env.example` como base.

Variáveis obrigatórias:
- `APPWRITE_ENDPOINT`: URL do serviço Appwrite.
- `APPWRITE_PROJECT_ID`: identificador do projeto Appwrite.
- `APPWRITE_API_KEY`: chave da API Appwrite com permissões para Databases.
- `APPWRITE_DATABASE_ID`: identificador do banco de dados utilizado.
- `APPWRITE_COLLECTION_PRODUTOS_CATALOGO_ID`: identificador da coleção de produtos de catálogo.
- `APPWRITE_COLLECTION_LABORATORIOS_ID`: identificador da coleção de laboratórios.
- `APPWRITE_COLLECTION_CATEGORIAS_ID`: identificador da coleção de categorias.
- `APPWRITE_COLLECTION_SUBCATEGORIAS_ID`: identificador da coleção de subcategorias de produtos.
- `APPWRITE_COLLECTION_CARRINHOS_ID`: identificador da coleção de carrinhos.
- `APPWRITE_COLLECTION_PEDIDOS_ID`: identificador da coleção de pedidos.
- `APPWRITE_COLLECTION_USUARIOS_ID`: identificador da coleção de usuários.
- `APPWRITE_COLLECTION_EMPRESAS_ID`: identificador da coleção de empresas.
- `APPWRITE_COLLECTION_EMPRESAS_DADOS_ID`: identificador da coleção com os dados enriquecidos de empresas (ReceitaWS).
- `APPWRITE_COLLECTION_ENDERECOS_ID`: identificador da coleção de endereços.
- `APPWRITE_COLLECTION_ENTREGAS_ID`: identificador da coleção de entregas.
- `MAPBOX_ACCESS_TOKEN`: token de acesso para geocodificação automática dos endereços das empresas.

Variáveis opcionais:
- `SECURITY_API_KEY`: chave para proteger as rotas com o header `x-api-key`.
- `CORS_ALLOW_ORIGINS`: lista separada por vírgula de origens autorizadas no CORS. Se vazia, `*` é utilizado.

### Campos adicionais na coleção `empresas-dados` (Appwrite)
Crie os atributos abaixo na coleção `empresas-dados` para suportar frete e geocodificação automática:

- `tipo-frete` (string, ex.: `gratis`, `fixo`, `por_km`)
- `taxa-entrega` (double/decimal)
- `valor-frete-km` (double/decimal)
- `raio-entrega-km` (double/decimal)
- `latitude` (double/decimal)
- `longitude` (double/decimal)

Os novos campos serão preenchidos automaticamente a partir do endereço relacionado (`enderecos`).

Variáveis de autenticação e sessão:
- `JWT_SECRET`: segredo para assinar/verificar JWT.
- `JWT_ALGORITHM`: algoritmo (ex.: `HS256`).
- `JWT_ACCESS_TTL_SECONDS`: validade do token (segundos).
- `SESSION_COOKIE_NAME`: nome do cookie httpOnly.
- `COOKIE_SECURE`: `true` para setar cookie com `Secure` (produção HTTPS).
- `COOKIE_DOMAIN`: domínio do cookie (opcional).
- `SUPERADMIN_IDENTIFICADOR` e `SUPERADMIN_SENHA`: credenciais para criar usuário superadmin no startup. A senha é armazenada com `bcrypt_sha256`, permitindo valores longos (recomendado usar frases secretas robustas). Não utilize chaves de API como senha.

Quando `SECURITY_API_KEY` está definido com um valor não vazio, todas as rotas passam a exigir o header `x-api-key` correspondente. Essa validação é feita via middleware, portanto o header **não** aparece na documentação do Swagger. Caso a variável esteja vazia ou ausente, nenhuma checagem é feita — ideal para ambientes de desenvolvimento.

## Endpoints
- `GET /` → `{ "message": "Hello, World!" }`
- `GET /healthz` → `{ "status": "ok" }`
- `GET /api/v1/ping` → `{ "pong": true }`
- `POST /api/v1/auth/register`
- `POST /api/v1/auth/login`
- `POST /api/v1/auth/logout`
- `GET /api/v1/auth/me`
- `GET /api/v1/categorias`
- `GET /api/v1/subcategorias`
- `GET /api/v1/usuarios`
- `GET /api/v1/empresas`
- `GET /api/v1/enderecos`
- `GET /api/v1/produtos-catalogo`
- `GET /api/v1/carrinhos`
- `GET /api/v1/pedidos`

## Como rodar em dev
```bash
pip install -r requirements.txt
uvicorn src.main:app --reload

# Docker
docker build -t saveinmed-bff .
docker run -p 8000:8000 --env-file .env saveinmed-bff
```

## Testes rápidos com curl
```bash
curl http://localhost:8000/
curl http://localhost:8000/healthz
curl http://localhost:8000/api/v1/ping
curl http://localhost:8000/api/v1/carrinhos
curl http://localhost:8000/api/v1/pedidos
```

> Adicione o header `-H "x-api-key: <token>"` nos exemplos abaixo quando a variável `SECURITY_API_KEY` estiver configurada.

### Auth
```bash
# Registro de usuário (senha é armazenada com hash no Appwrite)
curl -X POST "http://localhost:8000/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{"identificador": "user@example.com", "nome": "Nome do Usuário", "senha": "senha123"}'

# Login retorna o JWT e seta o cookie httpOnly
curl -i -X POST "http://localhost:8000/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"identificador": "user@example.com", "senha": "senha123"}'

# Após o login, o cookie é enviado automaticamente pelo navegador/Swagger
curl -b cookiejar.txt -c cookiejar.txt http://localhost:8000/api/v1/auth/me

# Logout remove o cookie httpOnly
curl -X POST http://localhost:8000/api/v1/auth/logout
```

> Rotas públicas: `/`, `/healthz`, `/api/v1/ping` e todas as rotas sob `/api/v1/auth/*`. As demais rotas exigem autenticação via JWT (Bearer ou cookie httpOnly).

Durante o startup, caso nenhum usuário superadmin exista na coleção, o BFF cria automaticamente um registro utilizando as credenciais definidas em `SUPERADMIN_IDENTIFICADOR` e `SUPERADMIN_SENHA`. Se a senha estiver vazia ou muito longa (> 1024 caracteres), o sistema registra um aviso no log e gera uma senha temporária aleatória.

### Categorias
```bash
curl -X GET "http://localhost:8000/api/v1/categorias?page=1&per_page=20"
curl -X POST "http://localhost:8000/api/v1/categorias" \
  -H "Content-Type: application/json" \
  -d '{"nome": "Dermocosméticos"}'
curl -X GET "http://localhost:8000/api/v1/categorias/cat_1"
curl -X PATCH "http://localhost:8000/api/v1/categorias/cat_1" \
  -H "Content-Type: application/json" \
  -d '{"nome": "Dermocosméticos premium"}'
curl -X DELETE "http://localhost:8000/api/v1/categorias/cat_1"
```

### Subcategorias
```bash
curl -X GET "http://localhost:8000/api/v1/subcategorias?page=1&per_page=20"
curl -X POST "http://localhost:8000/api/v1/subcategorias" \
  -H "Content-Type: application/json" \
  -d '{"nome": "Suplementos", "categoriaId": "cat_1"}'
curl -X GET "http://localhost:8000/api/v1/subcategorias/sub_1"
curl -X PATCH "http://localhost:8000/api/v1/subcategorias/sub_1" \
  -H "Content-Type: application/json" \
  -d '{"nome": "Suplementos esportivos"}'
curl -X DELETE "http://localhost:8000/api/v1/subcategorias/sub_1"
```

### Usuarios
```bash
curl -X GET "http://localhost:8000/api/v1/usuarios?page=1&per_page=20"
curl -X POST "http://localhost:8000/api/v1/usuarios" \
  -H "Content-Type: application/json" \
  -d '{"identificador": "admin@saveinmed.com", "senha": "senha123", "ativo": true, "superadmin": true, "telefone": "11987654321"}'
curl -X GET "http://localhost:8000/api/v1/usuarios/user_1"
curl -X PATCH "http://localhost:8000/api/v1/usuarios/user_1" \
  -H "Content-Type: application/json" \
  -d '{"ativo": false}'
curl -X DELETE "http://localhost:8000/api/v1/usuarios/user_1"
```

### Empresas
```bash
curl -X GET "http://localhost:8000/api/v1/empresas?page=1&per_page=20"
curl -X POST "http://localhost:8000/api/v1/empresas" \
  -H "Content-Type: application/json" \
  -d '{"cnpj": "12.345.678/0001-00", "razaoSocial": "Clínica Alfa LTDA", "nomeFantasia": "Clínica Alfa"}'
curl -X GET "http://localhost:8000/api/v1/empresas/emp_1"
curl -X PATCH "http://localhost:8000/api/v1/empresas/emp_1" \
  -H "Content-Type: application/json" \
  -d '{
    "nome-fantasia": "Clínica Alfa Centro",
    "telefone": "62999999999",
    "email": "contato@clinicaalfa.com"
  }'
curl -X DELETE "http://localhost:8000/api/v1/empresas/emp_1"
```

### Enderecos
```bash
curl -X GET "http://localhost:8000/api/v1/enderecos?page=1&per_page=20"
curl -X POST "http://localhost:8000/api/v1/enderecos" \
  -H "Content-Type: application/json" \
  -d '{"titulo": "Matriz", "cep": "12345-678", "cidade": "São Paulo", "estado": "SP"}'
curl -X GET "http://localhost:8000/api/v1/enderecos/end_1"
curl -X PATCH "http://localhost:8000/api/v1/enderecos/end_1" \
  -H "Content-Type: application/json" \
  -d '{"numero": "456"}'
curl -X DELETE "http://localhost:8000/api/v1/enderecos/end_1"
```

## Estrutura do projeto
```
.
├─ src/
│  ├─ __init__.py
│  ├─ main.py
│  ├─ app/
│  │  ├─ __init__.py
│  │  ├─ main.py
│  │  └─ api/
│  │     ├─ __init__.py
│  │     └─ v1/
│  │        ├─ __init__.py
│  │        └─ routes.py
│  ├─ core/
│  │  ├─ __init__.py
│  │  ├─ appwrite_client.py
│  │  ├─ config.py
│  │  ├─ deps.py
│  │  └─ security.py
│  └─ modules/
│     ├─ __init__.py
│     ├─ categorias/
│     │  ├─ __init__.py
│     │  ├─ router.py
│     │  ├─ schemas.py
│     │  └─ service.py
│     ├─ carrinhos/
│     │  ├─ __init__.py
│     │  ├─ router.py
│     │  ├─ schemas.py
│     │  └─ service.py
│     ├─ pedidos/
│     │  ├─ __init__.py
│     │  ├─ router.py
│     │  ├─ schemas.py
│     │  └─ service.py
│     └─ produtos_catalogo/
│        ├─ __init__.py
│        ├─ router.py
│        ├─ schemas.py
│        └─ service.py
├─ requirements.txt
├─ Dockerfile
├─ README.md
└─ .gitignore
```

## Próximos passos
- Criar as relações no Appwrite para os campos `usuarios`, `pedidos`, `comprador`, `vendedor` e `pagamentos` das coleções de carrinhos e pedidos. Quando as relações estiverem disponíveis, ajustar o BFF para enviar/receber os objetos de relação em vez de strings.

## Licença
MIT
