# Retiro Espiritual 2027 – Sistema de Gestão

> **Igreja Batista Lírio Armação** | Hotel Fazenda Amoras, Santo Antônio de Jesus – BA  
> **Datas do evento:** 05 a 10 de fevereiro de 2027  
> **Inscrições abertas:** a partir de 18/04/2026  
> **Slogan:** _"Enraizar. Crescer. Frutificar."_  
> **Versão atual:** v4.7 — 13/06/2026 — Sistema em produção ✅

---

## ☁️ Infraestrutura Cloudflare (Deploy de Produção)

> **Guia completo:** [`DEPLOY.md`](DEPLOY.md) — passo a passo com ~60 min para o primeiro deploy

### Arquitetura

```
retiro2027.com (Cloudflare Pages)
       │
       ▼
api.retiro2027.com (Cloudflare Workers)
       │
  ┌────┼────────────┐
  ▼    ▼            ▼
 D1   KV           R2
(SQLite) (Cache) (Arquivos)
```

### Arquivos de Infraestrutura

| Arquivo | Descrição |
|---------|-----------|
| `cloudflare/schema.sql` | Schema completo do banco D1 (SQLite) — 11 tabelas + 3 views |
| `cloudflare/seed.sql` | Dados iniciais — 4 usuários + 150 acomodações |
| `cloudflare/worker/src/index.js` | Cloudflare Worker — API REST completa (CRUD + auth + audit) |
| `cloudflare/worker/wrangler.toml` | Configuração do Worker (D1, KV, R2, secrets, rotas) |
| `cloudflare/worker/package.json` | Scripts npm para deploy, migrate, seed |
| `cloudflare/pages.toml` | Referência de configuração do Cloudflare Pages |
| `_headers` | Headers HTTP (CSP, cache, segurança) |
| `_redirects` | Redirecionamentos (www→raiz, atalhos) |
| `_routes.json` | Controle de rotas do Pages |
| `DEPLOY.md` | **Guia passo a passo completo** |

### Endpoints da API

| Método | Rota | Descrição |
|--------|------|-----------|
| GET | `/api/health` | Health check |
| GET | `/api/tables/:table` | Listar registros (paginação, busca, sort) |
| GET | `/api/tables/:table/:id` | Buscar por ID |
| POST | `/api/tables/:table` | Criar registro |
| PUT | `/api/tables/:table/:id` | Atualizar completo |
| PATCH | `/api/tables/:table/:id` | Atualizar parcial |
| DELETE | `/api/tables/:table/:id` | Soft-delete |
| GET | `/api/views/:view` | Executar view SQL |
| GET | `/api/config` | Listar configurações |
| PATCH | `/api/config/:chave` | Atualizar configuração |
| GET | `/api/stats` | KPIs do dashboard |
| POST | `/api/auth/login` | Autenticação |

### Tabelas do Banco de Dados (D1)

| Tabela | Registros iniciais | Descrição |
|--------|-------------------|-----------|
| `usuarios` | 4 | Perfis de acesso (admin/financeiro/hospedagem/alimentacao) |
| `acomodacoes` | 150 | 15 duplos + 30 triplos + 16 quádruplos + 21 internos + 36 masc + 18 fem |
| `inscricoes` | 0 | Registros de inscrição dos retirantes |
| `pagamentos` | 0 | Controle financeiro por inscrição |
| `veiculos` | 0 | Controle de estacionamento |
| `checkins` | 0 | Check-in/out no hotel |
| `fila_espera` | 0 | Lista de espera por tipo |
| `refeicoes` | 0 | Controle alimentação diária |
| `despesas` | 0 | Saídas financeiras |
| `auditoria` | 0 | Log imutável de ações |
| `configuracoes` | 24 | Parâmetros globais do sistema |

### Custos Estimados (Cloudflare Free Plan)

| Serviço | Limite Free | Suficiente para o Retiro? |
|---------|------------|--------------------------|
| Pages | Ilimitado | ✅ Sim |
| Workers | 100k req/dia | ✅ Sim (≤200 participantes) |
| D1 | 5 GB / 5M leituras | ✅ Sim |
| R2 | 10 GB / 10M req | ✅ Sim |
| SSL | Gratuito | ✅ Sim |
| **Total** | **~R$ 0/mês** | ✅ **Gratuito** |

---

## 📁 Estrutura de Arquivos

| Arquivo | Descrição |
|---------|-----------|
| `index.html` | Landing page pública com countdown, acomodações e inscrições |
| `login.html` | Tela de autenticação com 5 perfis de acesso |
| `inscricao.html` | Formulário de inscrição em 5 etapas |
| `dashboard.html` | Painel administrativo com 15 módulos |
| `banco-dados.html` | Visualização e exportação do banco de dados |
| `reset-sistema.html` | 🧹 **Ferramenta de reset** — limpa dados de teste e prepara para produção |
| `css/main.css` | Estilos globais (paleta Luxo Espiritual: Ciano, Petróleo, Verde-água, Areia, Dourado) |
| `js/app.js` | Funções globais e helpers de API |
| `js/dashboard.js` | Lógica completa de todos os módulos do painel |

---

## 🔐 Credenciais de Acesso (Demonstração)

| Perfil | E-mail | Senha |
|--------|--------|-------|
| Administrador Geral | admin@retiro2027.com | admin2027 |
| Equipe Financeira | financeiro@retiro2027.com | fin2027 |
| Equipe de Hospedagem | hospedagem@retiro2027.com | hosp2027 |
| Equipe de Alimentação | alimentacao@retiro2027.com | ali2027 |
| Retirante | retirante@email.com | retiro123 |

---

## 🏠 Acomodações e Valores (em até 10x) — v4.0

| Tipo | Unidades/Vagas | Total | Parcela (10x) |
|------|----------------|-------|---------------|
| Apartamento Duplo | 15 unidades | R$ 3.500,00 | 10x R$ 350,00 |
| Apartamento Triplo | 30 unidades | R$ 4.950,00 | 10x R$ 495,00 |
| Apartamento Quádruplo | 16 vendáveis | R$ 6.300,00 | 10x R$ 630,00 |
| ~~Apartamento Quíntuplo~~ | **REMOVIDO** | — | — |
| ~~Suíte Master~~ | **REMOVIDA** | — | — |
| Alojamento Masculino | 36 vagas | R$ 950,00/vaga | 10x R$ 95,00 |
| Alojamento Feminino | 18 vagas | R$ 950,00/vaga | 10x R$ 95,00 |

> **Fonte de verdade:** `TIPOS_ACOMODACAO` em `js/app.js` + `LIMITES_ACOMODACAO` em `inscricao.html` + campo `preco`/`capacidade` nos 96 registros da tabela `acomodacoes` (atualizado em 31/05/2026).
>
> **Nota técnica:** 96 registros físicos na API (0 suite_master). Limite vendável de Quádruplos (16) controlado por `LIMITES_ACOMODACAO`. Alojamentos: Masc. A/B = 18 vagas cada (total 36); Fem. A/B = 9 vagas cada (total 18).

---

## ✅ Alterações Aplicadas (v4.7 — 13/06/2026)

### 🔗 Inscrição — Etapa 4: Links de Pagamento Automáticos

**Problema:** O bloco "Dados Bancários / Link para Pagamento" exibia dois campos manuais desnecessários:
1. `Tipo de Acomodação para o Link *` — select redundante (já foi escolhida na Etapa 3)
2. `Número de Parcelas` — campo sem uso funcional na área de link

**Solução v4.7 em `inscricao.html`:**

| Item | Antes (v4.2) | Depois (v4.7) |
|---|---|---|
| Seleção do tipo | `<select id="f-link-tipo">` (manual) | **Automático** via `selectedAccom.id` |
| Parcelas do link | `<select id="f-parcelas-link">` | **Removido** — hardcode `1` no save |
| `LINKS_PAGAMENTO` | Objeto com dados bancários (PIX, CNPJ, etc.) | Objeto `tipo → link cfut_...` (5 chaves) |
| `updateLinkPagamento()` | Lê `f-link-tipo`, exibe tabela de dados bancários | Lê `selectedAccom.id`, exibe link principal + link avulsos |
| `selectAccomType()` | Preenchia `f-link-tipo` via `linkMap` | Apenas chama `updateLinkPagamento()` |
| `finalizarInscricao()` | Lê `f-link-tipo` e `f-parcelas-link` | Deriva `link_tipo` de `selectedAccom.id`; `parcelas_link = 1` |

**Links definitivos temporários:**
| Tipo | Link |
|---|---|
| Apartamento Duplo | `cfut_mQbBKA5DwE2EQkoktXZ35NitYDc2Ui5u59zJyzIZ6e8cadb8Ap.Duplo` |
| Apartamento Triplo | `cfut_mQbBKA5DwE2EQkoktXZ35NitYDc2Ui5u59zJyzIZ6e8cadb8Ap.Triplo` |
| Apartamento Quádruplo | `cfut_mQbBKA5DwE2EQkoktXZ35NitYDc2Ui5u59zJyzIZ6e8cadb8Ap.Quádruplo` |
| Alojamentos | `cfut_mQbBKA5DwE2EQkoktXZ35NitYDc2Ui5u59zJyzIZ6e8cadb8Alojamento` |
| Avulsos (crianças +6 anos, diferenciados) | `cfut_mQbBKA5DwE2EQkoktXZ35NitYDc2Ui5u59zJyzIZ6e8cadb8Avulsos` |

> ⚠️ Links temporários — serão atualizados após definição da prestadora bancária.

**Comportamento atual na Etapa 4:**
- Ao selecionar a acomodação (Etapa 3), o campo "Link de Pagamento (gerado automaticamente)" aparece preenchido automaticamente com o link correspondente (somente leitura)
- O box abaixo exibe o **link principal** em destaque azul + o **link de pagamentos avulsos** em destaque dourado com descrição dos casos aplicáveis
- Aviso de links temporários ao final do box

**Playwright:** ✅ 0 erros JS

---

## ✅ Correções Aplicadas (v4.5 — 13/06/2026)

### 🏨 Estrutura de Acomodações — Modelo Definitivo (v4.5)

A partir desta versão, o sistema diferencia claramente **apartamentos físicos**, **vendáveis** e **internos**:

| Categoria | Qtd | Tipo | Destino |
|---|---|---|---|
| 🌸 Duplos | 15 | Apartamento | Venda online |
| 🍊 Triplos | 30 | Apartamento | Venda online |
| 🐦 Quádruplos | 16 | Apartamento | Venda online |
| 🔑 Internos/Equipe | 21 | Apartamento | **Distribuição manual** (Mapa de Ocupação) |
| **Total Físico** | **82** | Apartamento | — |
| 👩 Alojamento Feminino | 18 | Vagas | Venda online |
| 👨 Alojamento Masculino | 36 | Vagas | Venda online |
| **Total Alojamentos** | **54** | Vagas | — |

> **Regra de negócio:** Os 61 vendáveis (15+30+16) são disponibilizados publicamente via formulário de inscrição. Os 21 internos são alocados manualmente pela equipe via **Mapa de Ocupação** no dashboard — nunca aparecem como opção de compra.

---

### 📊 KPI "Apts Disponíveis" — Dashboard Geral

| Campo | Antes (v4.4) | Depois (v4.5) |
|---|---|---|
| Valor exibido | X de 61 apartamentos | X de 82 apts · 61 vendáveis |
| Subtítulo (HTML inicial) | `de 82 apartamentos` | `de 82 apts · 61 vendáveis` |
| Constante `TOTAL_FISICO` | 61 (errado) | **82** (total real do hotel) |
| Constante `TOTAL_VENDAVEIS` | — | **61** (para anti-overbooking) |
| Comportamento | Contava só vendáveis | Mostra total físico + nota dos vendáveis |

---

### 🛏️ Reservas — Resumo por Tipo (5 cards)

| Card | Antes (v4.4) | Depois (v4.5) |
|---|---|---|
| Duplos | 15/15 | 15/15 🏷️ 15 vendáveis |
| Triplos | 30/30 | 30/30 🏷️ 30 vendáveis |
| Quádruplos | 16/16 | 16/16 🏷️ 16 vendáveis |
| Alojamentos | 54/54 | 54/54 (Masc: 36 · Fem: 18) |
| **Novo card** | — | 🔑 **Uso Interno/Equipe** — 21 aptos · Distribuição Manual |

O novo card roxo "Uso Interno / Equipe" informa visualmente à equipe que existem 21 apartamentos reservados para alocação manual — sem confundir com vagas de venda.

---

### 🔒 Anti-Overbooking — `inscricao.html`

Os `LIMITES_ACOMODACAO` permanecem com os valores **vendáveis** (15, 30, 16, 18, 36):
- Os 21 internos **nunca interferem** no anti-overbooking de inscrição online
- `verificarDisponibilidade()` conta apenas inscrições públicas (confirmado/quitado/pendente)
- Os 21 internos são alocados diretamente pela equipe no Mapa — sem registro de inscrição

---

### 🧪 Build/Test State — v4.5

| Arquivo | Playwright | Erros JS |
|---------|-----------|----------|
| `dashboard.html` | ✅ Testado | 0 erros (12 VERBOSE esperados) |
| `inscricao.html` | ✅ Testado | 0 mensagens |

---

## ✅ Correções Aplicadas (v4.4 — 13/06/2026)

### 🐦 Reservas — Quádruplos duplicados corrigidos

**Problema:** A tela de Reservas (Resumo por Tipo) exibia **dois cards separados** para Quádruplos — "Pássaros — Quádruplos" (16 un.) e "Árvores — Quádruplos" (16 un.) — somando visualmente **32 unidades** na contagem. O correto são **16 unidades quádruplas no total**.

**Causa raiz:** `renderReservasSummary()` em `js/dashboard.js` agrupava por `categoria` da API, e tanto "Pássaros" quanto "Árvores" são categorias do mesmo tipo `quadruplo`. Resultado: dois cards distintos para o mesmo tipo físico.

**Correção aplicada em `js/dashboard.js` — `renderReservasSummary()`:**
| Antes (v4.3) | Depois (v4.4) |
|---|---|
| 5 grupos: Flores, Frutas, Alojamento, **Pássaros (16)**, **Árvores (16)** | 4 grupos: Flores, Frutas, **Quádruplos (16)**, Alojamentos |
| Agrupamento por `categoria` (campo da API) | Agrupamento por `tipo` (duplo/triplo/quadruplo/alojamento) |
| Contagem visual: 32 quádruplos | Contagem visual: **16 quádruplos** ✅ |
| Cards mostravam "16 vendáveis" cada | Card único "🐦 Quádruplos · 16 unidades · R$ 6.300" |
| Alojamentos divididos por sub-categoria | Alojamentos unificados: `tipo.startsWith('alojamento')` — Masc: 36 · Fem: 18 = 54 vagas |

---

### 🔢 Dashboard Geral — KPI "Apts Disponíveis" fallback corrigido

**Problema:** O fallback hardcoded era "82 unidades" — valor incorreto. A estrutura real é:
- 15 Duplos + 30 Triplos + 16 Quádruplos = **61 apartamentos físicos**
- Alojamentos são **vagas** (não apartamentos) e não devem ser contados

**Correção em `js/dashboard.js` — `updateKPIs()`:**
| Campo | Antes | Depois |
|---|---|---|
| `TOTAL_APTS_FISICOS` (constante) | `82` (errado) | `61` (15+30+16) |
| Fallback antes de carregar API | `82` | `61` (assume todos disponíveis) |
| Subtítulo do KPI | `de ${totalApts \|\| 82} apartamentos` | `de ${totalApts} apartamentos` (sem fallback fixo errado) |

---

### 🔒 Segurança Login — Reconfirmada e reforçada (v4.3 → v4.4)

O isolamento de segurança v4.3 foi **reconfirmado ativo** no código:
- `verificarSessaoAtiva()` ✅ verifica `perfil ∈ PERFIS_EQUIPE` antes de redirecionar
- `handleLogin()` ✅ bloqueia qualquer perfil não-equipe de acessar o dashboard
- "Já sou inscrito" (index.html → login.html) ✅ limpa sessão residual de retirante

---

### 🗺️ Mapa de Ocupação — Subtítulo corrigido

- Texto "Visualização de todos os 82 apartamentos" → "Visualização de todos os apartamentos e alojamentos em tempo real"

---

### 🧪 Build/Test State — v4.4

| Arquivo | Playwright | Erros JS |
|---------|-----------|----------|
| `login.html` | ✅ Testado | 0 erros (3 VERBOSE esperados) |
| `dashboard.html` | ✅ Testado | 0 erros (12 VERBOSE esperados) |

---

## ✅ Correções Aplicadas (v4.3 — 13/06/2026)

### 🔒 Segurança — Isolamento total do fluxo Retirante vs. Equipe de Gestão

**Problema:** A IIFE `verificarSessaoAtiva()` em `login.html` redirecionava qualquer sessão ativa para `dashboard.html`, independente do perfil. Se um administrador estava logado e outro usuário abria `login.html`, a sessão de admin era detectada e o dashboard abria com permissões administrativas — expondo dados confidenciais.

**Correção aplicada em `login.html`:**
| Antes (v4.2) | Depois (v4.3) |
|---|---|
| `verificarSessaoAtiva()` → redireciona qualquer sessão para `dashboard.html` | Verifica `u.perfil` antes de redirecionar |
| Retirante com sessão ativa → abre dashboard como admin | Retirante → sessão limpa, permanece no login |
| Sessão corrompida → potencial acesso indevido | Sessão corrompida → limpa por segurança |
| `handleLogin()` → qualquer perfil válido acessa dashboard | Retirante bloqueado com mensagem clara antes de gravar sessão |

**Lógica de segurança v4.3:**
```
PERFIS_EQUIPE = [admin, financeiro, hospedagem, alimentacao]
SE sessão ativa E perfil ∈ PERFIS_EQUIPE → redireciona para dashboard.html  ✅
SE sessão ativa E perfil = retirante → limpa sessão, permanece no login       🔒
SE perfil = retirante tenta login → bloqueia acesso ao dashboard               ⛔
```

---

### 📊 Dashboard Geral — KPI "Apts Disponíveis" corrigido

**Problema:** O KPI exibia "96 de 82 unidades" — contava todos os 96 registros da API incluindo alojamentos, ultrapassando o máximo físico de 82 apartamentos.

**Correção aplicada em `js/dashboard.js` — `updateKPIs()`:**
| Antes (v4.2) | Depois (v4.3) |
|---|---|
| `disponiveis = allAcomodacoes.filter(a => a.status === 'disponivel').length` | Filtra apenas `tipo ∈ {duplo, triplo, quadruplo}` |
| Contava 96 registros (inclui alojamentos) | Conta apenas 82 apartamentos físicos |
| Label fixo "de 82 unidades" no HTML | Label dinâmico `de ${totalApts} apartamentos` via `id="kpiAptsSub"` |
| Texto: "de 82 unidades" | Texto: "de 82 apartamentos" |

**Correção aplicada em `dashboard.html`:**
- `<div class="kpi-sub">de 82 unidades</div>` → `<div class="kpi-sub" id="kpiAptsSub">de 82 apartamentos</div>`

---

### 💰 Dashboard Geral — KPI Receita Total zerado

**Correção aplicada em `js/dashboard.js` — `updateKPIs()`:**
- Quando `allPagamentos = []`, exibe `R$ 0` (não mais valor residual de sessão anterior)
- Subtítulo muda para "Nenhum pagamento registrado" quando zerado

---

### 💳 Gestão Financeira — KPIs, Gráficos e Lista zerados (estado pós-reset)

| Elemento | Comportamento v4.3 |
|---|---|
| KPIs: Receita Total / Recebido / Pendente | R$ 0,00 em cinza (indicador de sistema limpo) |
| KPI: Pagamentos Quitados | 0 de 0 inscritos |
| Gráfico "Por Forma de Pagamento" | Pizza cinza "Sem registros" — sem crash |
| Gráfico "Evolução de Recebimentos" | Barras zeradas com nota "Sem pagamentos registrados" |
| Lista de Pagamentos | Ícone 💳 + mensagem "Nenhum pagamento registrado" |
| **Despesas** | **MANTIDO INTACTO — sem alterações** ✅ |

---

### 📈 Relatórios — Valores zerados quando banco vazio

| Elemento | Comportamento v4.3 |
|---|---|
| Tabela "Resumo Financeiro" | Spinner → "Nenhum pagamento registrado ainda." |
| Gráfico "Distribuição Financeira" | Doughnut cinza "Sem registros" (antes: crash com [0,0]) |
| Gráfico "Inscrições por Tipo" | Barras cinzas zeradas com nota informativa |
| Permissão financeira negada | Mensagem "🔒 Dados financeiros — acesso restrito" |
| Erro de rede | Mensagem de erro em vermelho (antes: silencioso) |

---

### 🧪 Build/Test State — v4.3

| Arquivo | Playwright | Erros JS |
|---------|-----------|----------|
| `login.html` | ✅ Testado | 0 erros (3 VERBOSE esperados — campos senha sem form) |
| `dashboard.html` | ✅ Testado | 0 erros (12 VERBOSE esperados — campos senha sem form) |

---

## ✅ Funcionalidades Implementadas (v4.2 — 13/06/2026)

### 📋 Inscrição — Etapa 4: Dados Bancários / Link de Pagamento — v4.2

- **Novo bloco** inserido entre "Forma de Pagamento" e "Comprovante de Pagamento"
- **Select "Tipo de Acomodação para o Link"** com opções:
  - Apartamento Duplo · Apartamento Triplo · Apartamento Quádruplo · Alojamentos · Link Manual
- **Pré-seleção automática:** ao escolher acomodação na Etapa 2, o tipo do link já é selecionado
- **Ao selecionar Duplo/Triplo/Quádruplo/Alojamentos:**
  - Exibe campo **Número de Parcelas** com valores calculados por tipo (1× até 10×)
  - Exibe **box de dados bancários** com Chave PIX, Banco, Titular, CNPJ e Valor
- **Ao selecionar Link Manual:** exibe aviso de que o link será enviado pela equipe financeira por e-mail/WhatsApp
- **Link personalizado pelo Admin:** quando `localStorage['retiro2027_links_pagamento']` contiver uma URL para o tipo, ela é exibida em destaque verde dentro do box
- **Campos `link_tipo` e `parcelas_link`** gravados no registro de pagamento na API
- **Resumo da Etapa 5** exibe o tipo de link e parcelas escolhidos

### 💰 Dashboard Financeiro — Estado zerado pós-reset — v4.2

- **KPIs corrigidos:** calculados a partir de `valor_pendente` real (não mais por subtração) — nunca exibem valor residual
- **Zerado visualmente:** quando não há pagamentos, KPIs exibem `R$ 0,00` em cinza (indicador de sistema limpo)
- **Lista de pagamentos vazia:** exibe ícone 💳 + mensagem orientativa em vez de linha em branco
- **Lista com dados:** exibe badge verde `🔗 Tipo · Nx` com o link de pagamento registrado pelo retirante
- **Gráfico "Por Forma de Pagamento":** sem dados → pizza cinza com label "Sem registros" (sem crash, sem tela branca)

### 📊 Build/Test State — v4.2

| Arquivo | Playwright | Erros JS |
|---------|-----------|----------|
| `inscricao.html` | ✅ Testado | 0 mensagens |
| `dashboard.html` | ✅ Testado | 0 erros (12 VERBOSE esperados) |

---

## ✅ Funcionalidades Implementadas (v4.1 — Atualização 31/05/2026)

### 🛡️ Resiliência para 200+ Usuários Simultâneos — v4.1 (NOVO — 31/05/2026)

#### `js/app.js` — Helpers globais de resiliência
| Melhoria | Antes | Depois |
|----------|-------|--------|
| Retry automático nas chamadas API | ❌ 0 tentativas | ✅ 3 tentativas + backoff exponencial (500ms→1s→2s) |
| Timeout por request | ❌ Sem limite | ✅ AbortController com 15s por tentativa |
| Paginação automática | ❌ Sempre limit=200 | ✅ `apiGetAll()` — busca todas as páginas transparentemente |
| Debounce de filtros | ❌ Render a cada keystroke | ✅ `debounce(fn, ms)` — helper global |
| UUID de registros | ❌ `Date.now()+Math.random()` — colisível | ✅ `generateUUID()` via `crypto.randomUUID()` + fallback RFC-4122 |
| Toast simultâneos | ❌ Acúmulo ilimitado no DOM | ✅ Máximo 5 simultâneos; o mais antigo é removido automaticamente |
| Toast auto-remoção | ❌ Sem animação | ✅ Fade-out + `clearTimeout` no clique (evita double-remove) |
| `formatDateTime` | ❌ `new Date(d)` criado duas vezes (redundante) | ✅ Criado uma vez; guard `isNaN` + tratamento de strings "YYYY-MM-DD" como local |

#### `js/dashboard.js` — Correções de concorrência e memória
| Melhoria | Antes | Depois |
|----------|-------|--------|
| Auto-refresh com aba oculta | ❌ `setInterval` rodando mesmo com tab oculta | ✅ **Page Visibility API** pausa e reinicia o intervalo |
| Double-load de páginas | ❌ Dois cliques rápidos = dois fetches simultâneos | ✅ Guard `_pageLoading[page]` + `showPage` debounced 150ms |
| `filterInscricoes()` | ❌ Render síncrono a cada keystroke | ✅ Debounce 250ms |
| `filterVeiculos()` | ❌ Render síncrono a cada keystroke | ✅ Debounce 250ms |
| `filterPagamentos()` | ❌ Render síncrono a cada keystroke | ✅ Debounce 200ms |
| `searchForRecibo()` | ❌ Fetch a cada keystroke (sem cache) | ✅ Debounce 350ms + cache local de 30s |
| `savePagamento()` | ❌ Sem guard de double-submit | ✅ Flag `_savingPagamento` + botão desabilitado durante request |
| `saveVeiculo()` | ❌ Sem guard de double-submit | ✅ Flag `_savingVeiculo` + botão desabilitado durante request |
| `saveDespesa()` | ❌ Sem guard de double-submit | ✅ Flag `_savingDespesa` + botão desabilitado durante request |
| Gráfico Evolução Financeira | ❌ **`Math.random()` — dados FALSOS** em produção | ✅ **Dados reais** de `allPagamentos` agrupados por mês (Abr/2026–Fev/2027) |
| `renderChartRelAcoms()` | ❌ `type: 'horizontalBar'` declarado duas vezes | ✅ Propriedade duplicada removida |
| Valor total do pagamento | ❌ Hardcoded para `TIPOS_ACOMODACAO['duplo'].preco` | ✅ Usa `tipoConfig.preco` do tipo real do retirante |

#### `inscricao.html` — Anti-overbooking e robustez
| Melhoria | Antes | Depois |
|----------|-------|--------|
| ID de inscrição | ❌ `Date.now()+Math.random()` — colisível sob carga | ✅ `crypto.randomUUID()` com fallback RFC-4122 via `getRandomValues` |
| Falha de rede em `verificarDisponibilidade` | ❌ Retornava `1` (overbooking silencioso!) | ✅ 2 tentativas + aguarda 1s; retorna `-1` e BLOQUEIA inscrição |
| Timeout nas chamadas de verificação | ❌ Sem timeout | ✅ AbortController 10s por página |
| `pendente` ocupa vaga? | ❌ Apenas `confirmado`/`quitado` contavam | ✅ `pendente` também reserva vaga (evita race condition entre inscrições simultâneas) |
| Mensagem de falha de rede | ❌ Permitia continuar | ✅ Toast claro + aborta inscrição com botão restaurado |

#### `login.html` — Segurança
| Melhoria | Antes | Depois |
|----------|-------|--------|
| Brute-force | ❌ Tentativas ilimitadas | ✅ Rate limiting: máx. 5 tentativas / 60s via `localStorage` |
| Feedback de bloqueio | ❌ Sem feedback de tentativas restantes | ✅ Mostra "X tentativa(s) restante(s)" e "bloqueado por Xs" |
| Reset de rate limit | — | ✅ Reseta automaticamente após login bem-sucedido |

#### `index.html` — Performance
| Melhoria | Antes | Depois |
|----------|-------|--------|
| Logo da navbar | ❌ Carrega junto com tudo | ✅ `loading="eager" decoding="async"` |
| Logo do hero | ❌ Sem atributos de carregamento | ✅ `loading="eager" decoding="async"` |
| Scroll reveal | ✅ Já usava `IntersectionObserver` (eficiente) | ✅ Mantido |

---

### Estrutura de Acomodações — v4.0 (ATUALIZADO — 31/05/2026)
- **Suíte Master REMOVIDA** — tipo `suite_master` extinto do sistema; 2 registros (Angico/Braúna) convertidos para `quadruplo/Árvores/R$6.300`
- **Novos preços:** Duplo R$3.500 | Triplo R$4.950 | Quádruplo R$6.300 | Alojamentos R$950
- **Novas quantidades:** Duplo=15 | Triplo=30 | Quádruplo=16 vendáveis | Aloj.Masc=36 vagas | Aloj.Fem=18 vagas
- **Parcelas (10x):** Duplo=R$350 | Triplo=R$495 | Quádruplo=R$630 | Alojamentos=R$95
- **API:** 94 PATCH de preço (0 erros) + 2 conversões suite_master→quadruplo (HTTP200) + ajuste capacidade alojamentos
- **Arquivos atualizados:** `js/app.js`, `inscricao.html`, `index.html`, `js/dashboard.js` (10 substituições)
- **Verificação API:** 0 suite_master | VAGAS_MASC:36 ✓ | VAGAS_FEM:18 ✓ | todos preços OK
- **Playwright test:** `dashboard.html` — ✅ 0 erros JS
- **Playwright test v4.1:** `dashboard.html` ✅ 0 erros JS | `login.html` ✅ 0 erros JS | `inscricao.html` ✅ 0 erros JS

### Valores de Acomodações — v3.8 (ATUALIZADO — 31/05/2026)
- **Todos os preços atualizados** em toda a aplicação (arquivos estáticos + registros da API):
  - Apartamento Duplo: ~~R$ 4.000~~ → **R$ 3.650** (10x R$ 365)
  - Apartamento Triplo: ~~R$ 5.400~~ → **R$ 5.470** (10x R$ 547)
  - Apartamento Quádruplo: ~~R$ 6.600~~ → **R$ 6.380** (10x R$ 638)
  - Apartamento Quíntuplo: ~~R$ 7.500~~ → **R$ 6.380** (10x R$ 638)
  - Suíte Master: ~~R$ 6.500~~ → **R$ 6.530** (10x R$ 653)
  - Alojamentos (Fem/Masc): ~~R$ 1.300~~ → **R$ 1.150** (10x R$ 115)
- **Arquivos atualizados:** `js/app.js` (TIPOS_ACOMODACAO), `inscricao.html` (tipos array), `index.html` (cards landing page), `js/dashboard.js` (fallback 3650)
- **API:** 82 PATCH operations — todos os campos `preco` atualizados com sucesso
- **🔴 Bug corrigido:** Suíte Master (apts 64 Angico e 65 Braúna) tinham perdido `tipo=suite_master` e `categoria=Suíte` durante correção de categorias anterior → restaurados via PATCH + price 6530
- **Verificação:** `verify-precos.html` confirmou 7 tipos corretos; `fix-suite2.html` confirmou `PATCH HTTP200` para ambas as suítes
- **Arquivos temporários removidos:** `fix-precos.html`, `fix-suite.html`, `fix-suite2.html`, `verify-precos.html`
- **Playwright test:** `dashboard.html` — ✅ 0 erros JS

### Mapa de Ocupação — v3.7 (CORRIGIDO — Duplicatas e Categorias)
- **🔴 Bug crítico corrigido:** 207 registros na API (82 únicos corretos + 125 duplicatas) → todos os duplicados removidos via DELETE
- **Diagnóstico:** dois lotes de seed distintos (`apt-XX` e `apt-0XX`) geravam duplicatas de número 1 a 82 + números 83–125 extras
- **Correção de categorias:** 46 registros com categoria/tipo errados → PATCH aplicado (100% conforme)
- **Renomeação de apartamentos:** 35 apts renomeados para nomes coerentes com sua categoria:
  - Árvores (50–80): Ipê Amarelo, Cedro, Jequitibá, Imbuia, Aroeira, Pau-Brasil, Garapeira, Pequi, Buriti, Babaçu, Cajueiro, Umbuzeiro, Juazeiro, Jatobá, Angico, Braúna, Caatinga, Mandacaru, Jurema, Cumaru, Amburana, Canafístula, Pereiro, Marmeleiro, Favela, Catingueira, Sabiá, Jurubeba, Velame, Tingui, Xique-xique
  - Alojamento (29, 30): Alojamento Masc. A / Masc. B
  - Alojamento (81, 82): Alojamento Fem. A / Fem. B
- **`renderReservasSummary()`** reescrita: usa `categoria` (não `tipo`) como chave, totais corretos por grupo, barra de progresso por ocupação real (`confirmado`+`quitado`)
- **`renderMapa()`** aprimorado: grupos ordenados canonicamente (Flores → Frutas → Alojamento → Pássaros → Árvores), range de números exibido no título de cada grupo
- **Estado final da API:** 82 registros únicos, 0 duplicatas, 100% conformes com a especificação

#### Mapa de Acomodações — Especificação Canônica v4.0

| Grupo | Registros API | Qtd Vendável | Tipo | Exemplos de Nomes |
|-------|--------------|-------------|------|-------------------|
| 🌸 Flores | 18 registros | **15** duplos | duplo | Violeta, Rosa, Margarida, Girassol, Lavanda... |
| 🍊 Frutas | 24 registros | **30** triplos | triplo | Uva, Goiaba, Manga Rosa, Amora, Figo, Romã... |
| 🏠 Alojamento | 4 registros | **Masc: 36 · Fem: 18** vagas | alojamento_masc/fem | Aloj. Masc. A/B · Aloj. Fem. A/B |
| 🐦 Pássaros | 19 registros | **16** vendáveis | quadruplo | João de Barro, Asa Branca, Tucano, Beija-Flor... |
| 🌳 Árvores | 31 registros | **16** vendáveis | quadruplo | Ipê Amarelo, Cedro, Aroeira, Angico, Braúna... |
| ~~⭐ Suíte~~ | **0 registros** | **REMOVIDA** | ~~suite_master~~ | Angico/Braúna realocados para Árvores |

> **Nota:** 96 registros totais na API. Limite vendável controlado por `LIMITES_ACOMODACAO` em `inscricao.html`.

### Login (`login.html`) — v3.6 (CORRIGIDO — ReferenceError crítico)
- **🔴 Bug crítico corrigido (v3.6):** Login do Administrador travava com "fica rodando e não abre"
  - **Causa raiz:** `adminPanelAberto` era referenciada em `handleLogin()` (linha do guard de segurança) mas **nunca foi declarada** no script — `ReferenceError` silencioso travava o `setTimeout` inteiro
  - **Correção:** `let adminPanelAberto = false` declarada no **topo do script**, antes de qualquer função, garantindo escopo global correto
  - `abrirAdminPanel()` agora usa `panel.style.setProperty('display','block','important')` + atualiza `adminPanelAberto = true`
  - `fecharAdminPanel()` usa `panel.style.removeProperty('display')` + `adminPanelAberto = false` + limpa campos
  - Guard em `handleLogin()`: Admin só autentica se `adminPanelAberto === true` — mensagem clara orienta o usuário
  - Script completamente reescrito e reorganizado com seções documentadas
- **🆕 Recuperação de Senha — Retirante (modal 3 etapas, visual polido):**
  - Etapa 1: Retirante informa Nome Completo + CPF
  - Sistema consulta tabela `retirantes` via API (busca + normalização de acentos)
  - Etapa 2: Se validado → define nova senha (mínimo 6 chars) com confirmação + toggle de visibilidade
  - PATCH em `tables/retirantes/{id}` no campo `senha_hash`
  - Etapa 3: Feedback de sucesso + botão retornar ao login
  - Fechar clicando no backdrop (fora do modal)
  - "Esqueceu a senha?" para equipes mostra mensagem orientando contato com o Admin
- Senhas customizadas pelo Admin são verificadas via `localStorage['retiro2027_senhas']`
- Fluxo de login: 4 estágios de validação (campos vazios → credencial → guarda admin → sessão)

### Landing Page (`index.html`) — v3.2 (ATUALIZADO)
- Countdown regressivo para o retiro
- Exibição das acomodações com formato **"até 10x de R$ X"**
- Links para inscrição e login
- **🖼️ Galeria de Fotos no Hero** — posicionada entre a logomarca e o título "Retiro Espiritual 2027":
  - Layout breakout: `width: 100vw; max-width: 1280px` — escapa do container `max-width: 900px`
  - Exibe **3 fotos simultaneamente** lado a lado (esquerda · centro · direita)
  - **Foto central em destaque:** `clamp(260px, 38vw, 520px)`, borda glow ciano `#2EC4B6`, sombra profunda
  - **Fotos laterais dimadas:** `clamp(160px, 26vw, 360px)`, scale(0.72), opacidade 0.50, brightness 0.65
  - Responsivo com 4 breakpoints: 1024px · 768px · 480px
  - Setas ◀ ▶ nas extremidades para navegação infinita/circular
  - Suporte a **swipe touch** para mobile (pausa 3s após swipe)
  - **🆕 Fade crossfade ao trocar fotos** — `opacity: 0 → 1` em 0.45s ao trocar src
  - **🆕 Auto-advance automático a cada 5s** — pausa ao hover/focus, reinicia ao navegar manualmente
  - **🆕 Barra de progresso** animada (gradiente ciano) na base da foto central; dourada quando pausada
  - Contador de posição (ex: `2 / 16`) + legenda com nome da foto
  - **Modo Admin (dupla entrada):**
    - Via **sessionStorage** `currentUser` (login no dashboard como admin) → ⚙️ ativo automaticamente
    - Via **botão 📷 flutuante** (canto inferior direito) → mini-modal com senha `admin2027`
  - Botão flutuante muda para 🖼️ dourado quando admin está ativo
  - **Modal de Gerenciamento (Admin):**
    - Aba "Do Computador": seletor de arquivo + drag-and-drop → Canvas API (800px, JPEG 0.82) → Base64
    - Aba "Por Link (URL)": campo URL + nome personalizado
    - Preview em grid antes de confirmar; barra de progresso durante processamento
    - Indicador de uso de localStorage (limite 4.5 MB)
    - ⭐ Definir foto inicial; 🗑️ remover fotos individualmente
  - **16 fotos reais do retiro** em `images/galeria/` (≈1.7 MB total)
  - Fotos persistidas via `localStorage` (chave: `retiro2027_fotos_v3`)
  - **Navbar limpa:** sem carrossel miniatura — apenas logo + texto + links de navegação
- **🎨 Paleta Luxo Espiritual** em toda a página:
  - Ciano `#00FFFF` · Azul Petróleo `#0B3C49` · Verde Água `#2EC4B6` · Areia `#F4F1DE` · Dourado `#C6A75E`

### Inscrição (`inscricao.html`) — 5 Etapas
1. **Dados Pessoais** – validação obrigatória de TODOS os campos (nome, nascimento, CPF, e-mail, celular, sexo); campos de acompanhantes também são obrigatórios
2. **Acomodação** – seleção em tempo real com contagem de disponíveis; exibe "até 10x de R$ X"
3. **Acompanhantes** – campos dinâmicos conforme capacidade do tipo
4. **Pagamento** – PIX, cartão, transferência, dinheiro, boleto; **parcelamento em até 10x** com valor por parcela calculado dinamicamente
5. **Confirmação** – resumo completo + aceite de termos

#### Anti-Overbooking (NOVO)
- Antes de finalizar, verifica vagas disponíveis no banco via API
- Se esgotado → inscrição automática na **Fila de Espera** com tela específica
- Limites: Duplo=15, Triplo=30, Quádruplo=16, Aloj.Masc=36, Aloj.Fem=18

### Dashboard Administrativo (`dashboard.html`)

#### Módulo Inscrições
- Tabela com filtros (busca, status, tipo de acomodação)
- **Tipo de Acomodação** exibido em todas as listagens
- CRUD completo, exportação CSV/XLSX

#### Módulo Dashboard Geral
- KPIs: total inscritos, confirmados, arrecadação, ocupação
- **Painel "Inscritos Confirmados por Acomodação"** — exclusivo para Admin/Financeiro/Hospedagem
- Tabela de últimas inscrições com tipo de acomodação

#### Módulo Reservas
- Visualização em tempo real com estados (pré-reserva, confirmada, cancelada, pendente, quitada)

#### Módulo Mapa de Ocupação (ATUALIZADO)
- 82 apartamentos temáticos (Flores, Frutas, Pássaros, Árvores, Alojamentos)
- Cores por status (disponível, ocupado, reservado, manutenção)
- **Botão "Renomear Apartamentos"** — Admin e Hospedagem podem clicar no nome de qualquer apartamento para renomeá-lo via prompt
- Modo de Edição ativável/desativável com indicador visual

#### Módulo Refeições (ATUALIZADO — v3.2)
- Controle por participante e dia
- **Cardápio Diário pré-cadastrado e editável** para os 6 dias do retiro (05 a 10/02/2027): Café da Manhã, Almoço e Jantar
- **Edição e adição de novos cardápios:** Admin e Equipe de Alimentação podem editar cardápios existentes e adicionar novos via modal
- **Controle de acesso total ao cardápio para Retirantes:**
  - O card "Cardápio do Dia" é **completamente ocultado** para perfil Retirante
  - Botões "Editar Cardápio" são ocultados via CSS (`body.no-edit-cardapio .btn-edit-cardapio`)
  - Função `abrirModalCardapio()` bloqueia qualquer perfil não autorizado (dupla proteção)
  - Função `toggleRefeicao()` também bloqueia Retirantes de alterar registros
- Seletor de data limitado ao período do retiro (05–10/02/2027)
- KPIs diários de cada refeição

#### Módulo Financeiro
- Formas de pagamento: PIX, cartão, transferência, dinheiro, boleto
- **Parcelamento em até 10x**
- Gráficos de arrecadação, despesas e distribuição por forma de pagamento
- Emissão de recibos

#### Módulo Check-in / Check-out
- Registro de entrada e saída com data/hora e responsável

#### Módulo Veículos
- Cadastro de condutor, marca, modelo, placa, cor, ano

#### Módulo Relatórios — v3.5 (ATUALIZADO — Permissões Granulares)
- Exportação PDF e XLSX para todos os módulos
- **🔒 Controle por tipo de relatório (granular por perfil):**
  - `relatoriosPermitidos` array no `ACESSO_PERFIL.hospedagem` como fonte de verdade
  - Hospedagem vê e exporta: **Lista de Inscritos**, **Ocupação de Acomodações**, **Relatório de Refeições**, **Veículos Cadastrados**
  - Hospedagem **NÃO** vê: Relatório Financeiro, Auditoria do Sistema, Resumo Financeiro, Gráfico Distribuição Financeira
  - `aplicarControleRelatorios()` — oculta cards via `data-rel` e elementos por ID
  - Guard duplo em `exportarRelatorio()`: verifica `relatoriosPermitidos` + `podeVerFinanceiro`
  - `loadRelatorios()` não busca tabela `pagamentos` para perfis sem `podeVerFinanceiro`

#### Módulo Usuários — v3.3 (ATUALIZADO)
- Gestão de perfis e permissões por módulo (tabela visual completa)
- **🆕 Administração de Senhas (Admin exclusivo):**
  - Admin pode redefinir senhas para Equipe Financeira, Hospedagem e Alimentação
  - Confirmação de senha com campo duplo + toggle de visibilidade
  - Senhas customizadas salvas em `localStorage['retiro2027_senhas']`
  - `login.html` verifica senhas customizadas ANTES das padrão (override sem código)
  - Histórico de alterações visível na mesma sessão
  - Card totalmente oculto para perfis não-admin (segurança extra)

#### Módulo Auditoria
- Log de todas as ações com usuário, módulo, IP e data/hora
- **Acesso exclusivo do Administrador Geral**

---

## 🔐 Matriz de Controle de Acesso — v3.5 (IMPLEMENTADA)

> Fonte de verdade: objeto `ACESSO_PERFIL` em `js/dashboard.js`

### Módulos por Perfil

| Módulo | Admin | Financeiro | Hospedagem | Alimentação | Retirante |
|--------|:-----:|:----------:|:----------:|:-----------:|:---------:|
| Dashboard (KPIs gerais) | ✅ | ✅ | ✅ | ✅ | ❌ |
| KPI Receita/Financeiro | ✅ | ✅ | ❌ | ❌ | ❌ |
| KPI Inscritos | ✅ | ✅ | ✅ | ❌ | ❌ |
| Inscrições (lista) | ✅ | ❌ | 👁️ leitura | ❌ | ❌ |
| Reservas / Mapa / Fila | ✅ | ❌ | ✅ | ❌ | ❌ |
| Check-in / Check-out | ✅ | ❌ | ✅ | ❌ | ❌ |
| Refeições | ✅ | ❌ | ❌ | ✅ | ❌ |
| Veículos | ✅ | ❌ | ✅ | ❌ | ❌ |
| Financeiro / Pagamentos | ✅ | ✅ | ❌ | ❌ | ❌ |
| Despesas | ✅ | ✅ | ❌ | ❌ | ❌ |
| Recibos | ✅ | ✅ | ❌ | ❌ | ❌ |
| Relatórios (acesso à página) | ✅ | ✅ | ✅ | ❌ | ❌ |
| Gestão de Usuários | ✅ | ❌ | ❌ | ❌ | ❌ |
| Auditoria | ✅ | ❌ | ❌ | ❌ | ❌ |
| Meu Perfil | ✅ | ✅ | ✅ | ✅ | ✅ |

### Dados Sensíveis por Perfil

| Dado | Admin | Financeiro | Hospedagem | Alimentação | Retirante |
|------|:-----:|:----------:|:----------:|:-----------:|:---------:|
| CPF completo | ✅ | ✅ | 🔒 `•••.•••.•••-••` | ❌ | ❌ |
| Celular | ✅ | ✅ | 🔒 `(••) •••••-••••` | ❌ | ❌ |
| Dados financeiros | ✅ | ✅ | ❌ | ❌ | ❌ |
| Excluir registros | ✅ | ❌ | ❌ | ❌ | ❌ |
| Alterar status inscrição | ✅ | ❌ | ✅ | ❌ | ❌ |

### Página Inicial por Perfil (redirect automático ao login)

| Perfil | Página Inicial |
|--------|---------------|
| Administrador | Dashboard Geral |
| Financeiro | Dashboard Geral |
| Hospedagem | Dashboard Geral |
| Alimentação | Dashboard Geral |
| Retirante | Meu Perfil (único acesso) |

### Permissões Granulares por Relatório (v3.5)

| Relatório | Admin | Financeiro | Hospedagem | Alimentação |
|-----------|:-----:|:----------:|:----------:|:----------:|
| Lista de Inscritos | ✅ | ✅ | ✅ | ❌ |
| Relatório Financeiro | ✅ | ✅ | ❌ | ❌ |
| Ocupação de Acomodações | ✅ | ✅ | ✅ | ❌ |
| Relatório de Refeições | ✅ | ✅ | ✅ | ❌ |
| Veículos Cadastrados | ✅ | ✅ | ✅ | ❌ |
| Auditoria do Sistema | ✅ | ❌ | ❌ | ❌ |
| Resumo Financeiro (card) | ✅ | ✅ | ❌ | ❌ |
| Gráfico Distribuição Fin. | ✅ | ✅ | ❌ | ❌ |

### Implementação Técnica

- **`ACESSO_PERFIL`** — objeto único em `dashboard.js` como fonte de verdade
- **`getAcesso()`** — retorna as permissões do usuário logado
- **`podeAcessar(page)`** — verifica se a página está na lista de permitidas
- **`aplicarControleMenu(acesso)`** — oculta botões de menu via `data-section` e `data-page`
- **`showPage(page)`** — guarda de acesso: redireciona para página inicial se não autorizado
- **`relatoriosPermitidos`** — array em cada perfil do `ACESSO_PERFIL`; `null` = todos liberados
- **`aplicarControleRelatorios()`** — oculta cards `[data-rel]` bloqueados; oculta `#cardTotalFinanceiro` e `#cardChartRelFin`
- **`exportarRelatorio(tipo, formato)`** — guard duplo no topo: verifica `relatoriosPermitidos` + `podeVerFinanceiro`
- **`loadRelatorios()`** — não busca tabela `pagamentos` para perfis com `podeVerFinanceiro: false`
- **Guards em funções de API** — `loadFinanceiro`, `loadDespesas`, `loadAuditoria` verificam permissão antes de buscar dados
- **Mascaramento de dados** — CPF/celular exibidos como `•••` para perfis sem permissão
- **CSS classes** — `body.no-financeiro`, `body.no-excluir`, `body.no-edit-cardapio` para controle visual adicional

#### 🆕 Indicadores Visuais de Perfil (v3.2)
- **Avatar colorido** na topbar e sidebar com gradiente por perfil:
  - Admin → Dourado `#C6A75E`
  - Financeiro → Verde Água `#2EC4B6`
  - Hospedagem → Ciano `#00FFFF`
  - Alimentação → Laranja `#FF8C42`
  - Retirante → Cinza `#718096`
- **Badge de perfil** com ícone Font Awesome + rótulo colorido em:
  - Topbar (ao lado do nome)
  - Barra lateral (seção de usuário, novos elementos `#sidebarUserAvatar/Name/Role`)
  - Página "Meu Perfil"
- Sidebar colapsa corretamente ocultando nome/role mas mantendo avatar colorido

### Controle de Acesso por Perfil
| Perfil | Acesso |
|--------|--------|
| Admin | Todos os módulos |
| Financeiro | Financeiro, despesas, recibos, relatórios, inscrições |
| Hospedagem | Mapa, reservas, check-in, inscrições (+ renomear aptos) |
| Alimentação | Refeições, relatórios |
| **Retirante** | **Apenas seu próprio perfil** (inscrições, financeiro, mapa, relatórios e cardápio ocultados) |

### Login (`login.html`) — v3.2 (ATUALIZADO)
- **Perfis públicos visíveis:** Financeiro, Hospedagem, Alimentação, Retirante
- **Painel Admin oculto:** acessível apenas pelo link discreto "🔒 Acesso restrito — equipe de gestão"
- `selectProfile()` preenche e-mail automaticamente, **nunca preenche a senha**
- Dupla proteção: login de admin bloqueado se painel admin não estiver aberto
- **🆕 Sincronização de sessão:** após login bem-sucedido, grava em **ambos**:
  - `localStorage['retiro2027_user']` — persistência de 24h para `app.js`
  - `sessionStorage['currentUser']` — detecção automática de admin na galeria da landing page
- `logout()` em `app.js` limpa ambos os storages + `sessionStorage['landingAdminAtivo']`

### Banco de Dados (`banco-dados.html`)
- Visualização em tempo real de todas as 9 tabelas
- Exportação por tabela: JSON, Excel (XLSX), CSV
- Exportação geral: todos os formatos de uma vez

---

## 🗄️ Tabelas do Banco de Dados

| Tabela | Descrição | Campos |
|--------|-----------|--------|
| `retirantes` | Inscritos e usuários | 18 campos |
| `acomodacoes` | 82 apartamentos numerados | 10 campos |
| `pagamentos` | Histórico de pagamentos | 13 campos |
| `checkins` | Registros de entrada/saída | 12 campos |
| `refeicoes` | Controle por participante/dia | 10 campos |
| `fila_espera` | Fila por tipo de acomodação | 8 campos |
| `veiculos` | Veículos dos participantes | 10 campos |
| `despesas` | Despesas estimadas/confirmadas | 9 campos |
| `auditoria` | Log de ações do sistema | 7 campos |

---

## 🔗 URLs do Sistema

| Página | URL |
|--------|-----|
| Landing Page | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/` |
| Inscrição Pública | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/inscricao.html` |
| Login | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/login.html` |
| Dashboard Admin | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/dashboard.html` |
| Banco de Dados | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/banco-dados.html` |
| 🧹 Reset do Sistema | `https://2b086e3d-c064-4505-a489-5b4da4c0b515.vip.gensparksite.com/reset-sistema.html` |

---

## 🎨 Paleta de Cores — Luxo Espiritual (v3.0)

| Nome | Hex | Uso |  
|------|-----|-----|
| Ciano (predominante) | `#00FFFF` | Acentos, eyebrows, contador, nav ativo |
| Azul Petróleo | `#0B3C49` | Fundo hero, sidebar, modais, gradientes |
| Verde Água | `#2EC4B6` | Botões primários, bordas de card, hover, slogans |
| Areia Clara | `#F4F1DE` | Background geral do dashboard (alias cinza-100) |
| Dourado Elegante | `#C6A75E` | Logo, preços, badges especiais, botão Inscreva-se |

---

## 📁 Galeria de Fotos — Arquivos Locais

| Arquivo | Descrição |
|---------|-----------|
| `images/galeria/foto01-volei-por-do-sol.jpg` | Vôlei ao pôr do sol |
| `images/galeria/foto02-lagoa-hotel.jpg` | Lagoa do Hotel Fazenda Amoras |
| `images/galeria/foto03-vista-lagoa.jpg` | Vista panorâmica da lagoa |
| `images/galeria/foto04-futebol-campo.jpg` | Partida de futebol no campo |
| `images/galeria/foto05-circulo-comunhao.jpg` | Círculo de comunhão |
| `images/galeria/foto06-confraternizacao-noturna.jpg` | Confraternização noturna |
| `images/galeria/foto07-passeio-cavalo.jpg` | Passeio a cavalo |
| `images/galeria/foto08-fantasia-noturna.jpg` | Noite de fantasia |
| `images/galeria/foto09-noite-biblica.jpg` | Noite bíblica |
| `images/galeria/foto10-equipe-alimentacao.jpg` | Equipe de alimentação |
| `images/galeria/foto11-piscina-por-do-sol.jpg` | Piscina ao pôr do sol |
| `images/galeria/foto12-anjinhos.jpg` | Anjinhos |
| `images/galeria/foto13-tirolesa-voo.jpg` | Tirolesa em voo |
| `images/galeria/foto14-tirolesa-plataforma.jpg` | Plataforma da tirolesa |
| `images/galeria/foto15-colheita-laranjas.jpg` | Colheita de laranjas |
| `images/galeria/foto16-canoagem-lagoa.jpg` | Canoagem na lagoa |

---

## 🚀 Próximos Passos Recomendados

### Resiliência e Escala (pós-v4.1)
- [ ] Implementar **cache de dashboard** (localStorage com TTL 30s) para reduzir carga nos endpoints durante pico de acesso
- [ ] Adicionar **Service Worker** para cache offline das páginas estáticas (index, login, inscricao)
- [ ] **Otimistic UI** no Mapa de Ocupação: marcar apto como "reservando..." localmente antes do PATCH confirmar
- [ ] Integrar envio de e-mail de confirmação ao inscrito

### Funcionalidades
- [ ] Notificação automática por WhatsApp para fila de espera
- [ ] Relatório consolidado de acomodações por dia (check-in/out)
- [ ] Impressão do crachá/comprovante em PDF diretamente pelo retirante
- [ ] Dashboard de mapa de calor financeiro (metas vs. arrecadado)
- [ ] Módulo de comunicados/avisos para os retirantes
- [ ] Sincronizar fotos da galeria via tabela API (persistência multi-dispositivo sem localStorage)
- [ ] Adicionar painel de notificações (sino) com alertas de novas inscrições e pagamentos pendentes

---

## 📊 Build/Test State (v4.1 — 31/05/2026)

| Arquivo | Playwright | Erros JS |
|---------|-----------|----------|
| `dashboard.html` | ✅ Testado | 0 erros (12 VERBOSE esperados) |
| `login.html` | ✅ Testado | 0 erros (3 VERBOSE esperados) |
| `inscricao.html` | ✅ Testado | 0 mensagens |
| Nenhum build step | — | Site estático servido diretamente |
