Hábitos default no onboarding

TLDR: Permitir que admins cadastrem hábitos pré-configurados por período do dia, exibidos no onboarding para usuários sem hábitos.

Contexto

Usuários novos chegam numa tela vazia, sem hábitos. Para reduzir a fricção no onboarding, o app exibirá sugestões de hábitos pré-configurados. O admin cadastra os templates no Django Admin e o app os consome para criar os hábitos do usuário em uma única chamada.

Objetivos

  • Admins podem criar, editar e ativar/desativar DefaultHabit pelo Django Admin
  • Cada DefaultHabit tem três conjuntos independentes de horários: manhã, tarde e noite
  • O app lista os defaults disponíveis via API
  • O app cria os hábitos selecionados em uma única chamada, passando o período escolhido pelo usuário

Fora de escopo

— (não registrado na spec original)

Mudanças

Novo model: apps/habits/models/default_habit.py

DefaultHabit ├── name CharField(255) ├── category CharField — mesmos choices de Habit ├── frequency CharField — daily | weekly | monthly ├── hours_morning JSONField — ex: ['07:00', '10:00'] ├── hours_afternoon JSONField — ex: ['14:00', '17:00'] ├── hours_night JSONField — ex: ['20:00', '22:00'] ├── weekly_days JSONField(null) — para frequency=weekly ├── monthly_day IntegerField(null) — para frequency=monthly ├── is_active BooleanField(default=True) ├── order IntegerField(default=0) └── timestamps (created_at, updated_at)

Arquivos a criar/modificar

Arquivo Ação
apps/habits/models/default_habit.py criar model
apps/habits/models/__init__.py exportar DefaultHabit
apps/habits/admin.py registrar DefaultHabitAdmin
apps/habits/serializers/default_habit.py criar serializers
apps/habits/serializers/__init__.py exportar novos serializers
apps/habits/views.py adicionar DefaultHabitViewSet e CreateHabitsFromDefaultView
apps/habits/urls.py registrar rotas
apps/habits/services.py adicionar DefaultHabitService.create_from_defaults()
apps/habits/tests/unit/test_default_habit_service.py testes do service
apps/habits/tests/integration/test_default_habit_api.py testes da API
apps/habits/migrations/ migration gerada

Endpoints

GET /habits/defaults/ — lista DefaultHabits ativos POST /habits/default/ — cria hábitos do usuário a partir dos defaults selecionados

GET /habits/defaults/ — resposta: json [ { "id": 1, "name": "Beber água", "category": "health", "frequency": "daily", "hours_morning": ["07:00", "10:00", "14:00", "19:00"], "hours_afternoon": ["10:00", "14:00", "17:00", "19:00"], "hours_night": ["18:00", "20:00", "22:00"], "order": 1 } ]

POST /habits/default/ — payload: json { "time_of_day": "morning", "default_habit_ids": [1, 3] }

O backend busca cada DefaultHabit, usa o array de horários do time_of_day informado e chama o HabitService existente para criar o hábito e gerar as execuções. Retorna os hábitos criados.

Admin: DefaultHabitAdmin

  • list_display: name, category, frequency, is_active, order
  • Filtros: category, frequency, is_active
  • Fieldsets:
    • Info: name, category, frequency, is_active, order
    • Horários por período: hours_morning, hours_afternoon, hours_night
    • Recorrência: weekly_days, monthly_day

Passos de execução

  1. Model — criar apps/habits/models/default_habit.py, exportar em __init__.py, gerar e aplicar a migration
  2. Admin — adicionar DefaultHabitAdmin; validar no Django Admin a criação com os três arrays de horários
  3. Serializers — DefaultHabitSerializer (GET) e CreateHabitsFromDefaultSerializer (POST, valida time_of_day e default_habit_ids)
  4. Service — DefaultHabitService.create_from_defaults(user, time_of_day, default_habit_ids): busca só os is_active=True, seleciona o array de horários do período, chama o HabitService e retorna os hábitos criados
  5. Views — DefaultHabitViewSet (só list, ordenado por order) e CreateHabitsFromDefaultView
  6. URLs — registrar as duas rotas
  7. Testes unitários — test_default_habit_service.py: manhã/tarde/noite usam o array correto, inativos são ignorados, criação múltipla
  8. Testes de integração — test_default_habit_api.py: lista só ativos, ordenação por order, POST cria com horários corretos, time_of_day inválido retorna 400
  9. Factory e seed — DefaultHabitFactory; apps/habits/fixtures/default_habits.json com 4-5 hábitos representativos, idempotente via get_or_create por name
  10. Documentação — documentar a regra de negócio dos hábitos default e indexá-la

Como verificar

  1. Admin: criar um DefaultHabit com horários distintos por período
  2. GET /habits/defaults/ → retorna o default criado com os três arrays de horários
  3. POST /habits/default/ com time_of_day=morning e o ID do default → cria o hábito com os horários de manhã
  4. POST /habits/default/ com time_of_day=night → mesmo default, hábito criado com horários de noite
  5. Checar que as HabitExecution foram geradas corretamente para os horários
  6. make seed executa sem erro

Documentação