API REST em ASP.NET Core 10 para fichas de treino, sessões e acompanhamento de constância. O MoveUp compartilha este back-end com o aplicativo Flutter, que também funciona com armazenamento local no celular.
Este repositório contém o serviço HTTP e seu banco SQLite no servidor. Ele oferece catálogo e fichas de exercícios, registro de séries e histórico de sessões, calendário e métricas de consistência. Entity Framework Core e migrations mantêm o esquema do banco versionado. Os dados registrados são preservados como snapshots para que mudanças futuras em uma ficha não alterem o histórico do atleta.
O serviço destina-se a desenvolvimento e uso local neste estágio. Ele ainda não implementa contas, autenticação ou separação dos dados por usuário. O app usa SQLite local por padrão; conectar o app a esta API é opcional. Consulte o Front-end para o aplicativo e sua arquitetura e modos de armazenamento.
Requisitos: .NET 10 SDK. Na raiz do projeto:
cp .env.example .env # Na primeira configuração
./scripts/run-local.shA API atende em http://localhost:5013. A inicialização aplica migrations
pendentes e insere o catálogo inicial quando necessário. Verifique o serviço em
/health; em Development, consulte o contrato OpenAPI em /openapi/v1.json.
Os detalhes de conexão do aplicativo estão na seção Executar.
.enve bancos locais não pertencem ao repositório. O.env.examplecontém somente configurações de exemplo; mantenha segredos no ambiente privado.
MoveUp Flutter → API REST → Controllers → Services → Repositories → SQLite
As entidades Treino, Exercicio e TreinoExercicio compõem o catálogo e as
fichas. Sessões mantêm uma cópia independente do treino feito; os serviços
coordenam validação e transações, e os repositórios acessam SQLite.
- API para consultar, criar, editar e excluir fichas e exercícios.
- Sessões idempotentes, registro de séries, pausa, retomada e histórico paginado.
- Calendário, rotina, dias planejados, fuso horário e métricas de consistência.
- Migrations incrementais e regras de integridade com SQLite.
- Testes de integração com banco isolado e SQLite real.
Flutter → ApiWorkoutGateway → Controllers → Services → Repositories → SQLite.
O SQLite fica na máquina da API, em App_Data/moveup.db. O modo remoto do app precisa de
conexão com a API. O Flutter usa Drift/SQLite no aparelho por padrão, com
backup e importação da API; veja a arquitetura local do app. Este projeto
continua sendo o armazenamento do servidor. A API é de uso local/de desenvolvimento,
sem autenticação ou separação de dados por usuário nesta fase.
Na pasta MoveUp:
cp .env.example .env # Apenas na primeira configuração
./scripts/run-local.shA API atende em http://localhost:5013. A inicialização aplica as migrations pendentes, cria o banco e insere os
12 exercícios do catálogo inicial quando necessário. Inicializações seguintes
não duplicam nem sobrescrevem o catálogo. Alterações futuras de esquema devem
usar novas migrations, sem apagar o banco.
Para configurar o arquivo, use Database__Path=/caminho/moveup.db no ambiente.
O caminho relativo é resolvido a partir da pasta do projeto. O arquivo antigo
fitnessapp.db, se existir na pasta local do sistema, não é alterado ou importado
automaticamente. Este projeto usa um novo banco versionado por migrations;
bancos antigos criados com EnsureCreated precisam de migração de dados planejada.
No projeto Flutter:
flutter run -d chrome --dart-define=USE_REMOTE_API=true --web-hostname localhost --web-port 5173O app usa banco local por padrão. Ao ativar USE_REMOTE_API=true, usa esta API. No emulador Android, o endereço padrão é
http://10.0.2.2:5013; nas outras plataformas, http://localhost:5013.
Para endereço diferente:
flutter run --dart-define=USE_REMOTE_API=true --dart-define=API_BASE_URL=https://seu-hostPara aparelho físico, configure uma API acessível ao aparelho; localhost é o próprio dispositivo. HTTPS é necessário para a configuração de produção dos clientes. No Android debug, HTTP foi habilitado para desenvolvimento local. No macOS foi adicionada a permissão de cliente de rede.
CORS permite http://localhost:5173 e http://127.0.0.1:5173. Configure outras
origens por Cors__Origins__0, Cors__Origins__1, etc. CORS não é autenticação.
A documentação OpenAPI fica em /openapi/v1.json no ambiente Development;
/health confirma que a aplicação está atendendo.
- BACK-01: conexão SQLite configurável, chaves estrangeiras e migration inicial.
- BACK-02/03/04: tabelas, relações, índices, restrições e exclusão em cascata dos vínculos de treino. Exercícios em uso têm exclusão bloqueada.
- BACK-05: listagem, detalhes, criação, atualização e exclusão de fichas.
- BACK-06: CRUD do catálogo de exercícios.
- BACK-07: catálogo inicial com IDs estáveis, inserido pela migration.
- BACK-08: validações na camada de serviço e restrições adicionais no banco.
- BACK-09: serviços de treino/exercício separados das rotas e da persistência.
- BACK-10: adapter HTTP do Flutter e UUIDs compartilhados com a API.
- BACK-11: testes de integração com SQLite real e verificação do adapter Dart.
| Método | Rota | Resultado |
|---|---|---|
| GET | /api/treinos | Fichas completas, ordenadas por dia/nome |
| GET | /api/treinos/{id} | Uma ficha com itens ordenados |
| POST | /api/treinos | Cria com UUID gerado pelo servidor (201 + Location) |
| PUT | /api/treinos/{id} | Cria ou substitui a ficha com UUID fornecido (200) |
| DELETE | /api/treinos/{id} | Exclui ficha e vínculos (204) |
| GET | /api/exercicios | Catálogo por grupo/nome |
| GET | /api/exercicios/{id} | Consulta um exercício |
| POST | /api/exercicios | Cria exercício (201 + Location) |
| PUT | /api/exercicios/{id} | Atualiza exercício existente |
| DELETE | /api/exercicios/{id} | Exclui se não estiver em uso (204) |
O Front usa PUT com UUID gerado uma vez por formulário. Repetir a gravação com o mesmo ID não cria uma segunda ficha. IDs inválidos na rota não correspondem a um recurso. IDs desconhecidos na consulta/exclusão retornam 404.
Exemplo de corpo para criar/salvar treino:
{
"nome": "Peito + Tríceps",
"diaSemana": 1,
"descricao": "Treino A",
"ativo": true,
"exercicios": [
{
"exercicioId": "00000000-0000-4000-8000-000000000001",
"series": 4,
"repeticoes": 10,
"cargaInicial": 72.5,
"tempoDescanso": 90
}
]
}A ordem é a posição no array; o servidor atribui ordem a partir de zero.
Respostas incluem o exercício completo em cada item, além de ID, ordem, séries,
repetições, carga e descanso. DTOs evitam ciclos das entidades de navegação.
- Nome obrigatório, até 120 caracteres; grupo muscular até 80.
- Descrição opcional, até 2000 caracteres. Textos são aparados nas extremidades.
- Dia: 1 (segunda) a 7 (domingo).
- Ao menos um exercício, existente e sem duplicação na mesma ficha.
- Séries e repetições: inteiros maiores que zero.
- Carga: número finito, zero ou mais, em kg.
- Descanso: inteiro, zero ou mais, em segundos.
- Criação preserva
CreatedAt; edição preencheUpdatedAt, em UTC. - Edição remove os vínculos anteriores e insere os novos numa única transação. Qualquer falha desfaz inclusive as remoções já enviadas ao banco.
- Excluir treino mantém o catálogo. Excluir exercício em uso retorna 409.
- Validação retorna 400; ausência retorna 404; conflitos de integridade retornam 409; erros inesperados retornam 500 sem expor os detalhes internos ao cliente.
dotnet test tests/MoveUp.Tests.csprojSeis testes com SQLite real em arquivos temporários cobrem CRUD, reordenação e remoção de itens, validações, duplicações, reinício da API, preservação do seed, exclusão restrita, rollback após falha na inserção, OpenAPI e CORS.
No Flutter:
flutter test
flutter analyze
# Com uma API de desenvolvimento rodando:
dart run tool/check_api.dart http://localhost:5013A última verificação usa o adapter real para criar, ler, editar e excluir uma ficha temporária. O catálogo não é modificado. Os testes da API usam banco isolado e não acessam os dados normais da aplicação.
.env é local e ignorado pelo Git. O script scripts/run-local.sh carrega seus
valores; dotnet run executado diretamente não lê esse arquivo automaticamente.
O .env.example contém somente valores públicos de exemplo. Senhas, tokens e
chaves de serviços futuros devem ficar no ambiente do servidor ou no .env
local, nunca nos arquivos versionados. Não compartilhe o conteúdo do .env.
Bancos locais, certificados e arquivos de assinatura também estão ignorados.
BACK-12 a BACK-19 concluídas. O Front pode usar o modo API (USE_PREVIEW=false)
para executar sessões com persistência. A migration AddTrainingSessions é
aplicada ao iniciar a API e mantém as fichas e o catálogo existentes.
SessaoTreino: ID do cliente, vínculo opcional com a ficha, ID original para idempotência, nome copiado, início/fim UTC, status e observação.SessaoExercicio: nome, grupo, ordem e descanso copiados no início. Não depende do registro atual do catálogo.SerieRealizada: ordem, carga/repetições planejadas e realizadas, status e horário da conclusão.
A exclusão da ficha apenas limpa o vínculo opcional da sessão (SET NULL).
Nomes, exercícios e resultados anteriores permanecem. Editar ou excluir exercícios
do catálogo também não altera a cópia histórica.
| Método | Rota | Comportamento |
|---|---|---|
| GET | /api/sessoes/ativa | Sessão completa ou 204 se não houver ativa |
| GET | /api/sessoes/{id} | Consulta com exercícios, séries e resumo |
| PUT | /api/sessoes/{id} | Inicia com { "treinoId": "uuid" } |
| PUT | /api/sessoes/{id}/series/{serieId} | Registra, pula ou reabre uma série |
| PUT | /api/sessoes/{id}/conclusao | Finaliza com observação opcional |
| PUT | /api/sessoes/{id}/cancelamento | Cancela a sessão |
| GET | /api/sessoes?pagina=1&tamanhoPagina=20&status=concluida | Histórico paginado |
O contrato JSON completo, já consumido pelo Flutter, está na documentação de sessões.
- Apenas uma sessão ativa por vez no MVP individual. Um índice único filtrado no banco protege essa regra inclusive sob requisições simultâneas.
- Início copia a ficha em uma transação. Repetir o mesmo UUID retorna a mesma sessão e os mesmos IDs de exercícios/séries; reutilizar para outra ficha dá 409.
- Sessão:
emAndamento,concluidaoucancelada. - Série:
pendente,concluidaoupulada. - Concluir série exige repetições inteiras positivas e carga finita não negativa. Volume que excederia a capacidade numérica é rejeitado. Zero kg é permitido.
- Pular/reabrir série exige resultados nulos e preserva o planejamento. Repetir uma gravação idêntica não altera o horário de conclusão.
- Só é possível finalizar com pelo menos uma série concluída. As séries restantes são marcadas como puladas. Observação opcional até 2000 caracteres.
- Conclusão/cancelamento repetidos retornam o mesmo encerramento. Não é permitido alterar séries encerradas, cancelar sessão concluída ou concluir cancelada.
- Transações serializam as alterações de séries e encerramento, impedindo salvar resultados depois da conclusão. Falhas revertem toda a operação.
- Histórico contém somente concluídas, em ordem decrescente de início e ID. Tamanho de página entre 1 e 100; sessão com até 1000 séries.
- Resumo: duração em segundos entre início/fim, exercícios com séries concluídas, contagem de concluídas/puladas e soma de carga × repetições realizadas.
dotnet test tests/MoveUp.Tests.csproj executa 15 testes (6 da fase 1 e 9 da fase 2),
com bancos temporários. Cobertura: fluxo completo, reabertura/pulo de séries,
validações, pertencimento de séries, tentativas repetidas, concorrência, retomada
após reinício, histórico, preservação após excluir ficha/catálogo, migração da
fase 1 e rollback após falha forçada na criação da sessão.
No Flutter, tool/check_session_api.dart verifica os adapters HTTP reais contra
uma API de teste isolada. Ele cria e conclui uma sessão e remove sua ficha de
origem; o histórico permanece no banco temporário. O banco pessoal não é usado.
BACK-20 a BACK-27 implementadas e integradas ao Flutter (FRONT-19 a FRONT-26).
A migration AddConsistency preserva fichas, catálogo e sessões, adicionando
preferências de acompanhamento, revisões da rotina/meta e data/fuso de presença.
- Na Home ou Calendário, confirme os dias planejados, o fuso IANA e uma meta semanal entre 1 e 7 dias. Fichas ativas sugerem a configuração inicial.
- A primeira ativação classifica o histórico no fuso escolhido, sem presumir faltas antigas. Novas sessões fixam sua data local ao iniciar o treino.
- Somente sessões concluídas com alguma série realizada contam como presença. Duas sessões no mesmo dia contam um dia treinado, mantendo ambas nos detalhes.
- Descanso não quebra a sequência; treinos extras contam para a meta, sem aumentar a sequência de dias planejados. Hoje só vira falta após encerrar.
- Mudanças de rotina valem a partir do dia seguinte; metas, da próxima segunda. As revisões preservam o passado. Mudar o fuso não move presenças antigas nem antecipa revisões futuras já agendadas.
- O resumo semanal apresenta dias, sessões, duração, volume e adesão aos dias planejados já encerrados. Sem denominador, adesão é nula.
| Método | Rota | Resultado |
|---|---|---|
| GET/PUT | /api/acompanhamento/configuracao | Preferências, rotina/meta e revisões com vigência |
| GET | /api/acompanhamento/calendario?ano=2026&mes=10 | Datas classificadas e referências das sessões |
| GET | /api/acompanhamento/painel | Semana/mês atuais, sequência atual e melhor |
| GET | /api/acompanhamento/semanas?inicio=2026-09-28 | Resumo da semana iniciada nessa segunda-feira |
Datas de calendário/vigência usam YYYY-MM-DD. Horários de sessão continuam UTC.
O Back calcula as métricas usando TimeProvider e o fuso configurado. As consultas
por mês/semana projetam dados do período; a sequência usa datas distintas de
presença e versões da rotina, sem carregar todas as séries do histórico.
dotnet test tests/MoveUp.Tests.csproj passa 21 testes, incluindo 6 cenários novos
com SQLite isolado para frequência, rotina, meta, validações, fusos e reinício.
O Flutter passa 21 testes, análise estática e compilação web. A integração real
foi verificada com os adapters Dart e banco temporário vazio.
Contrato e execução no plano de calendário e consistência.
O acompanhamento remoto requer USE_REMOTE_API=true e USE_PREVIEW=false.
O modo padrão local possui acompanhamento equivalente sem API. Nenhum segredo
adicional é necessário.
A migration PreserveExerciseIdentity adiciona ExercicioOrigemId aos snapshots
de exercícios. Novas sessões preservam o ID do catálogo mesmo após alterações ou
exclusão da ficha/exercício. Sessões antigas mantêm null, sem associação inventada.
As respostas de sessão incluem também treinoOrigemId, dataPresenca e
fusoPresenca, permitindo importar o histórico para o SQLite do celular sem
perder as datas já fixadas.
O calendário passa a retornar onFire em cada dia: após cinco dias planejados
cumpridos em sequência, os dias realizados do segmento ganham destaque. Descanso
preserva a sequência; falta encerrada a quebra. Sessões duplicadas não inflam o
contador. Segmentos históricos que alcançaram cinco permanecem destacados.
dotnet test tests/MoveUp.Tests.csproj passa 23 testes. Os cenários adicionais
verificam OnFire entre meses e a migração de histórico da fase 3 preservando
resultados e datas, sem inventar identidade para exercícios legados. A preservação
de origem após excluir ficha/catálogo também é verificada.
Modelos, tema, ilustrações, gráficos, medidas e backup desta expansão ficam no Flutter e no banco local. Esta API não oferece contas nem sincronização automática.
