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
|
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
|
### 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_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
|
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_ID=$VITE_GA4_ID
|
||||||
ENV VITE_GA4_DEBUG=$VITE_GA4_DEBUG
|
ENV VITE_GA4_DEBUG=$VITE_GA4_DEBUG
|
||||||
|
|
||||||
RUN npm install -g pnpm
|
|
||||||
|
|
||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
RUN pnpm install
|
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json
|
RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json && \
|
||||||
|
pnpm run build && \
|
||||||
RUN pnpm run build
|
rm -rf node_modules .pnpm-store
|
||||||
|
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
COPY nginx-spa.conf /etc/nginx/conf.d/default.conf
|
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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<title>Decoda</title>
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ import LabPython from "./pages/LabPython/LabPython";
|
|||||||
import ScrollToTop from "./components/ScrollToTop";
|
import ScrollToTop from "./components/ScrollToTop";
|
||||||
import { getAnalytics, usePageTracking } from "./services/analytics";
|
import { getAnalytics, usePageTracking } from "./services/analytics";
|
||||||
import { initializeAnalytics, analyticsConfig } from "./services/analytics";
|
import { initializeAnalytics, analyticsConfig } from "./services/analytics";
|
||||||
import { ConsentManager } from "./services/consent";
|
|
||||||
|
|
||||||
// Inline CookieBanner para evitar bloqueio do Brave
|
// Inline CookieBanner para evitar bloqueio do Brave
|
||||||
function CookieBanner() {
|
function CookieBanner() {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const enableBanner = import.meta.env.VITE_ENABLE_CONSENT_BANNER === 'true';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!enableBanner) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stored = localStorage.getItem('decoda_consent');
|
const stored = localStorage.getItem('decoda_consent');
|
||||||
if (!stored) {
|
if (!stored) {
|
||||||
@@ -27,7 +29,7 @@ function CookieBanner() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Consent check failed:', e);
|
console.error('Consent check failed:', e);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [enableBanner]);
|
||||||
|
|
||||||
const handleAccept = () => {
|
const handleAccept = () => {
|
||||||
try {
|
try {
|
||||||
@@ -57,7 +59,7 @@ function CookieBanner() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!visible) return null;
|
if (!visible || !enableBanner) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-0 left-0 right-0 z-50 p-4 md:p-6" role="dialog" aria-label="Consentimento de cookies">
|
<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);
|
const [analyticsReady, setAnalyticsReady] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hasConsent = ConsentManager.hasConsent();
|
|
||||||
initializeAnalytics({
|
initializeAnalytics({
|
||||||
providerType: analyticsConfig.providerType,
|
providerType: analyticsConfig.providerType,
|
||||||
measurementId: analyticsConfig.measurementId,
|
measurementId: analyticsConfig.measurementId,
|
||||||
hasConsent,
|
hasConsent: true,
|
||||||
debugMode: analyticsConfig.debugMode,
|
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`.
|
- Atividades de letramento em `app/src/atividades/letramento`.
|
||||||
- Componentes compartilhados em `app/src/components`.
|
- Componentes compartilhados em `app/src/components`.
|
||||||
- Estado compartilhado em `app/src/contexts`.
|
- 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
|
checkout develop
|
||||||
commit id: "ordenação, offline, segurança"
|
commit id: "ordenação, offline, segurança"
|
||||||
checkout main
|
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