Arquitetura do Sistema
Visão técnica completa da arquitetura de microsserviços para o sistema de gamificação.
🏗️ Visão Geral da Arquitetura
🎮 Serviço de Gamificação (Core)
Responsabilidades
- Cálculo de pontuações em tempo real
- Gerenciamento de níveis e badges
- Manutenção de rankings
- Processamento de desafios e missões
- Sistema anti-fraude
Tecnologias
- Backend: Node.js/TypeScript ou Go
- Framework: Express.js ou Gin
- Cache: Redis para rankings em tempo real
- Queue: Kafka para processamento assíncrono
APIs Principais
Endpoint de Pontuação
// POST /api/v1/gamification/points
interface AddPointsRequest {
usuario_id: string;
acao: string;
chamado_id?: string;
valor_customizado?: number;
metadata?: Record<string, any>;
}
interface AddPointsResponse {
pontos_adicionados: number;
pontos_total: number;
nivel_atual: string;
subiu_nivel: boolean;
badges_conquistados: string[];
posicao_ranking_local: number;
posicao_ranking_nacional: number;
}
Endpoint de Rankings
// GET /api/v1/gamification/rankings
interface RankingParams {
tipo: "local" | "nacional" | "categoria";
cidade?: string;
categoria?: string;
periodo: "semanal" | "mensal" | "anual";
limit?: number;
offset?: number;
}
interface RankingResponse {
rankings: Array<{
posicao: number;
usuario_id: string;
nome: string;
pontos: number;
cidade: string;
nivel: string;
badges: string[];
variacao: number; // +/- em relação ao período anterior
}>;
total: number;
periodo: string;
ultima_atualizacao: string;
}
🗄️ Modelo de Dados
Esquema Principal (PostgreSQL)
-- Usuários
CREATE TABLE usuarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
nome VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
telefone VARCHAR(20),
cidade VARCHAR(100) NOT NULL,
estado CHAR(2) NOT NULL,
tier_cidade INTEGER NOT NULL DEFAULT 5,
pontos_total INTEGER DEFAULT 0,
nivel ENUM('Iniciante', 'Experiente', 'Expert', 'Master Tech', 'Legend') DEFAULT 'Iniciante',
data_cadastro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ultima_atividade TIMESTAMP,
ativo BOOLEAN DEFAULT true,
-- Índices para performance
INDEX idx_cidade_ativo (cidade, ativo),
INDEX idx_pontos_nivel (pontos_total, nivel),
INDEX idx_tier_estado (tier_cidade, estado)
);
-- Configuração de Tiers por Cidade
CREATE TABLE cidade_tiers (
id SERIAL PRIMARY KEY,
cidade VARCHAR(100) NOT NULL,
estado CHAR(2) NOT NULL,
tier INTEGER NOT NULL CHECK (tier >= 1 AND tier <= 5),
multiplicador DECIMAL(3,2) NOT NULL,
chamados_3m INTEGER DEFAULT 0,
tecnicos_ativos INTEGER DEFAULT 0,
populacao INTEGER,
ultima_atualizacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(cidade, estado),
INDEX idx_tier_multiplicador (tier, multiplicador)
);
-- Histórico de Pontuações
CREATE TABLE pontuacoes (
id BIGSERIAL PRIMARY KEY,
usuario_id UUID NOT NULL REFERENCES usuarios(id),
acao VARCHAR(50) NOT NULL,
pontos_base INTEGER NOT NULL,
multiplicador_tier DECIMAL(3,2) NOT NULL,
multiplicador_densidade DECIMAL(3,2) DEFAULT 1.0,
multiplicador_nivel DECIMAL(3,2) DEFAULT 1.0,
pontos_final INTEGER NOT NULL,
chamado_id UUID,
cidade VARCHAR(100),
metadata JSONB,
data_acao TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- Índices para queries frequentes
INDEX idx_usuario_data (usuario_id, data_acao),
INDEX idx_acao_cidade (acao, cidade),
INDEX idx_data_acao (data_acao),
INDEX idx_chamado (chamado_id)
);
-- Badges dos Usuários
CREATE TABLE usuario_badges (
id BIGSERIAL PRIMARY KEY,
usuario_id UUID NOT NULL REFERENCES usuarios(id),
badge_nome VARCHAR(50) NOT NULL,
badge_categoria VARCHAR(30),
data_conquista TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata JSONB,
UNIQUE(usuario_id, badge_nome),
INDEX idx_usuario_categoria (usuario_id, badge_categoria)
);
-- Rankings (Cache em tabela para performance)
CREATE TABLE rankings_cache (
id BIGSERIAL PRIMARY KEY,
usuario_id UUID NOT NULL REFERENCES usuarios(id),
tipo_ranking VARCHAR(20) NOT NULL, -- 'local', 'nacional', 'categoria'
categoria VARCHAR(50),
cidade VARCHAR(100),
estado CHAR(2),
posicao INTEGER NOT NULL,
pontos INTEGER NOT NULL,
posicao_anterior INTEGER,
periodo_inicio DATE NOT NULL,
periodo_fim DATE NOT NULL,
data_calculo TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- Índices para diferentes tipos de consulta
INDEX idx_tipo_categoria_periodo (tipo_ranking, categoria, periodo_inicio, periodo_fim),
INDEX idx_cidade_posicao (cidade, posicao),
INDEX idx_usuario_tipo (usuario_id, tipo_ranking)
);
-- Desafios e Missões
CREATE TABLE desafios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
nome VARCHAR(100) NOT NULL,
descricao TEXT,
tipo VARCHAR(30), -- 'individual', 'coletivo', 'regional'
tier_minimo INTEGER DEFAULT 1,
tier_maximo INTEGER DEFAULT 5,
meta_valor INTEGER NOT NULL,
meta_tipo VARCHAR(30), -- 'chamados', 'pontos', 'avaliacoes'
recompensa_pontos INTEGER,
recompensa_badge VARCHAR(50),
data_inicio DATE NOT NULL,
data_fim DATE NOT NULL,
ativo BOOLEAN DEFAULT true,
INDEX idx_periodo_ativo (data_inicio, data_fim, ativo),
INDEX idx_tier_tipo (tier_minimo, tier_maximo, tipo)
);
-- Progresso dos Usuários nos Desafios
CREATE TABLE usuario_desafios (
id BIGSERIAL PRIMARY KEY,
usuario_id UUID NOT NULL REFERENCES usuarios(id),
desafio_id UUID NOT NULL REFERENCES desafios(id),
progresso_atual INTEGER DEFAULT 0,
meta_valor INTEGER NOT NULL,
concluido BOOLEAN DEFAULT false,
data_inicio TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_conclusao TIMESTAMP,
UNIQUE(usuario_id, desafio_id),
INDEX idx_usuario_concluido (usuario_id, concluido),
INDEX idx_desafio_progresso (desafio_id, progresso_atual)
);
Cache Strategy (Redis)
// Estrutura de cache no Redis
interface CacheStructure {
// Rankings em tempo real
"ranking:local:{cidade}:mensal": ZSet; // Score = pontos
"ranking:nacional:mensal": ZSet;
"ranking:categoria:{categoria}:mensal": ZSet;
// Cache de usuário
"user:{userId}:stats": {
pontos_total: number;
nivel: string;
posicao_local: number;
posicao_nacional: number;
badges_count: number;
ultima_atualizacao: string;
};
// Cache de tiers
"tiers:cache": Map<
string,
{
tier: number;
multiplicador: number;
ultima_atualizacao: string;
}
>;
// Leaderboards temporários
"temp:ranking:{periodo}:{tipo}": ZSet;
// Rate limiting
"rate_limit:{userId}:{acao}": number; // TTL baseado
}
🔄 Fluxo de Processamento de Pontos
📊 Sistema de Analytics (MongoDB)
// Esquema de eventos no MongoDB
{
"_id": ObjectId,
"event_type": "points_added",
"user_id": "uuid",
"timestamp": ISODate,
"data": {
"acao": "checkin_pontual",
"pontos_base": 10,
"multiplicadores": {
"tier": 1.5,
"densidade": 1.2,
"nivel": 1.05
},
"pontos_final": 19,
"cidade": "Recife",
"tier": 2,
"chamado_id": "uuid"
},
"metadata": {
"ip": "192.168.1.1",
"user_agent": "mobile_app_v1.2.3",
"geolocation": {
"lat": -8.0476,
"lng": -34.8770
}
}
}
// Agregações para relatórios
db.events.aggregate([
{
$match: {
"event_type": "points_added",
"timestamp": {
$gte: ISODate("2025-01-01"),
$lt: ISODate("2025-02-01")
}
}
},
{
$group: {
"_id": "$data.cidade",
"total_pontos": { $sum: "$data.pontos_final" },
"total_eventos": { $sum: 1 },
"usuarios_unicos": { $addToSet: "$user_id" }
}
},
{
$project: {
"cidade": "$_id",
"total_pontos": 1,
"total_eventos": 1,
"usuarios_ativos": { $size: "$usuarios_unicos" },
"media_pontos_usuario": {
$divide: ["$total_pontos", { $size: "$usuarios_unicos" }]
}
}
}
]);
🚀 Deployment e DevOps
Containerização (Docker)
# Dockerfile para Gamification Service
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: gamification-service
spec:
replicas: 3
selector:
matchLabels:
app: gamification-service
template:
metadata:
labels:
app: gamification-service
spec:
containers:
- name: gamification
image: gamification-service:latest
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: redis-secret
key: url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
CI/CD Pipeline (GitHub Actions)
name: Deploy Gamification Service
on:
push:
branches: [main]
paths: ["services/gamification/**"]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm test
- run: npm run lint
build-and-deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t gamification-service:${{ github.sha }} .
- name: Push to registry
run: |
docker tag gamification-service:${{ github.sha }} $ECR_REGISTRY/gamification-service:${{ github.sha }}
docker push $ECR_REGISTRY/gamification-service:${{ github.sha }}
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/gamification-service \
gamification=$ECR_REGISTRY/gamification-service:${{ github.sha }}
💡 Dica: Para mais detalhes sobre o modelo de banco de dados, consulte a documentação técnica da API ou entre em contato com a equipe de desenvolvimento.