Skip to content

schulzdimitrii-study/tcc-backend

Repository files navigation

🏃 Bio Survival — Backend API

Backend REST API do aplicativo fitness Bio Survival, desenvolvido como Trabalho de Conclusão de Curso (TCC) no Inatel. A aplicação oferece autenticação JWT, sessões de treino em tempo real via WebSocket, dados biométricos, conquistas, rankings com cache Redis e sistema gamificado de Hordes.


📋 Índice


🎯 Sobre o Projeto

Bio Survival é um aplicativo fitness que transforma treinos em uma experiência gamificada. Os usuários podem registrar sessões de corrida, monitorar dados biométricos em tempo real (BPM, cadência, pace, calorias), desbloquear conquistas e competir em rankings globais.

Este repositório contém exclusivamente o backend, responsável por:

  • 🔐 Autenticação e autorização via JWT (JSON Web Tokens)
  • 🏃 Gerenciamento de sessões de treino e dados biométricos em tempo real via WebSocket STOMP
  • 🏆 Sistema de conquistas e rankings com cache Redis
  • 👥 Sistema de amizades entre usuários
  • 👾 Gestão de Hordes (desafios gamificados de corrida com horda virtual)
  • 💓 Monitoramento de zona cardíaca em tempo real
  • 📊 Leaderboard em tempo real com broadcast via WebSocket

🛠 Tecnologias

Tecnologia Versão Uso
Kotlin 2.1.20 Linguagem principal
Spring Boot 3.4.4 Framework web
Spring Security Autenticação e autorização
Spring Data JPA Persistência de dados
Spring WebSocket Comunicação em tempo real (STOMP)
Spring Data Redis Cache e leaderboards em tempo real
PostgreSQL 17 Banco de dados relacional
Redis 7 Cache de sessões e leaderboards
Flyway Migrations de banco de dados
SpringDoc OpenAPI 2.8.5 Documentação Swagger/OpenAPI
JJWT 0.12.6 Geração e validação de tokens JWT
BCrypt Hash de senhas
Docker Containerização (multi-stage build)
Jenkins CI/CD Pipeline
JaCoCo 0.8.13 Cobertura de testes
Maven Gerenciador de dependências
JUnit 5 + Mockito Testes unitários
H2 Banco de dados em memória para testes

🏛 Arquitetura

O projeto segue a arquitetura em camadas do Spring Boot com comunicação em tempo real via WebSocket e cache Redis:

Architecture Diagram

Fluxo de Autenticação

1. Client → POST /auth/register ou /auth/login
2. AuthController → AuthService (valida dados)
3. AuthService → UserRepository (busca/salva usuário)
4. AuthService → JwtService (gera token JWT)
5. Resposta: { token, name, email }

Para rotas protegidas:
1. Client → Header: Authorization: Bearer <token>
2. JwtAuthFilter → JwtService (valida token)
3. Request passa para o Controller

Fluxo de Biometria em Tempo Real

1. Galaxy Watch → dados de sensores via Wear OS Data Layer API (Bluetooth)
2. App React Native → WebSocket STOMP: /app/train/data (BiometricDataMessage)
3. BiometricWebSocketController:
   a. Persiste no PostgreSQL de forma assíncrona
   b. Calcula zona cardíaca (cache Redis)
   c. Atualiza estado do jogador no Redis (< 1ms por operação)
   d. Atualiza leaderboard no Redis (Sorted Set)
   e. Calcula posição virtual da horda
   f. Broadcast leaderboard → /topic/session/{id}/leaderboard
   g. Broadcast game state → /topic/session/{id}/game-state

🗄 Modelo de Dados

users
 ├── id (UUID, PK)
 ├── email (VARCHAR, UNIQUE)
 ├── name (VARCHAR)
 ├── password (VARCHAR, bcrypt)
 ├── birthday_date (DATE)
 ├── height (DOUBLE)
 ├── weight (DOUBLE)
 └── max_heart_rate (INT)

achievements          hordes (self-ref)
 ├── id (UUID)         ├── id (UUID)
 ├── title             ├── name
 ├── description       ├── description
 ├── url_icon          ├── difficulty (EASY/MEDIUM/HARD)
 ├── criterion         ├── estimated_duration
 └── active            ├── target_pace
                       ├── adaptive (BOOLEAN)
                       └── horde_id (FK → hordes)

train_sessions                    biometric_data
 ├── id (UUID)                     ├── id (UUID)
 ├── user_id (FK → users)          ├── timestamp
 ├── start_date                    ├── bpm
 ├── end_date                      ├── cadence
 ├── train_type                    ├── speed
 ├── total_distance                ├── pace
 ├── estimated_calories            ├── accumulated_distance
 └── horde_id (FK → hordes)        ├── accumulated_calories
                                   ├── cardiac_zone
                                   └── train_session_id (FK)

user_achievements         rankings                  friendships
 ├── user_id (FK)          ├── id (UUID)              ├── id (UUID)
 ├── achievement_id (FK)   ├── user_id (FK)           ├── requester_id (FK)
 └── unlock_date           ├── position               ├── recipient_id (FK)
                           ├── score                  ├── request_date
                           ├── period                 ├── response_date
                           ├── calcule_date           └── status
                           └── target_distance

📡 Endpoints da API

Documentação interativa disponível em: http://134.122.112.15:8080/swagger-ui/index.html

Autenticação

Rotas públicas — não requerem token JWT.

Método Endpoint Descrição
POST /auth/register Cria uma nova conta de usuário
POST /auth/login Autentica um usuário existente

POST /auth/register

Request Body:

{
  "email": "usuario@exemplo.com",
  "name": "João Silva",
  "password": "minhasenha123",
  "birthdayDate": "2000-05-15",
  "height": 1.80,
  "weight": 75.5
}

Response 201 Created:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "name": "João Silva",
  "email": "usuario@exemplo.com"
}

POST /auth/login

Request Body:

{
  "email": "usuario@exemplo.com",
  "password": "minhasenha123"
}

Response 200 OK:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "name": "João Silva",
  "email": "usuario@exemplo.com"
}

Usuários

Rotas protegidas — requerem Authorization: Bearer <token>

Método Endpoint Descrição
GET /users/{id} Retorna os dados de um usuário
PATCH /users/{id} Atualiza parcialmente um usuário

Sessões de Treino

Método Endpoint Descrição
POST /sessions/start Inicia uma nova sessão de treino
POST /sessions/{sessionId}/finish Finaliza uma sessão
GET /sessions/{sessionId} Retorna os dados de uma sessão
GET /sessions/{sessionId}/leaderboard Retorna o leaderboard da sessão
GET /sessions/hordes Lista todas as hordes disponíveis
GET /sessions/ranking/{period} Retorna o ranking global por período

POST /sessions/start

Request Body:

{
  "hordeId": "uuid-optional",
  "trainType": "RUN",
  "goalDistanceKm": 5.0
}

Response 201 Created:

{
  "sessionId": "uuid-da-sessao"
}

Rankings

Método Endpoint Descrição
GET /rankings/{period} Rankings históricos por período (WEEKLY, MONTHLY)
GET /rankings/user/{userId} Rankings históricos de um usuário

Respostas de Erro Padronizadas

Status Cenário
400 Bad Request Campos inválidos ou ausentes
401 Unauthorized Token ausente, inválido ou expirado
404 Not Found Recurso não encontrado
409 Conflict Email já cadastrado
500 Internal Server Error Erro interno do servidor

🔌 WebSocket — Biometria em Tempo Real

A comunicação de biometria durante as sessões de treino é feita via WebSocket STOMP.

Conexão

ws://host:8080/ws

Canal de Entrada

Destino: /app/train/data

Payload (BiometricDataMessage):

{
  "sessionId": "uuid-da-sessao",
  "userId": "uuid-do-usuario",
  "timestamp": 1717970400000,
  "bpm": 142,
  "cadence": 85.5,
  "speed": 10.2,
  "pace": 5.88,
  "accumulatedDistance": 2.35,
  "accumulatedCalories": 180.5
}

Canais de Saída (Broadcast)

Leaderboard: /topic/session/{sessionId}/leaderboard

{
  "sessionId": "uuid",
  "userRank": 2,
  "hordeVirtualDistanceKm": 1.8,
  "entries": [
    { "userId": "uuid", "rank": 1, "distanceKm": 2.5, "cardiacZone": "VIGOROUS" }
  ],
  "isBehindHorde": false,
  "distanceToHorde": -0.55
}

Game State: /topic/session/{sessionId}/game-state

{
  "sessionId": "uuid",
  "userId": "uuid",
  "playerPosition": 2.35,
  "hordePosition": 1.80,
  "distanceToGoal": 2.65,
  "distancePlayerToHorde": 0.55,
  "playerSpeed": 10.2,
  "hordeSpeed": 8.5,
  "raceProgress": 47.0,
  "gameStatus": "RUNNING",
  "serverTimestampMs": 1717970400000
}

Game Status: RUNNING | CAUGHT (horde alcançou o jogador) | ESCAPED (jogador completou a meta)

Unidades do Game State: playerPosition, hordePosition, distanceToGoal e distancePlayerToHorde usam quilometros; playerSpeed e hordeSpeed usam km/h; raceProgress e percentual no intervalo 0.0..100.0; serverTimestampMs usa epoch ms gerado pelo backend.


✅ Pré-requisitos

Certifique-se de ter instalado:

  • Java 25+ (JDK)
  • Maven 3.8+
  • PostgreSQL 17+
  • Redis 7+
  • Docker & Docker Compose (opcional, para execução containerizada)

🚀 Configuração e Execução

Opção 1: Docker Compose (recomendado)

git clone https://github.com/seu-usuario/tcc.git
cd tcc
./mvnw clean package -DskipTests
docker-compose up -d

A stack completa será iniciada: API + PostgreSQL + Redis + Jenkins + Ngrok.

Opção 2: Execução Local

1. Clone o repositório

git clone https://github.com/seu-usuario/tcc.git
cd tcc

2. Configure o banco de dados

CREATE DATABASE tcc;
CREATE USER seu_usuario WITH ENCRYPTED PASSWORD 'sua_senha';
GRANT ALL PRIVILEGES ON DATABASE tcc TO seu_usuario;

3. Inicie o Redis

docker run -d --name redis -p 6379:6379 redis:7-alpine

4. Configure as variáveis de ambiente

Edite src/main/resources/application.properties ou defina as variáveis de ambiente (veja a seção Variáveis de Ambiente).

5. Inicie a aplicação

./mvnw spring-boot:run

A API estará disponível em: http://localhost:8080

A documentação Swagger: http://localhost:8080/swagger-ui.html


🔄 CI/CD Pipeline

O projeto utiliza Jenkins com pipeline declarativo e notificação por email.

GitHub Push → Jenkins (webhook via Ngrok)
  ├── 1. Build        → mvnw clean install -DskipTests
  ├── 2. Tests        → mvnw clean verify (JaCoCo coverage)
  └── 3. Deploy       → SCP JAR + SSH docker-compose up (DigitalOcean Droplet)
                      → Email notification (sucesso/falha)

O Jenkins roda como container Docker dentro do docker-compose.yml, com o Ngrok expondo o webhook para o GitHub.


🧪 Testes

O projeto possui 30 arquivos de teste cobrindo todas as camadas. Redis em container temporário é usado nos testes de integração e H2 como banco em memória.

Executar todos os testes

./mvnw clean verify

Desenvolvido por Dimitri, José, Pedro Augusto, Pedro Bressan — Inatel © 2026

Releases

No releases published

Packages

 
 
 

Contributors