# Mais Saúde — Roteiro técnico

**Status:** análise aprovada para discussão · sem implementação até liberar etapa  
**Produto:** campanhas promocionais + gamificação + cupons (farmácia)  
**URL:** https://ms.restor.app.br  
**Cor padrão:** vermelho (`#C62828` base · `#E53935` destaque · `#B71C1C` hover)

---

## 1. Situação atual

| Item | Estado |
|------|--------|
| App | Laravel 13.26 em `/var/www/html/maissaude` |
| Banco | MySQL `maissaude` |
| Front | Vite + Tailwind 4 · Blade padrão (skeleton) |
| Auth | ainda não (só users da migration default) |
| Apache/SSL | ok em `ms.restor.app.br` |
| PDV | fora de escopo agora |

Base limpa. Nada do Conecta será misturado neste código.

---

## 2. Stack proposta

| Camada | Escolha | Motivo |
|--------|---------|--------|
| Backend | Laravel 11/13 (já instalado) | filas, policies, validação, jobs |
| Admin + cliente | **Inertia.js + Vue 3 + Tailwind** | raspadinha/roleta e telas admin no mesmo stack |
| Auth | Laravel Breeze (Inertia/Vue) ou Fortify + painel próprio | rápido e estável |
| Banco | MySQL (já no ar) | |
| Fila | database ou Redis (fase 12) | sorteio/auditoria assíncrona se precisar |
| QR | `simplesoftwareio/simple-qrcode` ou SVG próprio | links de campanha/participação |
| Multi-farmácia | `pharmacy_id` desde a etapa 1 | produto revendável depois |

**Não entra agora:** e-commerce, delivery, WhatsApp, Evolution, PDV real.

**Identidade visual:** vermelho como cor primária em todo o admin e nas experiências (raspadinha/roleta). Evitar roxo/gradiente genérico.

---

## 3. Conceito em 1 fluxo

```
Operador registra participação (valor compra + cliente + campanha)
        ↓
Backend sorteia prêmio (probabilidades da campanha)
        ↓
Gera participação + (opcional) cupom único
        ↓
Cliente abre link/QR → raspadinha ou roleta (só anima o resultado já definido)
        ↓
Cupom fica disponível
        ↓
Caixa valida código → UTILIZAR → status utilizado (sem descontar no PDV)
```

Regra de ouro: **sorteio e regras só no backend.** Front só exibe.

---

## 4. Módulos

| # | Módulo | Função |
|---|--------|--------|
| 1 | Auth / usuários | login, perfis Admin / Operador / Caixa |
| 2 | Farmácia (tenant) | dados da loja; base multi-tenant |
| 3 | Categorias | higiene, infantil… |
| 4 | Produtos | cadastro + vínculo categoria |
| 5 | Clientes | CPF/telefone + histórico |
| 6 | Campanhas | regras, datas, mecânica, limites |
| 7 | Prêmios | tipos + probabilidade por campanha |
| 8 | Participações | 1 compra → N chances → resultado |
| 9 | Cupons | emissão, consulta, validação caixa |
| 10 | Experiências | raspadinha / roleta / prêmio direto |
| 11 | Links + QR + tracking | origem, acessos, conversão |
| 12 | Dashboard / relatórios | KPIs + gráficos por período |
| 13 | Auditoria | log de ações críticas |
| 14 | API PDV (só contrato) | endpoints/stubs, sem integração real |

---

## 5. Perfis

| Perfil | Acesso |
|--------|--------|
| Administrador | tudo |
| Operador | campanhas, produtos, clientes, participações, relatórios |
| Caixa | validar cupom + consulta limitada de cliente/cupom |

---

## 6. Modelo de banco (núcleo)

Prefixo mental: tudo relevante carrega `pharmacy_id`.

### 6.1 Identidade e acesso
- `pharmacies` — nome, slug, config (cor, logo depois)
- `users` — name, email, password, `pharmacy_id`, `role` (admin|operator|cashier), active
- `audit_logs` — user_id, action, entity_type, entity_id, payload JSON, ip, created_at

### 6.2 Catálogo
- `categories` — pharmacy_id, name, slug, active
- `products` — pharmacy_id, category_id, name, sku, description, price, promo_price, stock nullable, image_path, active

### 6.3 Clientes
- `customers` — pharmacy_id, name, phone, cpf (único por farmácia), email, birth_date, active  
  Índice único: `(pharmacy_id, cpf)` e `(pharmacy_id, phone)` quando preenchidos

### 6.4 Campanhas e prêmios
- `campaigns`
  - name, slug, description, status (draft|active|paused|ended)
  - starts_at, ends_at
  - min_purchase_amount
  - max_participations_per_customer
  - chances_per_purchase (default 1)
  - mechanic (`scratch`|`wheel`|`direct`)
  - rules_text, notes
- `prizes`
  - pharmacy_id, name, description, type  
    `percent_off` | `fixed_off` | `gift` | `buy_x_get_y` | `points` | `special_coupon` | `custom`
  - percent, amount, buy_qty, get_qty, points
  - min_purchase_amount, validity_days, usage_limit, active
- `campaign_prize` (pivot)
  - campaign_id, prize_id
  - probability_weight (ex.: 30 = 30%)
  - sort_order, active  
  **Constraint app:** soma dos weights ativos da campanha = 100 (ou normalizar pesos relativos — decisão na etapa 5: **soma = 100 obrigatória**)
- `prize_products` / `prize_categories` — escopo do benefício

### 6.5 Participação e sorteio
- `participations`
  - pharmacy_id, campaign_id, customer_id
  - purchase_amount
  - chances_granted
  - status (`pending_play`|`played`|`cancelled`)
  - source (`manual`|`api_pdv` futuro)
  - **campos futuros PDV (nullable agora):** `external_sale_id`, `external_payload` JSON
  - created_by (user_id)
- `participation_plays`
  - participation_id
  - prize_id (sorteado no backend no momento do play ou na criação — ver regra abaixo)
  - coupon_id nullable
  - played_at
  - reveal_token (para link `/participar/{token}`)

**Decisão de sorteio (recomendada):**  
Ao criar a participação (ou no 1º acesso ao link), o backend sorteia e grava `prize_id`. A animação só revela o que já está gravado. Idempotente: refresh não muda o prêmio.

### 6.6 Cupons
- `coupons`
  - pharmacy_id, code (único global ou por pharmacy — **único por pharmacy_id+code**)
  - customer_id, campaign_id, prize_id, participation_play_id
  - status (`available`|`used`|`expired`|`cancelled`)
  - benefit snapshot JSON (congela regras do prêmio no momento da emissão)
  - starts_at, expires_at
  - used_at, used_by (user_id), used_purchase_amount nullable
  - notes

Snapshot no cupom evita mudar prêmio antigo e alterar benefício já emitido.

### 6.7 Tracking
- `campaign_links` — campaign_id, code, label (ex.: Instagram, Balcão), utm/source
- `link_hits` — link_id, ip_hash, ua_hash, created_at
- QR aponta para o mesmo link (`/c/{code}` ou `/participar/...`)

### 6.8 Relacionamentos principais

```
Pharmacy 1──* User / Customer / Campaign / Product / Coupon
Campaign 1──* Participation
Campaign *──* Prize (via campaign_prize + probability)
Participation 1──* ParticipationPlay
ParticipationPlay 1──0..1 Coupon
Customer 1──* Participation / Coupon
Prize *──* Product / Category (escopo)
Campaign 1──* CampaignLink 1──* LinkHit
```

---

## 7. Telas

### Admin
- Login
- Dashboard (filtros de período)
- Campanhas (lista / form / prêmios da campanha)
- Produtos + Categorias
- Prêmios (biblioteca) e vínculo na campanha
- Clientes + ficha (histórico)
- Participações (criar manual: cliente + valor + campanha)
- Cupons (busca) + **Validação caixa** (tela enxuta)
- Relatórios
- Usuários / Configurações da farmácia
- Auditoria (lista)

### Cliente (mobile)
- Landing da campanha `/c/{slug-or-code}`
- Jogar `/participar/{token}` → raspadinha ou roleta
- Resultado + cupom (código grande + validade + QR do cupom)

### Caixa
- `/caixa/validar` — input código → válido/inválido → botão Utilizar

---

## 8. APIs internas (web/Inertia) e preparação PDV

Agora: rotas web autenticadas + rotas públicas de jogo.

**Contrato futuro (não implementar corpo agora — só documentar na etapa 13):**

| Método | Rota futura | Uso |
|--------|-------------|-----|
| POST | `/api/v1/pdv/participations` | PDV registra venda elegível |
| POST | `/api/v1/pdv/coupons/validate` | PDV consulta cupom |
| POST | `/api/v1/pdv/coupons/redeem` | PDV confirma uso |
| GET | `/api/v1/pdv/customers/{cpf}` | lookup |

Auth futura: API token por farmácia. Campos `external_sale_id` / `external_payload` já existem nas participações.

---

## 9. Regras de negócio críticas

1. Probabilidades da campanha: soma = 100; bloquear save inválido.  
2. Sorteio: weighted random no PHP; gravar antes da UI.  
3. Cupom: código curto + entropia (ex. `HIG-8F72KX9`); único; sem reuso.  
4. Validação: existência, status, validade, cliente (se informado), min. compra (se informado), escopo produto/categoria (quando caixa informar — opcional v1).  
5. Limite de participações por cliente na campanha.  
6. Valor mínimo da compra na participação.  
7. Após 1ª play da campanha, edição de prêmios/probabilidades: **bloquear** ou exigir clone de campanha (preferência: bloquear campos sensíveis se já houver plays).  
8. Expiração de cupons: job diário (etapa 12).  
9. Auditoria em: criar/editar campanha, sorteio, emitir cupom, validar/utilizar, cancelar.

---

## 10. Etapas de desenvolvimento

Cada etapa: implementar → testar → você valida → só então próxima.

### ETAPA 1 — Base + auth + usuários
- Breeze/Inertia Vue, layout admin vermelho
- `pharmacies`, roles, seed admin
- middleware por perfil
- **Entrega:** login + usuário admin + shell do painel

### ETAPA 2 — Categorias + produtos
- CRUDs, upload imagem, ativo/inativo
- **Entrega:** catálogo básico

### ETAPA 3 — Clientes
- CRUD + busca CPF/telefone + ficha vazia (histórico depois)
- **Entrega:** cadastro cliente

### ETAPA 4 — Campanhas
- CRUD + status + datas + regras + mecânica
- validação de período
- **Entrega:** campanha sem prêmios ainda (ou só estrutura)

### ETAPA 5 — Prêmios
- CRUD tipos de prêmio
- vínculo campanha + pesos (soma 100)
- escopo produto/categoria
- **Entrega:** campanha completa configurável

### ETAPA 6 — Cupons
- geração, listagem, busca, status, snapshot
- tela de consulta admin
- **Entrega:** cupom manual de teste + listagem

### ETAPA 7 — Participações
- formulário operador: cliente + campanha + valor
- gera play(s) + sorteio + cupom (se aplicável)
- anti-duplicidade / limites
- **Entrega:** fluxo compra → chance → cupom (sem animação)

### ETAPA 8 — Raspadinha
- tela mobile + canvas/touch
- consome resultado já salvo
- **Entrega:** revelação completa

### ETAPA 9 — Roleta
- mesma regra de backend; UI roleta
- **Entrega:** mecânica alternativa

### ETAPA 10 — Links + QR + tracking
- links por origem, QR, contagem de hits
- **Entrega:** `/c/{code}` + métricas básicas

### ETAPA 11 — Dashboard + relatórios
- KPIs e gráficos (Chart.js ou similar)
- filtro período
- **Entrega:** painel gerencial

### ETAPA 12 — Auditoria + segurança + refinamentos
- audit_logs, job expiração, hardening policies, testes
- **Entrega:** base estável

### ETAPA 13 — Preparação PDV
- documentar OpenAPI dos 4 endpoints
- migrations já com campos externos
- stub autenticado (feature flag off)
- **Entrega:** contrato pronto, zero integração real

---

## 11. Ordem e dependências

```
1 Auth → 2 Catálogo → 3 Clientes
         ↘
           4 Campanhas → 5 Prêmios → 7 Participações → 6 Cupons (pode ir junto com 7)
                                              ↓
                                    8 Raspadinha / 9 Roleta
                                              ↓
                                         10 Tracking
                                              ↓
                                      11 Dashboard
                                              ↓
                                   12 Hardening → 13 PDV stub
```

Cupons (6) e Participações (7) na prática sobem juntas: participação emite cupom.

---

## 12. Fora do MVP

- Aplicar desconto no PDV  
- E-commerce / delivery  
- App nativo  
- Multi-loja na mesma tela (só estrutura `pharmacy_id`)  
- IA / ranking complexo  
- SMS/WhatsApp automático  

---

## 13. Critério de pronto por etapa

Antes de pedir ok para a próxima:
- migrations rodando
- telas mínimas usáveis
- regras no backend testadas manualmente (checklist da etapa)
- nada quebrando etapas anteriores

---

## 14. Próximo passo

Aguardando sua autorização para iniciar a **ETAPA 1** (auth + usuários + layout vermelho + pharmacy).

Quando liberar, na etapa 1 eu listo antes: arquivos, tabelas, como testar.
