Serviço responsável pelo gerenciamento de ciclos Pomodoro, persistência de dados e estatísticas de produtividade para o PomoCube IoT
⏱️ API RESTful do ecossistema PomoCube, responsável pelo gerenciamento de ciclos Pomodoro, persistência de dados e estatísticas de produtividade.
- Sobre
- Tecnologias
- Arquitetura e Segurança
- Configuração do Ambiente
- Variáveis de Ambiente
- Endpoints da API
- Formato de Erros
- CORS
O backend do PomoCube é uma API RESTful construída com Java Spring Boot e MongoDB Atlas, projetada para receber, armazenar e consultar sessões de estudo enviadas pelo dispositivo físico PomoCube (Raspberry Pi Pico W). Além do registro de sessões, a API oferece um conjunto de endpoints de dashboard com métricas e estatísticas de produtividade prontas para visualização no frontend.
- Java + Spring Boot — Framework principal da API
- MongoDB Atlas — Banco de dados NoSQL na nuvem
- Spring Security — Autenticação via API Key
- Spring Data MongoDB — Integração com MongoDB
- Spring Validation — Validação de dados de entrada
- Render — Plataforma de deploy em produção
Essa é uma abordagem muito sensata e alinhada com o princípio YAGNI (You Ain't Gonna Need It). Para um projeto pessoal e de usuário único, introduzir toda a infraestrutura de um Identity Provider ou a complexidade de expiração/refresh de tokens JWT muitas vezes traz mais "ruído" do que benefício real.
Aqui está uma sugestão de como estruturar essa justificativa de forma profissional e técnica para o seu README ou documentação:
A escolha do método de autenticação priorizou o equilíbrio entre segurança e simplicidade operacional.
Optei por utilizar autenticação via header customizado X-API-KEY em vez de padrões mais complexos (como JWT ou OAuth2) devido à natureza do sistema: por ser um projeto de uso pessoal (usuário único), a implementação de fluxos de token refresh ou integração com provedores de identidade aumentaria a complexidade do código sem oferecer um ganho proporcional de segurança para este caso de uso específico.
Com o uso de chaves estáticas protegidas, consigo garantir:
- Baixo Overhead: Sem necessidade de parsing complexo de tokens em cada requisição.
- Segurança Eficiente: As chaves são tratadas como segredos de ambiente, mantendo a API protegida contra acessos não autorizados.
- Segregação de Funções: Mesmo com chaves simples, o sistema implementa RBAC (Role-Based Access Control) para limitar o que cada cliente pode fazer.
A autenticação é obrigatória em todas as requisições. O sistema diferencia a origem através de duas chaves distintas:
| Chave | Role | Escopo de Permissões |
|---|---|---|
DEVICE_API_KEY |
ROLE_DEVICE |
Escrita (POST /sessions) e leitura geral (GET). |
FRONTEND_API_KEY |
ROLE_FRONTEND |
Leitura restrita aos endpoints de visualização (/sessions, /dashboard). |
| Status | Situação |
|---|---|
401 |
Header X-API-KEY ausente ou chave inválida |
403 |
Chave sem permissão para o endpoint acessado |
- Java 17+
- Maven ou Gradle
- Conta no MongoDB Atlas (ou instância local)
git clone https://github.com/ClarkAshida/pomodoro-api
cd pomodoro-apiCrie um arquivo .env ou configure as variáveis diretamente no ambiente (veja a seção abaixo).
# Maven
./mvnw spring-boot:run
A API estará disponível em: http://localhost:8080
| Variável | Default (dev) | Descrição |
|---|---|---|
SPRING_DATA_MONGODB_URI |
— | URI de conexão com o MongoDB Atlas |
DEVICE_API_KEY |
pomodoro-pico-w-secret-key-2025 |
Chave de autenticação do dispositivo |
FRONTEND_API_KEY |
pomodoro-frontend-secret-key-2025 |
Chave de autenticação do frontend |
CORS_ALLOWED_ORIGINS |
http://localhost:3000 |
Origins permitidas (separadas por vírgula) |
X-API-KEY: <sua-api-key>
Registra uma nova sessão de estudo.
Permissão: ROLE_DEVICE
curl -X POST http://localhost:8080/sessions \
-H "X-API-KEY: <DEVICE_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-02-27",
"startTime": "14:30:00",
"targetCycles": 4,
"completedCycles": 4,
"totalFocusMinutes": 100,
"totalBreakMinutes": 10,
"category": "TECHNOLOGY"
}'Campos do body:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
date |
string |
✅ | Data da sessão (YYYY-MM-DD) |
startTime |
string |
✅ | Hora de início (HH:MM:SS) |
targetCycles |
integer |
✅ | Meta de ciclos (mínimo 1) |
completedCycles |
integer |
✅ | Ciclos concluídos (mínimo 0) |
totalFocusMinutes |
integer |
✅ | Minutos em foco (mínimo 0) |
totalBreakMinutes |
integer |
✅ | Minutos em pausa (mínimo 0) |
category |
string |
✅ | TECHNOLOGY, MATH, PORTUGUESE, ENGLISH, OTHER |
Os campos
dayOfWeek,successeperiodsão calculados automaticamente pela API e retornados na resposta.
Resposta 201 Created:
{
"id": "67c0a1b2e4f5a6b7c8d9e0f1",
"date": "2026-02-27",
"dayOfWeek": "FRIDAY",
"startTime": "14:30:00",
"period": "AFTERNOON",
"category": "TECHNOLOGY",
"targetCycles": 4,
"completedCycles": 4,
"success": true,
"totalFocusMinutes": 100,
"totalBreakMinutes": 10
}Lista sessões de forma paginada com suporte a filtros e ordenação.
Permissão: ROLE_DEVICE ou ROLE_FRONTEND
Query Parameters:
| Parâmetro | Default | Descrição |
|---|---|---|
page |
0 |
Número da página |
size |
10 |
Itens por página |
sortBy |
date |
Campo para ordenação |
sortDir |
desc |
asc ou desc |
startDate |
— | Filtro de data inicial (YYYY-MM-DD) |
endDate |
— | Filtro de data final (YYYY-MM-DD) |
period |
— | MORNING, AFTERNOON ou NIGHT |
category |
— | TECHNOLOGY, MATH, PORTUGUESE, ENGLISH, OTHER |
success |
— | true ou false |
Busca uma sessão pelo ID.
Permissão: ROLE_DEVICE ou ROLE_FRONTEND
Todos os endpoints de dashboard requerem ROLE_DEVICE ou ROLE_FRONTEND.
Resumo geral: totais, médias e streak atual.
{
"totalSessions": 42,
"successfulSessions": 30,
"successRate": 71.43,
"totalFocusMinutes": 2100,
"averageCompletedCycles": 3.75,
"averageFocusMinutes": 50.0,
"currentStreak": 7
}Dados agrupados por período para gráficos de linha/barra.
Query Parameters: period (week | month | year | all), startDate, endDate
Distribuição de minutos e sessões por categoria (gráfico de pizza/donut).
Query Parameters: period, startDate, endDate
Atividade diária do ano inteiro, estilo GitHub contribution graph.
Query Parameters: year (default: ano atual)
Estatísticas agrupadas por período do dia (manhã, tarde, noite).
Estatísticas agrupadas por dia da semana (MONDAY → SUNDAY).
Métricas de progresso no período: dias ativos, médias e taxa de sucesso.
Query Parameters: period, startDate, endDate
| Método | Endpoint | Role necessária | Descrição |
|---|---|---|---|
POST |
/sessions |
DEVICE |
Registra nova sessão |
GET |
/sessions |
DEVICE ou FRONTEND |
Lista sessões paginadas |
GET |
/sessions/{id} |
DEVICE ou FRONTEND |
Busca sessão por ID |
GET |
/dashboard/summary |
DEVICE ou FRONTEND |
Resumo geral + streak |
GET |
/dashboard/overview |
DEVICE ou FRONTEND |
Dados por período (gráfico) |
GET |
/dashboard/by-category |
DEVICE ou FRONTEND |
Distribuição por categoria |
GET |
/dashboard/heatmap |
DEVICE ou FRONTEND |
Heatmap de atividade anual |
GET |
/dashboard/by-period |
DEVICE ou FRONTEND |
Stats por manhã/tarde/noite |
GET |
/dashboard/by-weekday |
DEVICE ou FRONTEND |
Stats por dia da semana |
GET |
/dashboard/goals |
DEVICE ou FRONTEND |
Metas e progresso no período |
Todos os erros seguem o padrão:
{
"status": 400,
"error": "Bad Request",
"message": "Descrição do erro",
"path": "/endpoint",
"timestamp": "2026-02-27T14:30:00"
}Erros de validação incluem o campo adicional fieldErrors:
{
"status": 400,
"error": "Validation Failed",
"message": "One or more fields have invalid values",
"fieldErrors": [
{
"field": "targetCycles",
"rejectedValue": 0,
"message": "targetCycles must be at least 1"
}
]
}| Status | Situação |
|---|---|
201 |
Sessão criada com sucesso |
200 |
Requisição GET bem-sucedida |
400 |
Dados inválidos / parâmetros incorretos |
401 |
API Key ausente ou inválida |
403 |
Chave sem permissão para o endpoint |
404 |
Sessão não encontrada |
500 |
Erro interno inesperado |
Para adicionar o frontend em produção, configure a variável de ambiente:
CORS_ALLOWED_ORIGINS=http://localhost:3000,https://seu-frontend.vercel.appParte do ecossistema PomoCube IoT 🍅