---
sidebar_position: 9
title: Versionamento e Detecção de Atualizações
---

# Versionamento e Detecção Automática de Atualizações

## Visão Geral

A plataforma Decoda implementa um sistema automático de detecção de atualizações que recarrega a aplicação quando um novo deploy é detectado. Isso garante que os usuários sempre utilizem a versão mais recente sem necessidade de ação manual.

---

## Como Funciona

### Arquivo `version.json`

Durante o build Docker, o Dockerfile gera um arquivo `version.json` contendo metadados de versão:

```json
{
  "version": "1.1.3",
  "commit": "abc1234def5678",
  "buildDate": "2026-06-05T10:30:45Z"
}
```

Este arquivo é:
- ✅ Gerado a cada build
- ✅ Servido pelo Nginx junto com os arquivos estáticos
- ✅ Sempre atualizado (sem cache)
- ✅ Acessível em `/version.json`

**Geração no Dockerfile:**

```dockerfile
RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json
```

### Script de Detecção em `index.html`

No `<head>` da página, um script verifica atualizações:

```javascript
(async function checkForUpdates() {
  try {
    // Busca a versão atual do servidor
    const response = await fetch('/version.json?t=' + Date.now());
    const newVersion = await response.json();
    const lastVersion = sessionStorage.getItem('app_version');

    // Se houver versão anterior e for diferente da atual
    if (lastVersion && lastVersion !== newVersion.commit) {
      console.log('🔄 Novo deploy detectado. Recarregando...');
      sessionStorage.setItem('app_version', newVersion.commit);
      window.location.reload(true);
      return;
    }

    // Armazena versão atual para próxima verificação
    sessionStorage.setItem('app_version', newVersion.commit);
  } catch (e) {
    console.warn('Falha ao verificar atualizações:', e);
  }
})();
```

### Fluxo de Detecção

```
1. Usuário acessa a página (GET /)
   ↓
2. Script em index.html executa
   ├─ Faz fetch de /version.json (sem cache: ?t=Date.now())
   ├─ Compara commit com sessionStorage
   │
   ├─ Se não há versão anterior:
   │  └─ Armazena e continua
   │
   └─ Se versão mudou:
      ├─ Armazena nova versão
      ├─ Log: "🔄 Novo deploy detectado"
      └─ window.location.reload(true) → força reload do cache
```

### Parâmetro `?t=Date.now()`

O parâmetro `?t=` garante que o navegador **não use o cache** de `/version.json`:

- **Sem o parâmetro:** Browser pode servir versão antiga do cache
- **Com o parâmetro:** Browser sempre faz nova requisição
- **Resultado:** Atualizações são detectadas na primeira página acessada

### `window.location.reload(true)`

O parâmetro `true` força reload ignorando cache:

```javascript
window.location.reload(true);  // ✅ Ignora cache, carrega do servidor
window.location.reload();      // ❌ Pode usar cache
```

---

## Armazenamento em sessionStorage

O commit hash é armazenado em `sessionStorage` (não `localStorage`):

- **sessionStorage** — Limpo ao fechar a aba/navegador
- **localStorage** — Persiste entre sessões

Usar `sessionStorage` garante que:
- Verificação acontece em cada nova aba/janela
- Histórico de versões não acumula
- Usuário tem sempre a última versão do servidor

---

## Metadados Disponíveis

O arquivo `/version.json` contém:

| Campo | Exemplo | Descrição |
|---|---|---|
| `version` | `1.1.3` | Versão semântica da app |
| `commit` | `abc1234def5678` | Hash curto do commit Git |
| `buildDate` | `2026-06-05T10:30:45Z` | Data/hora do build |

Exemplo de acesso programático:

```javascript
// Obter informações de versão no console
fetch('/version.json')
  .then(r => r.json())
  .then(v => console.log(v));

// Output:
// { version: "1.1.3", commit: "abc1234", buildDate: "..." }
```

---

## Variáveis de Build

O Dockerfile recebe argumentos para gerar a versão:

```dockerfile
ARG GIT_COMMIT_HASH=unknown
ARG APP_VERSION=1.1.3

RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", ...}" > public/version.json
```

### Passar argumentos

**Via Docker Compose:**

```bash
docker compose build --build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) app
```

**Via arquivo `.env`:**

```bash
GIT_COMMIT_HASH=abc1234
```

**Via docker build direto:**

```bash
docker build --build-arg GIT_COMMIT_HASH=abc1234 -t decoda:latest ./app
```

---

## Casos de Uso

### Usuário deixa a página aberta

```
14:00 — Usuário acessa /atividades
        Script detecta versão "abc1234"

14:15 — Deploy realizado com commit "def5678"

14:20 — Usuário navega para /atividades/puzzle
        Script detecta versão mudou
        → Recarrega página com novo código
```

### Novo deploy, usuário abre nova aba

```
14:00 — Deploy realizado com versão "def5678"

14:05 — Usuário abre nova aba (GET /)
        Script detecta versão "def5678"
        → Versão nova é carregada na aba
```

### Offline, usuário reconecta

```
14:00 — Usuário offline, página em cache
        Script falha ao fetch /version.json
        → Log: "Falha ao verificar atualizações"
        → Usuário continua com versão anterior

14:15 — Usuário reconecta e navega

14:20 — Script detecta nova versão
        → Recarrega com versão atualizada
```

---

## Tratamento de Erros

O script trata erros graciosamente:

```javascript
catch (e) {
  console.warn('Falha ao verificar atualizações:', e);
}
```

**Cenários:**

- ✅ **Offline** — Erro de network, silencioso, continua rodando
- ✅ **JSON inválido** — Parse error, log, continua rodando
- ✅ **Timeout** — Requisição fica pendurada, timeout natural
- ✅ **Nginx indisponível** — Erro 500/502, log, continua rodando

**Resultado:** Sempre funciona, nunca quebra a página

---

## Debugging

### Ver versão atual no console

```javascript
sessionStorage.getItem('app_version')
// Output: "abc1234def5678"
```

### Forçar reload de versão

```javascript
sessionStorage.removeItem('app_version');
location.reload();
// Próximo acesso detectará e armazenará nova versão
```

### Inspecionar /version.json

```bash
# Terminal
curl http://localhost/version.json

# Browser DevTools
fetch('/version.json').then(r => r.json()).then(console.log)
```

---

## Integração com Analytics

O commit hash também é enviado para Google Analytics:

```javascript
// Em usePageTracking.js
analytics.trackPageView({
  page_path: location.pathname,
  page_title: document.title,
  git_commit: window.APP_VERSION?.commit, // Hash do deploy
});
```

Permite rastrear qual versão o usuário estava utilizando quando completou uma atividade.

---

## Boas Práticas

1. **Sempre passar `GIT_COMMIT_HASH`** — Facilita debugging
   ```bash
   docker compose build --build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) app
   ```

2. **Usar arquivo `.env`** — Mais limpo e repetível
   ```bash
   GIT_COMMIT_HASH=$(git rev-parse --short HEAD) docker compose up --build
   ```

3. **Monitorar logs** — Verifique `console.log('🔄 Novo deploy detectado')`
   ```bash
   # Browser DevTools → Console
   ```

4. **Testar localmente** — Modifique `version.json` e navegue para testar

---

## Limitações e Considerações

| Aspecto | Descrição |
|---|---|
| **Timing** | Detecta somente quando usuário acessa página, não em tempo real |
| **sessionStorage** | Limpo ao fechar aba, não persiste entre navegadores |
| **SPA** | Apenas recarrega ao navegar, não há polling contínuo |
| **Sem notificação** | Recarrega silenciosamente, sem avisar usuário |

### Se precisar de comportamento diferente

- **Polling contínuo** — Usar `setInterval()` em vez de só no load
- **Notificação ao usuário** — Mostrar modal antes de reload
- **localStorage** — Persistir versão entre abas/sessões
- **Update prompts** — Permitir usuário decidir quando recarregar

Veja [service-workers.md](sistema-tours.md) para implementações mais avançadas com PWA.

---

## Referências

- [sessionStorage MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)
- [HTTP Cache Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
- [Service Workers para atualizações](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
