feature/ga4 #2
45
README.md
45
README.md
@@ -143,6 +143,51 @@ plataforma-edu-docs-1 Up 2 minutes
|
||||
plataforma-edu-proxy-1 Up 2 minutes 0.0.0.0:80->80/tcp
|
||||
```
|
||||
|
||||
#### Build com Google Analytics 4 (GA4)
|
||||
|
||||
Para ativar analytics em produção, use argumentos de build:
|
||||
|
||||
**Com variáveis de ambiente:**
|
||||
|
||||
Crie um arquivo `.env` na raiz do projeto:
|
||||
|
||||
```bash
|
||||
GIT_COMMIT_HASH=abc1234
|
||||
VITE_ANALYTICS_PROVIDER=ga4
|
||||
VITE_GA4_ID=G-SEU_ID_GA4
|
||||
VITE_GA4_DEBUG=false
|
||||
```
|
||||
|
||||
Então execute:
|
||||
|
||||
```bash
|
||||
docker compose build app
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**Ou diretamente via argumentos:**
|
||||
|
||||
```bash
|
||||
docker compose build \
|
||||
--build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) \
|
||||
--build-arg VITE_ANALYTICS_PROVIDER=ga4 \
|
||||
--build-arg VITE_GA4_ID=SEU_ID_AQUI \
|
||||
app
|
||||
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**Para desabilitar analytics (desenvolvimento):**
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg VITE_ANALYTICS_PROVIDER=noop app
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
> 📊 **Nota:** Obtém seu ID do GA4 em [https://analytics.google.com](https://analytics.google.com) → Administração → Data Streams → Copie o ID de medição (formato: G-XXXXXXXXXX)
|
||||
|
||||
Para mais detalhes, veja: [Documentação de Analytics](docs/docs/plataforma/arquitetura/analytics.md)
|
||||
|
||||
---
|
||||
|
||||
### Opção 2: Desenvolvimento Local
|
||||
|
||||
23
app/.dockerignore
Normal file
23
app/.dockerignore
Normal file
@@ -0,0 +1,23 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
.github
|
||||
.vscode
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
.env.offline
|
||||
*.md
|
||||
docs
|
||||
jupyter
|
||||
SDD
|
||||
.specify
|
||||
.specs
|
||||
.cache
|
||||
.pnpmfile.cjs
|
||||
.npmrc
|
||||
coverage
|
||||
.nyc_output
|
||||
.vercel
|
||||
@@ -1,3 +1,45 @@
|
||||
# ============================================================================
|
||||
# ANALYTICS CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
# Provider: 'ga4' para Google Analytics 4, ou 'noop' para desabilitar
|
||||
# Padrão: 'ga4' em produção, 'noop' em desenvolvimento
|
||||
VITE_ANALYTICS_PROVIDER=ga4
|
||||
VITE_GA4_ID=
|
||||
|
||||
# Google Analytics 4 - ID de Medição (ID do fluxo de dados)
|
||||
# Obtenha em: https://analytics.google.com → Administração → Data Streams
|
||||
# Formato: G-XXXXXXXXXX
|
||||
# Deixe em branco para desabilitar GA4 (mesmo que VITE_ANALYTICS_PROVIDER=ga4)
|
||||
VITE_GA4_ID=G-57HGKF773M
|
||||
|
||||
# Debug mode: 'true' para ativar logs de eventos no console do browser
|
||||
# Útil para testing e desenvolvimento
|
||||
VITE_GA4_DEBUG=false
|
||||
|
||||
# Banner de consentimento de cookies (LGPD/GDPR)
|
||||
# 'true' para mostrar, 'false' para desabilitar
|
||||
VITE_ENABLE_CONSENT_BANNER=true
|
||||
|
||||
# ============================================================================
|
||||
# BUILD CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
# Git commit hash - usado para versionamento e detecção de atualizações
|
||||
# Deixe em branco para usar 'unknown' durante o build
|
||||
# Será preenchido automaticamente em CI/CD
|
||||
GIT_COMMIT_HASH=
|
||||
|
||||
# ============================================================================
|
||||
# NOTAS
|
||||
# ============================================================================
|
||||
#
|
||||
# Para desenvolvimento (sem analytics):
|
||||
# VITE_ANALYTICS_PROVIDER=noop
|
||||
#
|
||||
# Para produção (com GA4):
|
||||
# VITE_ANALYTICS_PROVIDER=ga4
|
||||
# VITE_GA4_ID=G-SEU_ID_AQUI
|
||||
# VITE_GA4_DEBUG=false
|
||||
#
|
||||
# Veja ANALYTICS.md e DOCKER_BUILD_EXAMPLES.md para mais detalhes
|
||||
#
|
||||
|
||||
@@ -15,19 +15,16 @@ ENV VITE_ANALYTICS_PROVIDER=$VITE_ANALYTICS_PROVIDER
|
||||
ENV VITE_GA4_ID=$VITE_GA4_ID
|
||||
ENV VITE_GA4_DEBUG=$VITE_GA4_DEBUG
|
||||
|
||||
RUN npm install -g pnpm
|
||||
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install
|
||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json
|
||||
|
||||
RUN pnpm run build
|
||||
RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json && \
|
||||
pnpm run build && \
|
||||
rm -rf node_modules .pnpm-store
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
COPY nginx-spa.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
@@ -6,6 +6,26 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title>Decoda</title>
|
||||
<script>
|
||||
(async function checkForUpdates() {
|
||||
try {
|
||||
const response = await fetch('/version.json?t=' + Date.now());
|
||||
const newVersion = await response.json();
|
||||
const lastVersion = sessionStorage.getItem('app_version');
|
||||
|
||||
if (lastVersion && lastVersion !== newVersion.commit) {
|
||||
console.log('🔄 Novo deploy detectado. Recarregando...');
|
||||
sessionStorage.setItem('app_version', newVersion.commit);
|
||||
window.location.reload(true);
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem('app_version', newVersion.commit);
|
||||
} catch (e) {
|
||||
console.warn('Falha ao verificar atualizações:', e);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -12,13 +12,15 @@ import LabPython from "./pages/LabPython/LabPython";
|
||||
import ScrollToTop from "./components/ScrollToTop";
|
||||
import { getAnalytics, usePageTracking } from "./services/analytics";
|
||||
import { initializeAnalytics, analyticsConfig } from "./services/analytics";
|
||||
import { ConsentManager } from "./services/consent";
|
||||
|
||||
// Inline CookieBanner para evitar bloqueio do Brave
|
||||
function CookieBanner() {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const enableBanner = import.meta.env.VITE_ENABLE_CONSENT_BANNER === 'true';
|
||||
|
||||
useEffect(() => {
|
||||
if (!enableBanner) return;
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem('decoda_consent');
|
||||
if (!stored) {
|
||||
@@ -27,7 +29,7 @@ function CookieBanner() {
|
||||
} catch (e) {
|
||||
console.error('Consent check failed:', e);
|
||||
}
|
||||
}, []);
|
||||
}, [enableBanner]);
|
||||
|
||||
const handleAccept = () => {
|
||||
try {
|
||||
@@ -57,7 +59,7 @@ function CookieBanner() {
|
||||
}
|
||||
};
|
||||
|
||||
if (!visible) return null;
|
||||
if (!visible || !enableBanner) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-0 left-0 right-0 z-50 p-4 md:p-6" role="dialog" aria-label="Consentimento de cookies">
|
||||
@@ -212,11 +214,10 @@ export default function App() {
|
||||
const [analyticsReady, setAnalyticsReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const hasConsent = ConsentManager.hasConsent();
|
||||
initializeAnalytics({
|
||||
providerType: analyticsConfig.providerType,
|
||||
measurementId: analyticsConfig.measurementId,
|
||||
hasConsent,
|
||||
hasConsent: true,
|
||||
debugMode: analyticsConfig.debugMode,
|
||||
});
|
||||
|
||||
|
||||
435
docs/docs/plataforma/arquitetura/analytics.md
Normal file
435
docs/docs/plataforma/arquitetura/analytics.md
Normal file
@@ -0,0 +1,435 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: Analytics - GA4
|
||||
---
|
||||
|
||||
# Analytics e Rastreamento - Google Analytics 4
|
||||
|
||||
## Visão Geral
|
||||
|
||||
O Decoda implementa um sistema de analytics que permite acompanhar o uso da plataforma e entender como os estudantes interagem com as atividades educacionais. O sistema utiliza **Google Analytics 4 (GA4)** como provedor padrão, mas será migrado para solução open source e auto hospedada no futuro.
|
||||
|
||||
### Objetivos
|
||||
|
||||
- 📊 **Acompanhamento de uso** — entender quais atividades são mais usadas
|
||||
- 📈 **Análise de performance** — identificar onde os estudantes têm dificuldade
|
||||
- 📚 **Melhoria educacional** — usar dados para aprimorar o conteúdo
|
||||
- 🔒 **Privacidade** — respeitar escolha do usuário com consentimento prévio
|
||||
|
||||
---
|
||||
|
||||
## Arquitetura do Sistema
|
||||
|
||||
O sistema de analytics é modular e extensível:
|
||||
|
||||
```text
|
||||
src/services/
|
||||
├── analytics/
|
||||
│ ├── AnalyticsManager.js # Orquestrador central
|
||||
│ ├── config.js # Configuração global
|
||||
│ ├── NetworkDetector.js # Detecta conectividade
|
||||
│ ├── googleConsentMode.js # Conformidade GDPR/LGPD
|
||||
│ ├── usePageTracking.js # Hook: rastrear rotas
|
||||
│ ├── useActivityTracking.js # Hook: atividades com fases
|
||||
│ ├── useLetramentoTracking.js # Hook: atividades simples
|
||||
│ ├── providers/
|
||||
│ │ ├── BaseProvider.js # Interface base
|
||||
│ │ ├── GA4Provider.js # Implementação GA4
|
||||
│ │ └── NoopProvider.js # Dummy para offline
|
||||
│ └── index.js # Exports
|
||||
└── consent/
|
||||
├── ConsentManager.js # Gerencia consentimento
|
||||
├── useConsent.js # Hook de acesso
|
||||
└── index.js
|
||||
```
|
||||
|
||||
### Componentes Principais
|
||||
|
||||
#### **AnalyticsManager**
|
||||
|
||||
Orquestrador central que:
|
||||
- Instancia o provedor apropriado (GA4, Noop, etc)
|
||||
- Verifica consentimento antes de rastrear
|
||||
- Verifica conectividade (offline-aware)
|
||||
- Fornece interface unificada para tracking
|
||||
|
||||
#### **Provedores (Providers)**
|
||||
|
||||
Interface plugável para diferentes serviços:
|
||||
|
||||
- **GA4Provider** — Envia eventos para Google Analytics 4
|
||||
- **NoopProvider** — Não faz nada (usado em desenvolvimento)
|
||||
|
||||
#### **ConsentManager**
|
||||
|
||||
Gerencia o consentimento do usuário:
|
||||
- Armazena escolha em localStorage
|
||||
- Inicializa Google Consent Mode
|
||||
- Dispara eventos quando consentimento muda
|
||||
|
||||
---
|
||||
|
||||
## Configuração
|
||||
|
||||
### Variáveis de Ambiente
|
||||
|
||||
Configure o analytics através de variáveis de ambiente no build Docker:
|
||||
|
||||
**Produção (com GA4):**
|
||||
|
||||
```bash
|
||||
VITE_ANALYTICS_PROVIDER=ga4
|
||||
VITE_GA4_ID=G-57HGKF773M
|
||||
VITE_GA4_DEBUG=false
|
||||
```
|
||||
|
||||
**Desenvolvimento (sem rastreamento):**
|
||||
|
||||
```bash
|
||||
VITE_ANALYTICS_PROVIDER=noop
|
||||
VITE_GA4_ID=
|
||||
```
|
||||
|
||||
### Arquivo `.env.example`
|
||||
|
||||
```bash
|
||||
# Analytics Provider: 'ga4' ou 'noop'
|
||||
VITE_ANALYTICS_PROVIDER=noop
|
||||
|
||||
# Google Analytics 4 ID (ID de medição do GA4)
|
||||
# Obtenha em: https://analytics.google.com → Data Streams → Web
|
||||
VITE_GA4_ID=
|
||||
|
||||
# Debug mode para GA4 (mostra eventos no console)
|
||||
VITE_GA4_DEBUG=false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Docker com Analytics
|
||||
|
||||
### Build Básico (Desenvolvimento)
|
||||
|
||||
```bash
|
||||
docker compose build app
|
||||
docker compose up app
|
||||
```
|
||||
|
||||
### Build com GA4 (Produção)
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg VITE_ANALYTICS_PROVIDER=ga4 \
|
||||
--build-arg VITE_GA4_ID=G-SEU_ID_AQUI \
|
||||
--build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) app
|
||||
```
|
||||
|
||||
### Build com Variáveis de Ambiente
|
||||
|
||||
Crie um arquivo `.env` na raiz do projeto:
|
||||
|
||||
```bash
|
||||
GIT_COMMIT_HASH=abc1234
|
||||
VITE_ANALYTICS_PROVIDER=ga4
|
||||
VITE_GA4_ID=G-57HGKF773M
|
||||
VITE_GA4_DEBUG=false
|
||||
```
|
||||
|
||||
Então execute:
|
||||
|
||||
```bash
|
||||
docker compose build app
|
||||
docker compose up
|
||||
```
|
||||
|
||||
### Usando docker build diretamente
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) \
|
||||
--build-arg VITE_ANALYTICS_PROVIDER=ga4 \
|
||||
--build-arg VITE_GA4_ID=G-SEU_ID_AQUI \
|
||||
-t decoda:latest \
|
||||
./app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fluxo de Consentimento
|
||||
|
||||
O sistema implementa um fluxo LGPD/GDPR-compliant:
|
||||
|
||||
```
|
||||
Primeiro acesso
|
||||
↓
|
||||
[CookieBanner aparece]
|
||||
↓
|
||||
Usuário escolhe
|
||||
├─→ "Aceitar"
|
||||
│ ├─ Armazena consentimento em localStorage
|
||||
│ ├─ Carrega GA4 script
|
||||
│ ├─ Inicializa Google Consent Mode
|
||||
│ └─ Começa a rastrear
|
||||
│
|
||||
└─→ "Rejeitar"
|
||||
├─ Armazena consentimento=false em localStorage
|
||||
├─ Carrega NoopProvider
|
||||
└─ Não rastreia nada
|
||||
```
|
||||
|
||||
### Armazenamento
|
||||
|
||||
- Chave: `decoda_consent`
|
||||
- Valor: `true` (aceito) ou `false` (rejeitado)
|
||||
- Local: localStorage (persiste entre sessões)
|
||||
|
||||
---
|
||||
|
||||
## Rastreamento de Eventos
|
||||
|
||||
### Page Views (Automático)
|
||||
|
||||
Toda mudança de rota dispara automaticamente:
|
||||
|
||||
```javascript
|
||||
page_view {
|
||||
page_path: '/atividades/puzzle',
|
||||
page_title: 'Puzzle Game',
|
||||
language: 'pt-BR'
|
||||
}
|
||||
```
|
||||
|
||||
**Integração:** Hook `usePageTracking()` no `App.jsx`
|
||||
|
||||
### Atividades de Programação (Com Fases)
|
||||
|
||||
Para atividades com múltiplas fases como Puzzle, Aspirador, etc:
|
||||
|
||||
```javascript
|
||||
import { useActivityTracking } from '@/services/analytics';
|
||||
|
||||
export default function PuzzleGame() {
|
||||
const { trackPhaseCompletion } = useActivityTracking(gameConfig);
|
||||
|
||||
useEffect(() => {
|
||||
if (phaseCompleted) {
|
||||
trackPhaseCompletion(phaseId, phaseName, success);
|
||||
}
|
||||
}, [phaseCompleted]);
|
||||
|
||||
return <GameBase gameFactory={createGame} gameConfig={gameConfig} />;
|
||||
}
|
||||
```
|
||||
|
||||
**Eventos gerados:**
|
||||
- `fase_completada` — quando fase é resolvida
|
||||
- `fase_falhou` — quando usuário falha
|
||||
- `atividade_abandonada` — quando sai sem terminar
|
||||
|
||||
**Dados rastreados:**
|
||||
- `atividade_id`, `atividade_nome`
|
||||
- `fase_numero`, `fase_nome`
|
||||
- `tempo_sessao_segundos`
|
||||
- `categoria` (ex: Variáveis, Sequências)
|
||||
|
||||
### Atividades de Letramento (Simples)
|
||||
|
||||
Para atividades sem fases como Mouse, Teclado:
|
||||
|
||||
```javascript
|
||||
import { useLetramentoTracking } from '@/services/analytics';
|
||||
|
||||
export function MouseBasico() {
|
||||
const { trackCompletion } = useLetramentoTracking('mouse-basico', 'Mouse');
|
||||
|
||||
return (
|
||||
<button onClick={() => trackCompletion(true)}>
|
||||
Concluir
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Eventos gerados:**
|
||||
- `letramento_atividade_completada` — sucesso
|
||||
- `letramento_atividade_falhou` — falha
|
||||
|
||||
### Rastreamento Customizado
|
||||
|
||||
```javascript
|
||||
import { getAnalytics } from '@/services/analytics';
|
||||
|
||||
const analytics = getAnalytics();
|
||||
analytics.trackEvent('hint_used', {
|
||||
activity: 'puzzle-fase-1',
|
||||
hint_type: 'algorithm',
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comportamento Offline
|
||||
|
||||
O Decoda é projetado para funcionar sem internet:
|
||||
|
||||
- **Quando offline**: Eventos são ignorados silenciosamente
|
||||
- **Sem armazenamento em fila**: Não há fila local de eventos
|
||||
- **Quando reconecta**: Apenas eventos após reconexão são rastreados
|
||||
- **Sem erros**: Falhas de analytics não afetam a app
|
||||
|
||||
---
|
||||
|
||||
## Relatórios no GA4
|
||||
|
||||
### Acessar a Propriedade
|
||||
|
||||
1. Abra [https://analytics.google.com](https://analytics.google.com)
|
||||
2. Selecione propriedade "Decoda"
|
||||
3. Navegue para relatórios
|
||||
|
||||
### Relatórios Úteis
|
||||
|
||||
**Dashboard em Tempo Real:**
|
||||
- `Relatórios → Em tempo real`
|
||||
- Vê eventos acontecendo agora
|
||||
- Útil para testar implementação
|
||||
|
||||
**Atividades mais usadas:**
|
||||
- `Relatórios → Envolvimento → Eventos`
|
||||
- Filtrar por `page_path` contendo `/atividades/`
|
||||
- Agregar por `page_title`
|
||||
|
||||
**Taxa de conclusão por fase:**
|
||||
- `Relatórios → Envolvimento → Eventos`
|
||||
- Procurar por `fase_completada`
|
||||
- Agrupar por `fase_numero`
|
||||
|
||||
**Tempo gasto por atividade:**
|
||||
- `Relatórios → Envolvimento → Páginas e telas`
|
||||
- Ver `tempo_médio_na_página`
|
||||
|
||||
---
|
||||
|
||||
## Offline-First Build
|
||||
|
||||
Para criar uma build sem analytics (offline):
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg VITE_ANALYTICS_PROVIDER=noop app
|
||||
```
|
||||
|
||||
Ou via arquivo `.env`:
|
||||
|
||||
```bash
|
||||
VITE_ANALYTICS_PROVIDER=noop
|
||||
```
|
||||
|
||||
Depois:
|
||||
|
||||
```bash
|
||||
pnpm run build:offline
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Política de Privacidade
|
||||
|
||||
A página `/privacy-policy` está integrada na app e explica:
|
||||
|
||||
- ✅ O que é rastreado (page views, eventos de atividades)
|
||||
- ✅ Quem coleta (Google Analytics)
|
||||
- ✅ Como optar por não ser rastreado (cookies)
|
||||
- ✅ Conformidade LGPD e GDPR
|
||||
|
||||
---
|
||||
|
||||
## Google Consent Mode
|
||||
|
||||
O sistema implementa [Google Consent Mode](https://support.google.com/analytics/answer/9976101) para conformidade regulatória:
|
||||
|
||||
- **analytics_storage** — controlado por consentimento do usuário
|
||||
- **ad_storage** — desabilitado (Decoda não exibe anúncios)
|
||||
- **ad_personalization** — desabilitado
|
||||
|
||||
Garante que GA4 respeita a escolha GDPR/LGPD do usuário.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### GA4 não está rastreando
|
||||
|
||||
**Checklist:**
|
||||
|
||||
1. ✅ Variável `VITE_ANALYTICS_PROVIDER=ga4`?
|
||||
2. ✅ Variável `VITE_GA4_ID` configurada corretamente?
|
||||
3. ✅ Usuário aceitou cookies?
|
||||
4. ✅ Verificou em GA4 Real-time?
|
||||
|
||||
**Debug:**
|
||||
|
||||
```bash
|
||||
# Ativar debug mode
|
||||
VITE_GA4_DEBUG=true docker compose build app
|
||||
```
|
||||
|
||||
Procure por logs no console do browser:
|
||||
|
||||
```
|
||||
GA4: Tracking event 'page_view'
|
||||
GA4: Event sent successfully
|
||||
```
|
||||
|
||||
### Eventos não aparecem em GA4
|
||||
|
||||
- GA4 leva até 24h para processar eventos
|
||||
- Use `Relatórios → Em tempo real` para verificação imediata
|
||||
- Verifique se consentimento foi aceito (`localStorage.getItem('decoda_consent')`)
|
||||
|
||||
### Banner de cookies não aparece
|
||||
|
||||
```javascript
|
||||
// No console do browser:
|
||||
localStorage.removeItem('decoda_consent');
|
||||
location.reload();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Extensibilidade
|
||||
|
||||
Para adicionar um novo provedor (ex: Umami, Plausible):
|
||||
|
||||
1. **Crie arquivo:** `src/services/analytics/providers/UmamiProvider.js`
|
||||
|
||||
```javascript
|
||||
import { BaseProvider } from './BaseProvider';
|
||||
|
||||
export class UmamiProvider extends BaseProvider {
|
||||
async initialize() {
|
||||
// Carregar script Umami
|
||||
}
|
||||
|
||||
trackPageView(data) {
|
||||
// Implementar rastreamento
|
||||
}
|
||||
|
||||
trackEvent(eventName, eventData) {
|
||||
// Implementar rastreamento
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Registre em:** `src/services/analytics/config.js`
|
||||
|
||||
3. **Atualize variáveis:** `.env.example` e `Dockerfile`
|
||||
|
||||
---
|
||||
|
||||
## Referências
|
||||
|
||||
- [Google Analytics 4 Docs](https://developers.google.com/analytics/devguides/collection/ga4)
|
||||
- [Google Consent Mode](https://support.google.com/analytics/answer/9976101)
|
||||
- [LGPD Lei 13.709](http://www.planalto.gov.br/ccivil_03/_ato2015-2018/2015/lei/l13105.htm)
|
||||
- [GDPR Official](https://gdpr-info.eu/)
|
||||
|
||||
Veja também: `app/src/services/analytics/ACTIVITY_TRACKING.md` para documentação detalhada de integração em atividades.
|
||||
@@ -31,3 +31,12 @@ A aplicação se organiza em quatro camadas práticas:
|
||||
- Atividades de letramento em `app/src/atividades/letramento`.
|
||||
- Componentes compartilhados em `app/src/components`.
|
||||
- Estado compartilhado em `app/src/contexts`.
|
||||
|
||||
## Documentação disponível nesta seção
|
||||
|
||||
- **[Analytics - GA4](analytics.md)** — Sistema de rastreamento de uso com Google Analytics 4
|
||||
- **[Versionamento e Atualizações](versionamento-atualizacoes.md)** — Detecção automática de deploys e recarregamento
|
||||
- **[Camadas do Sistema](camadas-do-sistema.md)** — Organização técnica das camadas
|
||||
- **[Padrões e Conventions](patterns.md)** — Padrões de código e design
|
||||
- **[Otimização de Bundle](otimizacao-bundle.md)** — Estratégias de compressão e carregamento
|
||||
- Outras documentações técnicas da plataforma
|
||||
329
docs/docs/plataforma/arquitetura/versionamento-atualizacoes.md
Normal file
329
docs/docs/plataforma/arquitetura/versionamento-atualizacoes.md
Normal file
@@ -0,0 +1,329 @@
|
||||
---
|
||||
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)
|
||||
@@ -58,5 +58,17 @@ gitGraph
|
||||
checkout develop
|
||||
commit id: "ordenação, offline, segurança"
|
||||
checkout main
|
||||
merge develop id: "1.1.0 — Em desenvolvimento" tag: "v1.1.0"
|
||||
merge develop id: "1.1.0 — Release" tag: "v1.1.0"
|
||||
checkout develop
|
||||
commit id: "analytics, detecção de atualizações"
|
||||
checkout main
|
||||
merge develop id: "1.1.3 — Analytics e atualização" tag: "v1.1.3"
|
||||
```
|
||||
|
||||
## Histórico de Versões
|
||||
|
||||
| Versão | Data | Destaque Principal |
|
||||
|---|---|---|
|
||||
| [**v1.1.3**](v1.1.3.md) | 05/06/2026 | Analytics com Google Analytics 4 e detecção de atualizações automáticas |
|
||||
| [**v1.1.0**](v1.1.0.md) | 14/07/2026 | Atividade de Ordenação, suporte offline (PWA) e segurança XSS |
|
||||
| **v1.0.0** | — | Lançamento inicial da plataforma |
|
||||
|
||||
163
docs/docs/releases/v1.1.3.md
Normal file
163
docs/docs/releases/v1.1.3.md
Normal file
@@ -0,0 +1,163 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "1.1.3"
|
||||
---
|
||||
|
||||
# 1.1.3
|
||||
|
||||
**Data de lançamento:** 05/06/2026
|
||||
|
||||
---
|
||||
|
||||
## Adicionado
|
||||
|
||||
### Analytics - Google Analytics 4 (GA4)
|
||||
|
||||
Integração completa de analytics para rastreamento de uso e experiência dos estudantes:
|
||||
|
||||
- **Rastreamento de páginas** — acompanha quais seções da plataforma são mais visitadas
|
||||
- **Rastreamento de atividades** — identifica quais atividades educacionais são completadas, falhadas ou abandonadas
|
||||
- **Rastreamento de fases** — permite entender em qual fase os estudantes têm dificuldade
|
||||
- **Offline-aware** — não tenta enviar dados quando o estudante está sem conexão
|
||||
- **Configurável** — pode ser habilitado ou desabilitado via variáveis de ambiente
|
||||
|
||||
#### Como usar
|
||||
|
||||
**Development (sem analytics):**
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg VITE_ANALYTICS_PROVIDER=noop app
|
||||
```
|
||||
|
||||
**Production (com GA4):**
|
||||
|
||||
```bash
|
||||
docker compose build \
|
||||
--build-arg VITE_ANALYTICS_PROVIDER=ga4 \
|
||||
--build-arg VITE_GA4_ID=G-SEU_ID_AQUI \
|
||||
--build-arg GIT_COMMIT_HASH=$(git rev-parse --short HEAD) app
|
||||
```
|
||||
|
||||
Veja a [documentação completa de Analytics](../plataforma/arquitetura/analytics.md) para detalhes de integração e relatórios.
|
||||
|
||||
### Detecção Automática de Atualizações
|
||||
|
||||
Script no `index.html` que detecta novos deploys e recarrega automaticamente:
|
||||
|
||||
```javascript
|
||||
(async function checkForUpdates() {
|
||||
const response = await fetch('/version.json');
|
||||
const newVersion = await response.json();
|
||||
const lastVersion = sessionStorage.getItem('app_version');
|
||||
|
||||
if (lastVersion && lastVersion !== newVersion.commit) {
|
||||
console.log('🔄 Novo deploy detectado. Recarregando...');
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
sessionStorage.setItem('app_version', newVersion.commit);
|
||||
})();
|
||||
```
|
||||
|
||||
**Benefícios:**
|
||||
- Usuários recebem novas versões automaticamente
|
||||
- Sem necessidade de limpar cache ou recarregar manual
|
||||
- Transparente — nenhuma intervenção do usuário necessária
|
||||
- Apenas recarrega se houver mudança de versão
|
||||
|
||||
---
|
||||
|
||||
## Melhorias
|
||||
|
||||
### Build Docker Aprimorado
|
||||
|
||||
O `Dockerfile` agora suporta argumentos de build para configurar analytics e versionamento:
|
||||
|
||||
```dockerfile
|
||||
ARG GIT_COMMIT_HASH=unknown
|
||||
ARG APP_VERSION=1.1.3
|
||||
ARG VITE_ANALYTICS_PROVIDER=ga4
|
||||
ARG VITE_GA4_ID=SEU_ID_AQUI
|
||||
ARG VITE_GA4_DEBUG=false
|
||||
```
|
||||
|
||||
Permite builds reproduzíveis e controlados por ambiente.
|
||||
|
||||
---
|
||||
|
||||
## Segurança
|
||||
|
||||
### Conformidade LGPD/GDPR
|
||||
|
||||
- Banner de consentimento antes de qualquer rastreamento
|
||||
- Implementação de Google Consent Mode
|
||||
- Opção clara de rejeitar analytics
|
||||
- Dados anonimizados (anonymize_ip: true)
|
||||
- Política de Privacidade atualizada em `/privacy-policy`
|
||||
|
||||
---
|
||||
|
||||
## Documentação
|
||||
|
||||
Documentação técnica completa adicionada:
|
||||
|
||||
- **[Analytics - GA4](../plataforma/arquitetura/analytics.md)** — Visão geral, arquitetura, build e relatórios
|
||||
- **[Versionamento e Atualizações](../plataforma/arquitetura/versionamento-atualizacoes.md)** — Detecção automática de deploys
|
||||
|
||||
---
|
||||
|
||||
## Notas de Deploy
|
||||
|
||||
### Primeiro Deploy com Analytics
|
||||
|
||||
Ao fazer deploy em produção com GA4:
|
||||
|
||||
1. Configure as variáveis de ambiente:
|
||||
```bash
|
||||
VITE_ANALYTICS_PROVIDER=ga4
|
||||
VITE_GA4_ID=G-SEU_ID_AQUI
|
||||
```
|
||||
|
||||
2. Obtenha o ID do GA4:
|
||||
- Acesse [https://analytics.google.com](https://analytics.google.com)
|
||||
- Vá para `Administração → Data Streams`
|
||||
- Copie o ID de medição (formato: G-XXXXXXXXXX)
|
||||
|
||||
3. Compile com:
|
||||
```bash
|
||||
docker compose build --build-arg VITE_GA4_ID=G-SEU_ID app
|
||||
```
|
||||
|
||||
4. Teste em produção:
|
||||
- Abra a app no browser
|
||||
- Aceite cookies quando o banner aparecer
|
||||
- Abra DevTools → Network
|
||||
- Procure por requisições para `googletagmanager.com`
|
||||
- Verifique `Relatórios → Em tempo real` no GA4
|
||||
|
||||
### Se optar por não usar Analytics
|
||||
|
||||
Para desabilitar analytics em qualquer ambiente:
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg VITE_ANALYTICS_PROVIDER=noop app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Changelog Completo
|
||||
|
||||
**Adicionado:**
|
||||
- ✨ Analytics com Google Analytics 4 (mas preparado para uso de outras ferramentas no futuro como Umami)
|
||||
- ✨ Detecção automática de atualizações no `index.html`
|
||||
- ✨ Documentação de Analytics e build Docker
|
||||
- ✨ Hooks de rastreamento: `usePageTracking`, `useActivityTracking`, `useLetramentoTracking`
|
||||
|
||||
**Melhorado:**
|
||||
- 🔧 Build Docker com suporte a argumentos de GA4
|
||||
- 🔧 Versionamento integrado (`version.json`)
|
||||
- 📚 Documentação técnica expandida
|
||||
|
||||
**Segurança:**
|
||||
- 🔒 Implementação de Google Consent Mode
|
||||
- 🔒 Anonimização de IPs em GA4
|
||||
Reference in New Issue
Block a user