# Banco de Dados (/docs/banco-de-dados)



Postgres gerenciado pelo Supabase é a **fonte da verdade**. Toda tabela tem
**RLS** habilitada; a lógica crítica fica em funções `SECURITY DEFINER`. O schema
evolui por migrations em `supabase/migrations/*.sql` (nome com timestamp).

> Fonte canônica de cada detalhe (colunas, constraints, policies) é o próprio
> arquivo de migration. Esta página é o mapa.

## Tabelas [#tabelas]

| Tabela                 | Propósito                                                                                                                                                 |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `profiles`             | Perfil 1:1 com `auth.users`: `role`, `status`, dados de sócio (`membership_*`, `member_number`, `card_token`, foto) e `points_balance` (cache de pepitas) |
| `site_sections`        | Blocos de conteúdo editável do site (chave → título/descrição/CTA)                                                                                        |
| `events`               | Eventos da atlética                                                                                                                                       |
| `ticket_options`       | Lotes de ingresso de cada evento (`price`, `member_price`, `availability`, `max_per_order`)                                                               |
| `products`             | Catálogo da loja (`price`, `member_price`)                                                                                                                |
| `gallery_items`        | Itens da galeria                                                                                                                                          |
| `board_members`        | Diretoria (equipe pública)                                                                                                                                |
| `membership_plans`     | Planos de sócio (mensal/semestral/anual)                                                                                                                  |
| `coupons`              | Cupons de desconto; `owner_user_id` + `source` distinguem cupom pessoal (de pepitas) de cupom manual                                                      |
| `orders`               | Pedidos/financeiro (produto, ingresso, associação); status e IDs/estado do PIX (Sicoob)                                                                   |
| `partners`             | Parceiros com desconto para sócios                                                                                                                        |
| `loyalty_rewards`      | Catálogo de recompensas (desconto → cupom; produto → brinde)                                                                                              |
| `loyalty_transactions` | **Ledger imutável** de pepitas — fonte da verdade do saldo                                                                                                |
| `loyalty_redemptions`  | Resgates (fila de brinde / emissão de cupom)                                                                                                              |
| `page_banners`         | Banners por página (galeria/diretoria/sobre), em carrossel                                                                                                |

Storage: bucket &#x2A;*`site-media`**, com subpastas `events/`, `products/`,
`gallery/`, `board/`, `partner/`, `banners/`, `members/`.

## Funções (Postgres / RPC) [#funções-postgres--rpc]

### Helpers de papel (`SECURITY DEFINER`, estáveis) [#helpers-de-papel-security-definer-estáveis]

`is_admin()`, `is_super_or_admin()`, `is_super_admin()`, `is_active_member()`,
`can_admin_section(section)` — este último espelha o mapa papel→seção do app
(`security_hardening.sql`).

### Triggers [#triggers]

* `set_updated_at()` — mantém `updated_at`.
* `handle_new_user()` — cria o `profile` no signup a partir do `raw_user_meta_data`.
* `guard_points_balance()`, `guard_membership_fields()`,
  `guard_privileged_profile_fields()` — tornam `role`/`status`/pontos/associação
  somente-leitura via cliente.

### Negócio (`SECURITY DEFINER`) [#negócio-security-definer]

| Função                                           | O que faz                                                                                                 | Quem executa                     |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | -------------------------------- |
| `redeem_coupon(code)`                            | Incrementa `uses_count` de forma atômica                                                                  | só `service_role` (webhook)      |
| `earn_points(user, points, reason, order, once)` | Credita pepitas; **idempotente** por pedido/motivo                                                        | só `service_role`                |
| `reverse_purchase_points(order)`                 | Estorna pepitas de pedido reembolsado (idempotente)                                                       | só `service_role`                |
| `adjust_points(user, points, reason)`            | Ajuste manual (+/−); valida `is_super_or_admin`                                                           | admin autenticado / service role |
| `redeem_reward(reward)`                          | Resgata recompensa: valida sócio ativo + saldo + estoque, debita, cria redemption, emite cupom single-use | o próprio sócio                  |
| `assign_membership_card(user, plan, months)`     | Ativa/renova associação (número, token, validade, plano)                                                  | admin autenticado                |
| `revoke_membership(user)`                        | Encerra associação (mantém número/token)                                                                  | admin autenticado                |
| `verify_membership_card(token)`                  | Verificação pública por QR; devolve só dados exibíveis (sem PII)                                          | `anon`                           |
| `submit_card_photo(url)`                         | Sócio envia foto (ativo, sem pendência, 1×/ano)                                                           | authenticated                    |
| `review_card_photo(user, approve)`               | Diretoria aprova/rejeita foto; valida `is_admin`                                                          | authenticated                    |

> **Removida por segurança**: `activate_membership(user, plan)` existia com
> `EXECUTE` para `PUBLIC` (permitia auto-ativar sem pagar) e foi eliminada em
> `20260807120000_security_hardening.sql`. A ativação real hoje é
> `assign_membership_card`, feita pela diretoria.

## Migrations (ordem cronológica) [#migrations-ordem-cronológica]

```
20260407120000_initial_covil               schema base
20260423120000_event_archived_status       status "arquivado" de evento
20260424120000_membership_and_roles        associação + papéis
20260430120000_orders                       pedidos
20260430140000_new_permission_roles         novos papéis de permissão
20260731120000_payments_partners            pagamentos + parceiros
20260801120000_multi_images                 múltiplas imagens (images jsonb)
20260802120000_signup_and_membership_approval  cadastro + aprovação de sócio
20260803120000_loyalty_pepitas              programa de pepitas
20260804120000_membership_card              carteirinha digital
20260804130000_partner_image                imagem de parceiro
20260805120000_member_photo                 foto do sócio
20260805130000_member_photo_storage         storage da foto do sócio
20260807120000_security_hardening           ⚠️ hardening de segurança (crítica)
20260810120000_page_banners                 banners por página
```

Ao evoluir o schema: **nova migration** (nunca edite uma já aplicada) +
espelhar os tipos em `src/types/supabase.ts` e o domínio em
`src/types/content.ts`.

Aplicação em produção e verificação de pendências: ver [`deploy.md`](deploy.md).
