Implementação da API de micro hábitos
TLDR: Passo-a-passo de implementação do módulo de micro hábitos em 8 fases, uma por endpoint, começando pela infraestrutura base (models + migrations + admin).
Estado: as fases 4 e 7 (endpoints 3 e 6) ficaram pendentes neste plano; o contrato final da API está em reference/habits/habits_api.md.
Visão geral
Implementar o módulo completo de micro hábitos seguindo os padrões do projeto Django/DRF existente. O sistema permite criar hábitos com diferentes frequências (diária, semanal, mensal) e gerenciar suas execuções.
Endpoints alvo:
- GET
/api/v1/habits/executions/{date}— listar execuções do dia - GET
/api/v1/habits— listagem de hábitos cadastrados - PUT
/api/v1/habits/executions/{execution_id}— atualizar execução de um hábito - POST
/api/v1/habits— cadastrar hábito - PUT
/api/v1/habits/{habit_id}— atualizar hábito - GET
/api/v1/habits/{habit_id}/executions— histórico de execuções de um hábito
```mermaid graph TB User[User] –> Habit[Habit Model] Habit –> Execution[HabitExecution Model]
HabitViewSet --> HabitSerializer
ExecutionViewSet --> ExecutionSerializer
HabitViewSet --> HabitService
ExecutionViewSet --> ExecutionService
HabitService --> GenerateExecutions[Geração de Execuções]
GenerateExecutions --> Execution ```
Estrutura do app:
apps/habits/
├── models/ # habit.py, execution.py
├── serializers/ # habit.py, execution.py
├── views.py # HabitViewSet, ExecutionViewSet
├── urls.py # rotas da API
├── services.py # lógica de negócio
├── tasks.py # tasks Celery (geração de execuções)
└── migrations/
Fases
Fase 1 — Infraestrutura base
Todos os endpoints dependem disto.
- Criar o app
habitse a estrutura de diretórios - Adicionar o app em
INSTALLED_APPS - Implementar os models
HabiteHabitExecution - Criar e executar as migrations
- Registrar os models no admin
apps/habits/models/habit.py — herda de BaseModel (já tem created_at, updated_at, deleted_at):
- Campos: user (FK), name, category (choices), frequency (daily/weekly/monthly), status (active/finished), start_date, end_date, finished_at, hours (JSONField — array de HH:MM), weekly_days (JSONField — mon/tue/…), monthly_day (1-31)
- Métodos: frequency_label (property, label PT-BR) e save() sobrescrito para setar finished_at quando status='finished'
apps/habits/models/execution.py — herda de BaseModel:
- Campos: habit (FK), scheduled_date, scheduled_time, status (pending/completed/skipped/not-completed), executed_at
- Meta: unique_together ['habit', 'scheduled_date', 'scheduled_time']; índices em scheduled_date e status
Fase 2 — Endpoint 1: listar execuções do dia
GET /api/v1/habits/executions/{date}
ExecutionSerializerpara listagem (comhabit_id,habit_name,habit_category)ExecutionService.get_executions_by_date(user, date)ExecutionViewSet.list_by_date()
Fase 3 — Endpoint 2: listagem de hábitos cadastrados
GET /api/v1/habits
HabitSerializerpara listagem (comfrequency_labele todos os campos)HabitViewSet.list()
Fase 4 — Endpoint 3: atualizar execução de um hábito
PUT /api/v1/habits/executions/{execution_id} — pendente
ExecutionUpdateSerializeremapps/habits/serializers/execution.py— apenas o campostatus, validandocompletedouskippedExecutionService.update_execution_status(execution_id, status, user)— validar que a execução pertence ao usuário, atualizar o status e setarexecuted_atExecutionViewSet.update_status()emapps/habits/views.py— PUT que recebeexecution_idna URL, valida autenticação, chama o service e retorna oExecutionSerializeratualizado- Adicionar a rota em
apps/habits/urls.py
Fase 5 — Endpoint 4: cadastrar hábito
POST /api/v1/habits
HabitSerializerpara criação com validações:weekly_daysobrigatório sefrequency='weekly',monthly_dayobrigatório sefrequency='monthly',hoursnão pode ser vazio,end_date >= start_dateHabitService.generate_executions(habit, start_date=None, end_date=None)— gera execuções conforme a frequência (diário: todos os dias entrestart_dateeend_dateou hoje + 30 dias; semanal: só nos dias da semana especificados; mensal: só no dia do mês). Usabulk_createHabitViewSet.create()eperform_create()
Fase 6 — Endpoint 5: atualizar hábito
PUT /api/v1/habits/{habit_id}
HabitSerializerpara atualização (todos os campos opcionais, validações condicionais)- Lógica para regerar execuções futuras quando
frequency/hours/weekly_days/monthly_day/end_datemudarem HabitViewSet.update()eperform_update()
Fase 7 — Endpoint 6: histórico de execuções de um hábito
GET /api/v1/habits/{habit_id}/executions — pendente
ExecutionListSerializer— camposid,scheduled_date,scheduled_time,status,executed_at,day_of_week(nome do dia em PT-BR)ExecutionService.get_executions_by_habit(habit_id, user, filters, pagination)— validar que o hábito pertence ao usuário, filtrar por status quando fornecido, ordenar porscheduled_date desc,scheduled_time descExecutionViewSet.list_by_habit()— query paramspage,per_page,status; paginaçãoLimitOffsetPagination; resposta{habit_id, habit_name, total, page, per_page, executions: [...]}- Adicionar a rota em
apps/habits/urls.py
Fase 8 — Configuração final
- Criar
urls.pycom os 6 endpoints e registrar as rotas emroutes/api.py - Testes básicos
- Documentação
Regras de negócio embutidas
Criação de hábito
- Se start_date não informada, usa a data atual
- Se end_date não informada, o hábito é indefinido (null)
- Gera execuções automaticamente ao criar (próximos 30 dias ou até end_date)
Atualização de hábito
- Se mudar frequency, hours, weekly_days, monthly_day ou end_date, regera as execuções futuras
- Se status mudar para finished, seta finished_at e cancela as execuções futuras
Execuções
- Status inicial: pending
- Ao atualizar para completed ou skipped, seta executed_at
- Execuções passadas não podem ser alteradas
Filtros
- O endpoint de histórico suporta filtro por status via query param
- Paginação padrão: LimitOffsetPagination (20 itens)
Verificação
- Criação de hábito
- Geração de execuções por frequência (diária, semanal, mensal)
- Atualização de status de execução
- Filtros e paginação no histórico
Observações
- Usar
select_relatedpara evitar N+1 queries - Execuções são geradas de forma eager (antecipada) por padrão
- Se houver muitos hábitos, considerar task assíncrona para a geração de execuções