Ir para o conteúdo

Backend - Serviços

Este documento descreve todos os serviços do backend, suas responsabilidades, métodos principais e dependências.

Índice

  1. Serviços de Domínio (Método Billings)
  2. Serviços de Autenticação
  3. Serviços de Profissional
  4. Serviços Financeiros
  5. Serviços de Comunicação
  6. Serviços de Integração
  7. Serviços de Cursos e Vídeo (Marketplace)

Serviços de Domínio (Método Billings)

FertilityService

Serviço responsável por calcular o status de fertilidade baseado nas regras do Método Billings.

Localização: internal/modules/general/services/fertility_service.go

Dependências: - *gorm.DB - Conexão com banco de dados

Métodos Principais:

GetFertilityStatus

Calcula o estado de fertilidade para uma data específica.

func (s *FertilityService) GetFertilityStatus(userID uint, date time.Time) (*FertilityStatus, error)

Parâmetros: - userID - ID do usuário - date - Data para calcular o status

Retorna: - *FertilityStatus - Status de fertilidade - error - Erro se não houver ciclo ativo

FertilityStatus:

type FertilityStatus struct {
    IsFertile         bool       // Se está fértil
    IntercourseStatus string     // "not_allowed", "allowed_with_risk", "allowed_no_risk"
    DaysAfterPeak     *int       // Dias após o ápice (nil se não houver)
    HasBleeding       bool       // Se há sangramento
    PeakDate          *time.Time // Data do ápice (nil se não houver)
}

Regras Aplicadas (em ordem): 1. Regra 1: Não permitir relação nos dias de sangramento 2. Regra 2: Não permitir relação nos primeiros 15 dias 3. Regra 3: Aplicar regras baseadas no objetivo (engravidar/espaçar) 4. Regra 4: Após 4 dias do ápice, permitir relação sem risco

Exemplo:

fertilityService := services.NewFertilityService(db)
status, err := fertilityService.GetFertilityStatus(userID, time.Now())
if err != nil {
    // Tratar erro
}
// status.IsFertile, status.IntercourseStatus, etc.

GetFertilityStatusForDateRange

Calcula status de fertilidade para um intervalo de datas.

func (s *FertilityService) GetFertilityStatusForDateRange(userID uint, startDate, endDate time.Time) (map[string]*FertilityStatus, error)

Retorna: Map onde a chave é a data (YYYY-MM-DD) e o valor é o status.

Documentação Completa: Ver FERTILITY_RULES.md

Atualização 2026-03-09 (arquitetura interna): - regras compartilhadas extraídas para internal/modules/general/services/fertility/ - FertilityService segue como fachada pública do cálculo, sem mudança de contrato.


CycleService

Serviço responsável por gerenciar operações relacionadas a ciclos menstruais.

Localização: internal/modules/general/services/cycle_service.go

Dependências: - *gorm.DB - Conexão com banco de dados

Métodos Principais:

GetActiveCycle

Retorna o ciclo ativo do usuário.

func (s *CycleService) GetActiveCycle(userID uint) (*models.Cycle, error)

Retorna: - *models.Cycle - Ciclo ativo ou nil se não houver - error - Erro de banco de dados

CalculateCycleDay

Calcula o dia do ciclo para uma data específica.

func (s *CycleService) CalculateCycleDay(cycle *models.Cycle, date time.Time) (int, error)

Retorna: - int - Dia do ciclo (1 = primeiro dia) - error - Erro se ciclo inválido

EnsureSingleActiveCycle

Garante que apenas um ciclo esteja ativo por usuário.

func (s *CycleService) EnsureSingleActiveCycle(userID uint, newCycleID uint) error

Comportamento: - Se newCycleID for 0, desativa todos os ciclos ativos - Caso contrário, desativa todos os outros ciclos ativos, exceto o novo

Regra operacional (criação do primeiro ciclo): - O primeiro ciclo não é criado automaticamente no onboarding. - A criação ocorre via POST /cycles. - No primeiro ciclo, start_date deve ser não futura e dentro da janela de 12 meses.


CycleValidationsService

Serviço responsável por validações relacionadas a ciclos.

Localização: internal/modules/general/services/cycle_validations.go

Métodos Principais:

ValidateDateInCycle

Valida se uma data está dentro de um ciclo.

func (s *CycleValidationsService) ValidateDateInCycle(date time.Time, cycle *models.Cycle) error

Validações: - Data não pode ser anterior ao início do ciclo - Se ciclo tem fim, data não pode ser posterior - Data não pode ser futura

CanEditCycle

Verifica se um ciclo pode ser editado.

func (s *CycleValidationsService) CanEditCycle(cycle *models.Cycle) bool

Retorna: true se ciclo está ativo e não tem data de fim.

ShouldShowFirstDayOfMenstruation

Verifica se deve mostrar o campo "primeiro dia da menstruação".

func (s *CycleValidationsService) ShouldShowFirstDayOfMenstruation(cycle *models.Cycle, date time.Time) bool

Retorna: true se já passaram 15 dias desde o início do ciclo.


SymbolRulesService

Serviço responsável por gerenciar regras de símbolos do Método Billings.

Localização: internal/modules/general/services/symbol_rules.go

Dependências: - *gorm.DB - Conexão com banco de dados

Métodos Principais:

GetAllowedSymbols

Retorna os IDs dos símbolos permitidos para um contexto específico.

func (s *SymbolRulesService) GetAllowedSymbols(cycleID uint, day int, sensationID *uint, appearanceID *uint) ([]uint, error)

Parâmetros: - cycleID - ID do ciclo - day - Dia do ciclo - sensationID - ID da sensação (opcional) - appearanceID - ID da aparência (opcional)

Lógica: 1. Busca regras baseadas em dias (DayBasedRule) aplicáveis 2. Coleta símbolos permitidos das regras 3. Aplica restrições das regras 4. Se não houver regras, permite todos os símbolos

ValidateSymbol

Valida se um símbolo é permitido para uma observação.

func (s *SymbolRulesService) ValidateSymbol(observation *models.Observation, symbolID uint) error

Validações: - Observação deve ter cycle_id - Calcula dia do ciclo - Verifica se símbolo está na lista permitida

CheckRuleViolation

Verifica se houve infração de regras no dia atual.

func (s *SymbolRulesService) CheckRuleViolation(userID uint, date time.Time) (bool, error)

Retorna: true se houve infração, false caso contrário.


MOBRulesService

Serviço responsável por aplicar regras específicas do Método de Ovulação Billings (MOB).

Localização: internal/modules/general/services/mob_rules_service.go

Responsabilidades: - Aplicar regras específicas do MOB - Validar padrões de infertilidade - Calcular períodos férteis baseados em regras MOB


Serviços de Autenticação

AuthService

Serviço responsável por autenticação, registro e gerenciamento de usuários.

Localização: internal/services/auth/auth_service.go

Dependências: - repo.Repository - Repository de autenticação - *email.EmailService - Serviço de email

Métodos Principais:

Login

Autentica um usuário por email e senha.

func (s *Service) Login(email, password string) (*LoginResult, error)

Validações: - Email e senha devem ser válidos - Usuário deve estar ativo - Email deve estar verificado

Retorna:

type LoginResult struct {
    Token        string
    RefreshToken string
    User         *models.User
}

Erros: - INVALID_CREDENTIALS - Credenciais inválidas - USER_INACTIVE - Usuário inativo - EMAIL_NOT_VERIFIED - Email não verificado

Register

Cria um novo usuário e envia email de verificação.

func (s *Service) Register(req RegisterRequest) (*models.User, string, error)

RegisterRequest:

type RegisterRequest struct {
    Username string
    Email    string
    Password string
    Name     string
    UserType string
}

Processo: 1. Valida tipo de usuário 2. Verifica se email já existe 3. Hash da senha (bcrypt) 4. Cria usuário com email_verified = false 5. Gera token de verificação 6. Envia email de verificação 7. Retorna usuário e mensagem

VerifyEmail

Verifica email do usuário.

func (s *Service) VerifyEmail(token string) error

Processo: 1. Busca token de verificação 2. Valida expiração 3. Marca email como verificado 4. Marca token como usado

ForgotPassword

Solicita reset de senha.

func (s *Service) ForgotPassword(email string) error

Processo: 1. Busca usuário por email 2. Gera token de reset 3. Salva token no banco 4. Envia email com link de reset

ResetPassword

Redefine senha do usuário.

func (s *Service) ResetPassword(token, newPassword string) error

Processo: 1. Valida token 2. Verifica expiração 3. Atualiza senha (hash bcrypt) 4. Marca token como usado

RefreshToken

Renova token de acesso usando refresh token.

func (s *Service) RefreshToken(refreshToken string) (string, error)

Retorna: Novo token JWT


OAuth Service

Serviço responsável por autenticação OAuth (Google, Apple).

Localização: internal/services/oauth/provider.go

Provedores Suportados: - Google OAuth - Apple Sign In

Métodos Principais:

Authenticate

Autentica usuário via OAuth.

func (p *Provider) Authenticate(provider string, token string) (*OAuthResult, error)

Processo: 1. Valida token OAuth com provedor 2. Busca ou cria usuário 3. Cria/atualiza UserAuthProvider 4. Gera tokens JWT 5. Retorna resultado

OAuthResult:

type OAuthResult struct {
    Token        string
    RefreshToken string
    User         *models.User
    IsNewUser    bool
}

Provedores: - google - Google OAuth - apple - Apple Sign In


Serviços de Profissional

ProfessionalProfileService

Serviço responsável por gerenciar perfis profissionais.

Localização: internal/services/professional/professional_profile_service.go

Dependências: - repo.ProfessionalProfileRepository - Repository de perfis - authRepo.Repository - Repository de autenticação

Métodos Principais:

GetProfile

Retorna o perfil do profissional.

func (s *ProfessionalProfileService) GetProfile(userID uint, userType string) (interface{}, error)

Comportamento: - Se userType == "admin", retorna dados básicos do usuário - Caso contrário, retorna perfil profissional completo

CreateOrUpdateProfile

Cria ou atualiza perfil profissional.

func (s *ProfessionalProfileService) CreateOrUpdateProfile(userID uint, req UpdateProfileRequest) (*models.ProfessionalProfile, error)

Processo: 1. Verifica se perfil existe 2. Se existe, atualiza 3. Se não existe, cria com status pending 4. Retorna perfil

Validações: - Usuário deve ser do tipo professional - Campos obrigatórios devem estar preenchidos


ProfessionalPatientService

Serviço responsável por gerenciar vínculos entre profissionais e pacientes.

Localização: internal/services/professional/professional_patient_service.go

Dependências: - repo.ProfessionalPatientRepository - Repository de vínculos

Métodos Principais:

GetPatients

Lista pacientes do profissional com paginação.

func (s *ProfessionalPatientService) GetPatients(professionalID uint, search string, page, limit int) (*PatientListResult, error)

Retorna:

type PatientListResult struct {
    Data       []PatientWithStatus
    Total      int64
    Page       int
    Limit      int
    TotalPages int
}

LinkToProfessional

Permite que um cliente se vincule a um profissional.

func (s *ProfessionalPatientService) LinkToProfessional(patientID, professionalID uint) (*models.ProfessionalPatient, error)

Validações: - Profissional deve existir - Profissional deve ter perfil aprovado - Cria vínculo com status pending

Notificações: - Cria notificação para o profissional sobre nova solicitação

UnlinkFromProfessional

Permite que um paciente encerre o vínculo.

func (s *ProfessionalPatientService) UnlinkFromProfessional(patientID uint) error

Nota: Não requer aprovação - paciente pode encerrar livremente.

ChangeProfessional

Permite que um paciente mude de orientadora.

func (s *ProfessionalPatientService) ChangeProfessional(patientID, newProfessionalID uint) (*models.ProfessionalPatient, error)

Processo: 1. Valida novo profissional 2. Remove vínculo antigo 3. Cria novo vínculo com status pending 4. Notifica novo profissional

Permite que a orientadora aprove um vínculo pendente.

func (s *ProfessionalPatientService) ApproveLink(professionalID, patientID uint) (*models.ProfessionalPatient, error)

Notificações: - Cria notificação para paciente sobre aprovação

Permite que a orientadora rejeite um vínculo pendente.

func (s *ProfessionalPatientService) RejectLink(professionalID, patientID uint) error

Notificações: - Cria notificação para paciente sobre rejeição

UpdatePatientWomanPattern

Atualiza o Padrão Básico de Infertilidade (PBI) do paciente.

func (s *ProfessionalPatientService) UpdatePatientWomanPattern(professionalID, patientID uint, womanPattern string, pbiSensationID, pbiAppearanceID *uint) error

Validações: - Profissional deve estar vinculado ao paciente - Vínculo deve estar aprovado


AvailabilityService

Serviço responsável por gerenciar disponibilidade de profissionais.

Localização: internal/services/professional/availability_service.go

Dependências: - repo.AvailabilityRepository - Repository de disponibilidade

Métodos Principais:

GetAvailability

Retorna os horários disponíveis do profissional.

func (s *AvailabilityService) GetAvailability(professionalID uint) ([]models.AvailabilitySlot, error)

CreateSlot

Cria um novo slot de disponibilidade.

func (s *AvailabilityService) CreateSlot(professionalID uint, dateStr, startTime, endTime string) (*models.AvailabilitySlot, error)

Validações: - Data não pode ser no passado - Horários devem estar no formato HH:MM - Slot não pode já existir

BulkCreate

Cria múltiplos slots de disponibilidade.

func (s *AvailabilityService) BulkCreate(professionalID uint, req BulkCreateRequest) (int, int, error)

BulkCreateRequest:

type BulkCreateRequest struct {
    Date       string   // Data específica
    TimeSlots  []string // Slots no formato "HH:MM-HH:MM"
    DaysOfWeek []int    // Dias da semana (0=Domingo, 6=Sábado)
    StartDate  string   // Data inicial (para recorrência)
    EndDate    string   // Data final (para recorrência)
}

Comportamento: - Se fornecido DaysOfWeek + StartDate + EndDate, cria slots recorrentes - Se fornecido apenas Date, cria slots para data específica - Ignora slots duplicados

Retorna: (createdCount, totalCount, error)

UpdateSlot

Atualiza um slot de disponibilidade.

func (s *AvailabilityService) UpdateSlot(professionalID uint, slotID uint, req UpdateSlotRequest) (*models.AvailabilitySlot, error)

DeleteSlot

Remove um slot de disponibilidade.

func (s *AvailabilityService) DeleteSlot(professionalID uint, slotID uint) error

ProfessionalFinancialService

Serviço responsável por gerenciar informações financeiras de profissionais.

Localização: internal/services/professional/professional_financial_service.go

Métodos Principais:

GetFinancialSummary

Retorna resumo financeiro do profissional.

func (s *ProfessionalFinancialService) GetFinancialSummary(professionalID uint) (*FinancialSummary, error)

GetBankAccount

Retorna conta bancária do profissional.

func (s *ProfessionalFinancialService) GetBankAccount(professionalID uint) (*models.ProfessionalBankAccount, error)

UpdateBankAccount

Atualiza conta bancária do profissional.

func (s *ProfessionalFinancialService) UpdateBankAccount(professionalID uint, account *models.ProfessionalBankAccount) error

GetPayments

Lista pagamentos do profissional.

func (s *ProfessionalFinancialService) GetPayments(professionalID uint, page, limit int) ([]models.Payment, int64, error)

Serviços Financeiros

AccountService

Serviço responsável por gerenciar contas financeiras genéricas.

Localização: internal/services/accounts/account_service.go

Dependências: - repo.Repository - Repository de contas

Métodos Principais:

List

Lista contas do usuário.

func (s *Service) List(userID uint, userType string) ([]models.Account, error)

Get

Obtém uma conta específica.

func (s *Service) Get(id uint, userID uint, userType string) (*models.Account, error)

Validações de Acesso: - Usuário pode acessar apenas suas próprias contas - Admin e professional podem acessar contas de outros usuários

Create

Cria uma nova conta.

func (s *Service) Create(account *models.Account, userID uint) error

Update

Atualiza uma conta existente.

func (s *Service) Update(id uint, input *models.Account, userID uint, userType string) (*models.Account, error)

Delete

Remove uma conta.

func (s *Service) Delete(id uint, userID uint, userType string) error

PlanService

Serviço responsável por gerenciar planos de assinatura.

Localização: internal/services/plans/plan_service.go

Dependências: - repo.Repository - Repository de planos

Métodos Principais:

List

Lista planos com paginação e pesquisa.

func (s *Service) List(userType string, search string, page, limit int) (*ListResult, error)

Validações: - page mínimo: 1 - limit mínimo: 1, máximo: 100

Retorna:

type ListResult struct {
    Data       []models.Plan
    Total      int64
    Page       int
    Limit      int
    TotalPages int
}

Get

Obtém um plano por ID.

func (s *Service) Get(id uint) (*models.Plan, error)

Create

Cria um novo plano (apenas admin).

func (s *Service) Create(plan *models.Plan) error

Validações: - Nome é obrigatório - Todos os preços devem ser maiores que zero

Update

Atualiza um plano existente (apenas admin).

func (s *Service) Update(id uint, plan *models.Plan) (*models.Plan, error)

Delete

Remove um plano (apenas admin).

func (s *Service) Delete(id uint) error

Serviços de Comunicação

NotificationService

Serviço responsável por criar e gerenciar notificações.

Localização: internal/services/notifications/notification_service.go

Métodos Principais:

CreateMessageNotification

Cria notificação para nova mensagem.

func CreateMessageNotification(userID, messageID uint, senderName string) error

CreateAppointmentNotification

Cria notificação para agendamento.

func CreateAppointmentNotification(userID, appointmentID uint, appointmentType string, details map[string]interface{}) error

Tipos de Agendamento: - created - Novo agendamento criado - confirmed - Agendamento confirmado - rejected - Agendamento rejeitado - cancelled - Agendamento cancelado

CreateTaskNotification

Cria notificação para tarefa pendente.

func CreateTaskNotification(userID uint, taskType string, title, message string, metadata map[string]interface{}) error

Uso: - Solicitações de vínculo - Aprovações/rejeições - Outras tarefas pendentes

CreateSystemNotification

Cria notificação do sistema.

func CreateSystemNotification(userID uint, title, message string) error

CreatePendingRecordNotification

Cria notificação de lembrete para registro diário pendente.

func CreatePendingRecordNotification(userID uint, missingDaysCount int, cycleID uint) error

Comportamento: - Mensagem varia conforme quantidade de dias pendentes - Inclui metadata com missing_days_count e cycle_id


Serviços de Integração

EmailService

Serviço responsável por enviar emails.

Localização: internal/services/email/email.go

Dependências: - EmailProvider - Provedor de email (SendGrid ou SMTP) - EmailConfig - Configurações de email

Provedores Suportados: - SendGrid (via sendgrid_provider.go) - SMTP genérico (via smtp_provider.go)

Métodos Principais:

SendEmail

Envia email genérico.

func (es *EmailService) SendEmail(to, subject, body string) error

SendVerificationEmail

Envia email de verificação de conta.

func (es *EmailService) SendVerificationEmail(email, token string) error

Template: - Link de verificação - Expira em 24 horas - HTML formatado

SendPasswordResetEmail

Envia email de reset de senha.

func (es *EmailService) SendPasswordResetEmail(email, token string) error

Template: - Link de reset - Expira em 24 horas - HTML formatado

Factory: O serviço é criado via factory (factory.go) que detecta automaticamente qual provedor usar baseado nas variáveis de ambiente.


Serviços de Cursos e Vídeo (Marketplace)

Course Service (módulo marketplace/courses)

Serviço responsável por catálogo, matrículas, editor de curso do profissional, pipeline de vídeo com Mux e playback protegido.

Localização: internal/modules/marketplace/courses/service.go

Subpastas por ator (registro de rotas): - internal/modules/marketplace/courses/client - internal/modules/marketplace/courses/professional - internal/modules/marketplace/courses/admin - internal/modules/marketplace/courses/webhooks

Rotas relacionadas: - cliente: GET /marketplace/enrollments/:enrollment_id/lessons/:lesson_id/playback - profissional: POST /marketplace/professional/courses/:course_id/lessons/:lesson_id/video-upload-url - profissional: POST /marketplace/professional/courses/:course_id/lessons/:lesson_id/video-from-url - profissional: GET /marketplace/professional/courses/:course_id/lessons/:lesson_id/video-status - webhook: POST /marketplace/webhooks/mux

Pipeline de vídeo atual (Mux): 1. profissional cria upload direto (CreateLessonVideoUpload) ou importa por URL (CreateLessonVideoFromURL); 2. aula entra em video_status=processing; 3. webhook Mux processa eventos idempotentes em video_webhook_events; 4. quando video.asset.ready, aula recebe mux_playback_id e status ready; 5. cliente solicita token assinado de playback (GetPlaybackToken) para render no player.

Status de vídeo da aula: - pending_upload - processing - ready - errored

Feature flags operacionais: - marketplace.mux.enabled - marketplace.mux.webhook.enabled - marketplace.mux.signed_playback.enabled

Rate limit de playback: - endpoint protegido por limite por minuto; - configuração via MARKETPLACE_PLAYBACK_RATE_LIMIT_PER_MINUTE.


Padrões de Uso

Inicialização de Serviços

// Serviço com dependência de DB
fertilityService := services.NewFertilityService(db)

// Serviço com dependência de Repository
accountRepo := accountsRepo.NewGormAccountRepository(db)
accountService := accounts.NewAccountService(accountRepo)

// Serviço com múltiplas dependências
profileRepo := profRepo.NewGormProfessionalProfileRepository(db)
userRepo := authRepo.NewGormAuthRepository(db)
profileService := professional.NewProfessionalProfileService(profileRepo, userRepo)

Tratamento de Erros

Todos os serviços retornam erros que devem ser tratados pelos handlers:

result, err := service.DoSomething()
if err != nil {
    // Erro pode ser:
    // - Erro de validação (retornar 400)
    // - Erro de não encontrado (retornar 404)
    // - Erro de permissão (retornar 403)
    // - Erro de banco (retornar 500)
    return handleError(err)
}

Validações

Serviços devem validar: - Dados de entrada - Regras de negócio - Permissões de acesso - Integridade de dados


Referências