Skip to main content

Fluxo de Atualização de Telefone e E-mail

Escopo: Atualização de dados de contato do usuário no app Flutter (Coezzion Vendas)
Data: 2026-07-06


1. Resumo

Os fluxos de atualização de telefone e e-mail permitem que o usuário cadastre ou altere seus dados de contato com verificação por código de 6 dígitos. Ambos seguem a mesma arquitetura em três etapas:

  1. Informar o novo telefone ou e-mail
  2. Receber e validar o código de verificação enviado
  3. Persistir a alteração via API (change-cellphone ou change-email)

O fluxo é acionado em três contextos distintos: obrigatoriamente após o login, pelo perfil do vendedor (usuário logado) ou como sub-fluxo da recuperação de senha. A diferença entre os contextos está principalmente na forma de autenticação das requisições HTTP.


2. Pontos de Entrada

Existem três contextos que utilizam as mesmas telas e endpoints, com parâmetros diferentes:

ContextoCondição de ativaçãocustomAuthorizationTokencanValidateByEmailArquivo
Pós-login obrigatóriois_update_contact_enabled == true e !user.isContactUpdatedauthApp.auth.tokentruelib/screens/login/login_manager.dart
Perfil do vendedorUsuário logado, ícone de edição em dados de contatonull (usa AuthInterceptor)false (telefone)lib/screens/seller_profile/seller_profile/widget/seller_contact_details.dart
Recuperação de senhaLimite de SMS excedido ou troca de método em CodeVerificationByMethodScreennulltruelib/controllers/code_verification/by_method/code_verification_by_method_controller.dart

Condição isContactUpdated

Definida em lib/models/user/user.dart:

bool get isContactUpdated {
if (cellPhoneConfirmed) return true;
if (emailConfirmed) return true;
return false;
}

O fluxo pós-login só é exibido quando nenhum dos dois contatos está confirmado.

Fluxo pós-login (LoginManager._updateContact)

  1. Login bem-sucedido via tryCompletLogin
  2. Verifica Remote Config is_update_contact_enabled
  3. Se contato não atualizado, fecha loader e exibe bottom sheet obrigatório
  4. Navega para UpdateUserContactScreen passando authApp completo
  5. Se usuário cancela (result == null), aborta o login
  6. Se atualiza com sucesso, retorna authApp atualizado e continua o fluxo de login

3. Fluxo de Telefone

Passo a passo

EtapaTelaAçãoAPI
1UpdatePhoneScreenInforma telefone e toca Continuar
2CodeVerificationByPhoneScreenCódigo enviado automaticamente ao abrirPOST /api/auth/verify-phone
3CodeVerificationByPhoneScreenInforma código de 6 dígitosPOST /api/auth/verify-code
4(interno ao controller)Persiste alteraçãoPOST /api/auth/change-cellphone
5Tela anteriorRetorna resultado e atualiza estado local

4. Fluxo de E-mail

Passo a passo

EtapaTelaAçãoAPI
1UpdateEmailScreenInforma e-mail e toca Continuar
2CodeVerificationByEmailScreenCódigo enviado automaticamente ao abrirPOST /api/auth/verify-email
3CodeVerificationByEmailScreenInforma código de 6 dígitosPOST /api/auth/verify-code
4(interno ao controller)Persiste alteraçãoPOST /api/auth/change-email
5Tela anteriorRetorna resultado e atualiza estado local

5. Endpoints

Base URL dinâmica: {baseUrl} via PrefsService.getEnvConfig().

5.1 Fluxo de telefone

#MétodoEndpointControllerRequest Body
1POST/api/auth/verify-phoneCodeVerificationByPhoneController.sendCode{cpf, cellPhone}
2POST/api/auth/verify-codeCodeVerificationByPhoneController.verifyCode{cpf, cellPhone, VerificationCode}
3POST/api/auth/change-cellphoneCodeVerificationByPhoneController.updatePhone{cpf, cellPhone, token}

Payloads:

// POST /api/auth/verify-phone
{ "cpf": "12345678900", "cellPhone": "11999998888" }

// POST /api/auth/verify-code
{ "cpf": "12345678900", "cellPhone": "11999998888", "VerificationCode": "123456" }

// POST /api/auth/change-cellphone
{ "cpf": "12345678900", "cellPhone": "11999998888", "token": "<token>" }

5.2 Fluxo de e-mail

#MétodoEndpointControllerRequest Body
1POST/api/auth/verify-emailCodeVerificationByEmailScreenController.sendCode{cpf, email}
2POST/api/auth/verify-codeCodeVerificationByEmailScreenController.verifyCode{cpf, email, VerificationCode}
3POST/api/auth/change-emailCodeVerificationByEmailScreenController.updateEmail{cpf, email, token}

Payloads:

// POST /api/auth/verify-email
{ "cpf": "12345678900", "email": "usuario@email.com" }

// POST /api/auth/verify-code
{ "cpf": "12345678900", "email": "usuario@email.com", "VerificationCode": "123456" }

// POST /api/auth/change-email
{ "cpf": "12345678900", "email": "usuario@email.com", "token": "<token>" }

5.3 Constantes em api_utils.dart

static const forgetPasswordSendCode = '$authApi/verify-phone';
static const forgetEmailSendCode = '$authApi/verify-email';
static const forgetPasswordValidateCode = '$authApi/verify-code';
static const updatePhone = '$api/auth/change-cellphone';
static const updateEmail = '$api/auth/change-email';

Nota: Os endpoints verify-phone, verify-email e verify-code compartilham nomenclatura com o fluxo de recuperação de senha, mas utilizam payloads diferentes do fluxo verify-recover-method / verify-code-recover documentado em recover.md.


6. Telas e Navegação

6.1 Telas principais

Rota (AppRoutes)TelaTítuloController
/update_user_contactUpdateUserContactScreenAtualizar telefone ou e-mailUpdateUserContactController
/update_phoneUpdatePhoneScreenAtualizar telefoneUpdatePhoneController
/update_emailUpdateEmailScreenAtualizar e-mailUpdateEmailController
/code_verification_by_phoneCodeVerificationByPhoneScreenCódigo de verificaçãoCodeVerificationByPhoneController
/code_verification_by_emailCodeVerificationByEmailScreenCódigo de verificaçãoCodeVerificationByEmailScreenController

6.2 Argumentos de navegação

ClasseCamposUso
UpdateUserContactScreenArgumentauthAppHub pós-login com objeto de autenticação completo
UpdatePhoneScreenArgumentcpf, customAuthorizationToken, canValidateByEmailEntrada da tela de telefone
UpdateEmailScreenArgumentcpf, customAuthorizationTokenEntrada da tela de e-mail
CodeVerificationByPhoneArgumentscpf, cellPhone, customAuthorizationToken, canRedirectToEmailVerificação SMS
CodeVerificationByEmailScreenArgumentscpf, email, customAuthorizationTokenVerificação e-mail

6.3 Resultados de navegação

ClasseCamposRetornado por
UpdateUserContactResultcontactUpdated, updatedAuthAppUpdateUserContactControllerLoginManager
UpdatePhoneScreenResultphoneUpdatePhoneController
UpdateEmailScreenResultemail, token, expirationDateUpdateEmailController
CodeVerificationByPhoneResultisUpdated, token, expirationDateCodeVerificationByPhoneController
CodeVerificationByEmailScreenResultisUpdated, token, expirationDateCodeVerificationByEmailScreenController
ValidateByEmailResultCodeVerificationByPhoneController (fallback SMS → e-mail)

6.4 Hub pós-login (UpdateUserContactScreen)

Tela intermediária que exibe sempre as duas opções (Telefone e E-mail). Ao concluir qualquer uma:

  • Atualiza authApp.user.cellPhone / authApp.user.email
  • Define cellPhoneConfirmed ou emailConfirmed = true
  • Retorna UpdateUserContactResult para o LoginManager

Se o usuário falha no SMS e aceita validar por e-mail, UpdateUserContactController.updatePhone redireciona automaticamente para updateEmail.


7. Keys e Autenticação

7.1 Firebase Remote Config

KeyTipoPropriedade DartUso
is_update_contact_enabledboolisUpdateContactEnabledHabilita fluxo obrigatório pós-login
recover_methods_tokenstringrecoverMethodsTokenHeader x-api-key para todos os endpoints de verificação e alteração de contato

7.2 Headers HTTP

HeaderQuando aplicadoValor
x-api-keyverify-phone, verify-email, verify-code, change-cellphone, change-emailrecover_methods_token via VerifyMethodsInterceptor
Authorization: Bearer {token}Fluxo pós-login (antes de setAuthApp)customAuthorizationToken passado manualmente em DefaultDioProvider.post
AuthorizationPerfil do vendedor (usuário logado)Injetado automaticamente por AuthInterceptor

7.3 Diferença de autenticação por contexto


8. Modelos Request/Response

Requests

ModeloCamposEndpoint
SendValidationCodeRequest (byPhone)cpf, cellPhoneverify-phone
SendValidationCodeRequest (byEmail)cpf, emailverify-email
ValidateCodeRequest (byPhone)cpf, cellPhone, VerificationCodeverify-code
ValidateCodeRequest (byEmail)cpf, email, VerificationCodeverify-code
UpdatePhoneRequestcpf, cellPhone, tokenchange-cellphone
UpdateEmailRequestcpf, email, tokenchange-email

Responses

ModeloCampos relevantes
SendValidationCodeResponseisSuccess, error.message
ValidateCodeResponseisSuccess, success.token, success.expirationDate, error.message
UpdatePhoneResponseisSuccess, success/error (title, message, needConfirm)
UpdateEmailResponseisSuccess, success/error (title, message, needConfirm)

9. Regras de Negócio

Validação de entrada

CampoRegraImplementação
TelefoneFormato brasileiro válidoflutter_libphonenumber com região BR; botão habilitado com 15 caracteres mascarados
E-mailFormato válidotext.isEmail (extensão GetX)

Timer de reenvio

  • Intervalo de 2 minutos entre solicitações
  • PhoneCodeVerificationTimerController para SMS
  • EmailCodeVerificationTimerController para e-mail
  • Botão "Reenviar código" habilitado apenas após expiração

Limite de tentativas SMS

Implementado em PhoneCodeVerificationCounterService:

  • Máximo de 3 tentativas em 1 hora (0 em modo debug)
  • Após exceder, exibe bottom sheet oferecendo validação por e-mail
  • Só se aplica quando canValidateByEmail == true (pós-login e recuperação de senha)
  • No perfil do vendedor (canValidateByEmail: false), o fallback para e-mail não está disponível

Comportamento pós-sucesso por contexto

ContextoAção após sucesso
Pós-loginAtualiza authApp in-memory, define cellPhoneConfirmed/emailConfirmed = true, retorna UpdateUserContactResult
Perfil vendedorAppEssentialDataService.updateSellerPhone/Email + EditedUserInformationRewardEvent
Recuperação de senhaReinicia fluxo em ForgotPasswordScreen (Get.offNamedUntil)

Cancelamento pós-login

Se o usuário sai do fluxo sem atualizar contato (result == null), o LoginManager retorna null em _updateContact e aborta o login — o usuário não prossegue para a home.


10. Diagramas

10.1 Mapa de pontos de entrada

10.2 Sequência API — telefone

10.3 Sequência API — e-mail

10.4 Fallback SMS para e-mail

10.5 Fluxo pós-login completo


11. Relação com recover.md

Os fluxos de atualização de contato compartilham telas e endpoints com o fluxo de recuperação de senha documentado em docs/recover.md, mas com propósitos distintos:

Aspectoupdate-contact (este doc)recover.md
ObjetivoAtualizar telefone/e-mail do usuárioRedefinir senha de acesso
Endpoints de verificaçãoverify-phone, verify-email, verify-codeverify-recover-method, verify-code-recover
Endpoint finalchange-cellphone / change-emailchange-password
Hub de seleçãoUpdateUserContactScreen (sempre 2 opções)UpdateUserContactByMethodsScreen (métodos da API)
AutenticaçãoPode usar Authorization (pós-login) ou apenas x-api-keyApenas x-api-key (sem login)

Sub-fluxo compartilhado: durante a recuperação de senha, quando o usuário excede o limite de SMS, CodeVerificationByMethodScreenController.tryAnotherMethod aciona UpdatePhoneScreen ou UpdateEmailScreen — os mesmos fluxos documentados aqui. Após atualizar o contato, o usuário é redirecionado de volta ao início da recuperação de senha.


12. Arquivos Relacionados

Controllers

ArquivoResponsabilidade
lib/controllers/update_user_contact/update_user_contact_controller.dartHub pós-login, orquestra telefone/e-mail
lib/controllers/update_phone/update_phone_controller.dartValidação e navegação para verificação SMS
lib/controllers/update_email/update_email_controller.dartValidação e navegação para verificação e-mail
lib/controllers/code_verification/phone/code_verification_by_phone_controller.dartEnvio/validação SMS + change-cellphone
lib/controllers/code_verification/email/code_verification_by_email_controller.dartEnvio/validação e-mail + change-email
lib/controllers/seller/seller_edit_controller.dartEntrada de edição de e-mail no perfil

Screens

ArquivoRota
lib/screens/update_user_contact/update_user_contact_screen.dart/update_user_contact
lib/screens/update_phone/update_phone_screen.dart/update_phone
lib/screens/update_email/update_email_screen.dart/update_email
lib/screens/code_verification/phone/code_verification_by_phone_screen.dart/code_verification_by_phone
lib/screens/code_verification/email/code_verification_by_email_screen.dart/code_verification_by_email
lib/screens/seller_profile/seller_profile/widget/seller_contact_details.dartEntrada perfil vendedor
lib/screens/login/login_manager.dartEntrada pós-login

Providers

ArquivoURL base
lib/providers/update_phone/update_phone_provider.dartchange-cellphone
lib/providers/update_email/update_email_provider.dartchange-email
lib/providers/code_verification/phone/code_verification_by_phone_provider.dartURL dinâmica
lib/providers/code_verification/email/code_verification_by_email_provider.dartURL dinâmica

Models

ArquivoDescrição
lib/models/update_phone/update_phone_request.dartRequest change-cellphone
lib/models/update_phone/update_phone_response.dartResposta change-cellphone
lib/models/update_email/update_email_request.dartRequest change-email
lib/models/update_email/update_email_response.dartResposta change-email
lib/controllers/forgot_password/send_validate_code_request.dartRequest envio de código
lib/controllers/forgot_password/send_validation_code_response.dartResposta envio de código
lib/models/code_verification/validate_code_request.dartRequest validação de código
lib/models/code_verification/validate_code_response.dartResposta validação de código
lib/models/user/user.dartisContactUpdated, flags de confirmação

Serviços e infraestrutura

ArquivoDescrição
lib/services/app_essential_data_service.dartupdateSellerPhone, updateSellerEmail
lib/services/firebase_remote_config_service.dartisUpdateContactEnabled, recoverMethodsToken
lib/middlewares/http/recover_methods_interceptor.dartInjeta x-api-key
lib/shared/utils/api_utils.dartConstantes de endpoints
lib/shared/routes/app_routes.dartConstantes de rotas
lib/shared/routes/app_pages.dartRegistro de páginas GetX
lib/screens/code_verification/by_method/code_verification_counter_service.dartControle de tentativas SMS