4Safe · documento interno de parceiros · Ver o tutorial animado

Jornada do parceiro: cliente Pitzi

Hoje o único parceiro é a Pitzi (no app aparece como "Pitzi"). O código é a fonte da verdade. Referências: android = dtb-4safe-android@origin/refactor-2.0, ios = dtb-4safe-ios@origin/develop, api = dtb-4safe-api@origin/develop (os ramos mais recentes de cada repositório em 2026-10-19). Caminhos do Android partem de app/src/main/java/br/net/datamob/foursafe/. Dados de exemplo são fictícios.

Mapa da jornada: cliente direto x cliente Pitzi

Cliente direto (sem parceiro)

  1. Abre o login na aba Telefone (a inicial) e digita o número.android@refactor-2.0 activities/LoginActivity.kt:135
  2. Toca Continuar; o servidor responde se o usuário existe e qual método vale (identify).android@refactor-2.0 presentation/login/LoginViewModel.kt:295-301
  3. Método padrão (OTP): código por SMS e criação da própria senha.android@refactor-2.0 LoginViewModel.kt:299-300; activities/ValidateOTPActivity.kt:329-334
  4. Sem parceiro no token: vai direto às permissões (onboarding).android@refactor-2.0 domain/boot/BootRoute.kt:119-123

Cliente Pitzi

  1. Informado pelo produto (Datamob): a Pitzi avisa o cliente, em comunicado próprio antes ou no primeiro login, do código (PTZ + Order Id) e de que a senha inicial são os 4 últimos dígitos do CPF. Fato de domínio; não está no código.
  2. Login na aba Código com o código de ativação.android@refactor-2.0 LoginActivity.kt:558; ios@develop Authentication/Phone/AuthenticationPhone.xcstrings (MethodCode)
  3. O servidor responde authMethod = initialPassword e o app pede a Senha inicial.android@refactor-2.0 LoginViewModel.kt:297-298; ios@develop AuthenticationPhoneInteractor.swift:121
  4. Telefone de recuperação com código SMS.android@refactor-2.0 LoginViewModel.kt:177 (GoToRecoveryPhone); ios@develop AuthenticationPasswordInitialPresenter.swift:77
  5. Cadastro da própria senha e entrada automática.android@refactor-2.0 ValidateOTPActivity.kt:329; CreatePasswordViewModel.kt:138-152; ios@develop PhoneRecoveryRegisterPresenter.swift:74-77
  6. Com parceiro no token: busca os detalhes e mostra as boas-vindas da Pitzi antes das permissões.android@refactor-2.0 BootRoute.kt:119-123, 137-140; LoadingViewModel.kt:469-475

Diferenças

PontoCliente diretoCliente Pitzi
IdentificadorNúmero de telefoneCódigo de ativação com prefixo PTZ (cards #2483, #2498); o código aceita qualquer comprimento, e "Order Id" só consta nos cards e nos exemplos (PTZ1234567810)android@refactor-2.0 res/layout/activity_login.xml:141; api@develop docs/swagger-parceiro-4safe.yaml:522
Primeira credencialCódigo por SMSSenha inicial emitida pela Pitzi (card #2502); o app a trata como texto opacoandroid@refactor-2.0 data/remote/dto/InitialPasswordInput.kt:12-14; api@develop docs/swagger-parceiro-4safe.yaml:545
Quem decide o caminhoO servidor (authMethod); ausente vale OTPandroid@refactor-2.0 data/remote/dto/AccessIdentifyOutput.kt:27
Validar a senha inicial-Não abre sessão nem consome a senhaandroid@refactor-2.0 InitialPasswordInput.kt:5-10; api@develop src/modules/auth/controllers/auth.controller.ts:204-228
Bloqueio-5 erros consecutivos bloqueiam a licença de vezapi@develop assets/4Safe_Integracao_Parceiro.html:198. Android mostra "Ativação bloqueada"; o iOS não tem tratamento próprio (ver Incoerências)
Depois de entrarPermissõesBoas-vindas com a marca da parceira (layouts A, B ou C)android@refactor-2.0 BootRoute.kt:137-140

Como um cliente Pitzi faz login: textos reais das telas

Quando Android e iOS diferem, os dois aparecem. Android: res/values-pt-rBR/strings.xml. iOS: arquivos .xcstrings em 4Safe/Sources/Screens/.

  1. Código.
    Android (strings.xml:648-652): abas Telefone / Código; título Informe seu código para continuar; campo Código de ativação; ajuda Digite o código completo, incluindo as letras iniciais.
    iOS (Authentication/Phone/AuthenticationPhone.xcstrings): Código / Telefone; Informe seu código para continuar; Código de ativação; mesma ajuda.
  2. Senha inicial.
    Android (strings.xml:653-655): rótulo e campo Senha inicial; ajuda Ela vale só neste primeiro acesso. Depois você cria a sua.
    iOS (Authentication/PasswordInitial/AuthenticationPasswordInitial.xcstrings): título Informe sua senha inicial; texto Você recebeu essa senha da seguradora. Ela vale só neste primeiro acesso.; ajuda Depois deste acesso você cria a sua própria senha.; erro Acesso não confirmado: Os dados informados não estão corretos. Tente novamente.
  3. Telefone de recuperação e SMS.
    Android (strings.xml:656-657): Cadastre seu telefone para continuar; Precisamos cadastrar o seu telefone para caso você precise recuperar seu acesso. Vamos enviar um código por SMS para confirmar que este telefone é válido.
    iOS (Phone/Recovery/Register/PhoneRecoveryRegister.xcstrings): mesmo título e mesmo texto; botão Salvar e confirmar por SMS; ajuda Usamos este número apenas para recuperar seu acesso. Ele não é compartilhado.
  4. Criar a própria senha.
    Android (strings.xml:75-79): Crie sua senha; Você irá utilizar essa senha sempre que precisar fazer login no aplicativo.; botão Criar senha
    iOS (Password/Authentication/Register/PasswordAuthenticationRegister.xcstrings): Crie sua senha; campos Informe uma senha / Confirme sua senha; botão Criar senha; sucesso Senha criada com sucesso!
  5. Bloqueio por tentativas. Android (strings.xml:672, 676-677): Ativação bloqueada; Houve tentativas demais, e este código de ativação não pode mais ser usado. Fale com a sua seguradora para receber um novo.; botão Voltar ao login. iOS: sem texto próprio.

Como a tela da Pitzi recebe o fundo

  1. Banco de dados (backend). O branding fica na tabela foursafe.partner, coluna JSON welcomeMessage (cores, fonte, botão, layout e textos por idioma), e o logo na tabela foursafe.partner_asset (tipo "logo").lib@develop src/entities/partner.entity.ts:119, 186; src/entities/partner-asset.entity.ts:17
  2. Backend, leitura. PartnerBrandingService.getDetails busca o parceiro pelo id (senão 404 PARTNER_NOT_FOUND) e o logo; fundo ausente ou inválido vira #001B66; o layout é o salvo em welcomeMessage.layout se for A, B ou C, senão o padrão do backend, que é B.lib@develop src/services/partner-branding.service.ts:186-228; src/entities/partner.entity.ts:116-117
  3. API, rota. GET /v1/partner/:id/details exige o JWT interno e que o :id seja o partnerId do token, e delega ao serviço acima.api@develop src/modules/partner/controllers/partner-app.controller.ts:30-51
  4. App, chamada. Android: DeviceService.partnerDetails (GET em URL montada com o partnerId do token), chamada pelo LoadingViewModel.checkPartnerWelcome. iOS: PartnerService.details(id:) em /v1/partner/\(id)/details, chamada por fetchPartnerDetails logo após o login. Falha ou ausência cai silenciosamente nas permissões.android@refactor-2.0 data/remote/api/DeviceService.kt:93; presentation/loading/LoadingViewModel.kt:469-475; ios@develop Common/Service/Partner/PartnerApiEndpoint.swift:35, PartnerService.swift:19; Screens/Authentication/Password/AuthenticationPasswordInteractor.swift:189
  5. App, modelo. Campos: id, name, backgroundColor, buttonBackgroundColor, buttonFontColor, fontColor, layout, logo{contentBase64,mimeType}, updatedAt, welcomeMessage{title, titleHighlight, buttonActivate, subtitle, text, locale, resolvedFrom}. O logo vem em base64 dentro do JSON.android@refactor-2.0 data/remote/dto/PartnerDetails.kt:24-34, 71-79; ios@develop Common/Service/Partner/Response/ApiEndpointPartnerDetailsResponse.swift:1-27
  6. App, layout. layout "A", "B" ou "C"; ausente ou desconhecido vira A. A tela só aparece se há mensagem de boas-vindas ou se o layout é C.android@refactor-2.0 PartnerDetails.kt:37-47, data/remote/dto/PartnerWelcomeLayout.kt; BootRoute.kt:137-140; ios@develop Screens/Partner/Welcome/Enum/PartnerWelcomeLayout.swift:8
  7. Tela, fundo. Layouts A e B: o fundo é backgroundColor da API (padrão #001B66), aplicado por root.setBackgroundColor no Android e por PartnerWelcomeBackgroundView no iOS. Layout C ignora o fundo da API nas duas plataformas: usa #001B66 fixo.android@refactor-2.0 activities/WelcomeActivity.kt:78-83, 116-121; res/layout/activity_welcome_c.xml:12; res/values/colors.xml:66; ios@develop Screens/Partner/Welcome/PartnerWelcomePresenter.swift:54-62; PartnerWelcomeView.swift:21; Layouts/LayoutC/PartnerWelcomeLayoutCDefault.swift:5
  8. Tela, logo e textos no layout C. Vêm da API o logo e os textos titleHighlight e buttonActivate (Android) ou também title (iOS); o resto é fixo no app.android@refactor-2.0 WelcomeActivity.kt:178-212; ios@develop PartnerWelcomePresenter.swift:95-103

Qual layout a Pitzi recebe em produção? Vem da coluna welcomeMessage.layout da linha da Pitzi em foursafe.partner; o valor real só se vê lendo o banco, o que não foi feito. O card pede o Layout C (cards #1845 e #1846). Atenção: se o registro da Pitzi tiver layout C, a cor de fundo gravada no banco não tem efeito nenhum nos dois apps (usam #001B66 fixo); ela só vale nos layouts A e B.

Ciclo de vida da senha inicial

  1. Criada. A Pitzi envia a senha ao criar a licença; o backend grava só o hash em firstTokenLogin (a licença nasce pendente).lib@develop src/services/license.service.ts:710 (em lote: :1141)
  2. Validada. POST /v1/auth/validate-initial-password: código inexistente e senha errada dão o mesmo 401; cada erro soma uma tentativa; a senha certa zera o contador. Não abre sessão.lib@develop src/services/auth.service.ts:1499-1545; api@develop auth.controller.ts:213-228
  3. Bloqueada. Com 5 tentativas erradas, o backend responde 422 INITIAL_PASSWORD_LOCKED. O mesmo limite vale no set-password quando a senha inicial é usada como credencial.lib@develop auth.service.ts:1489, 1516-1524, 2040-2053
  4. Apagada e licença ativada. Ao gravar a senha própria (set-password), o backend guarda o hash da nova senha, põe firstTokenLogin = null e zera as tentativas; a licença de código passa de pendente para ativa. A senha inicial deixa de existir.lib@develop auth.service.ts:2080-2085, 2090-2096

A página cita o develop da biblioteca @datamob/4safe (16/10/2026), não necessariamente a versão publicada que a API fixa (0.0.1-dev-19751, api@develop package.json).

Incoerências encontradas

Card / reunião / versão anteriorO que o código faz
Quem esquece a senha inicial é orientado a falar com o suporteNão existe esse texto. iOS: erro genérico "Acesso não confirmado" e frase "Você recebeu essa senha da seguradora". Android: "Fale com a sua seguradora" só depois do bloqueio.ios@develop AuthenticationPasswordInitial.xcstrings; AuthenticationPasswordInitialInteractor.swift:82-83; android@refactor-2.0 strings.xml:672
iOS e Android tratam igual o bloqueio por tentativasAndroid tem fluxo próprio (INITIAL_PASSWORD_LOCKED); no iOS qualquer falha cai no mesmo alerta genérico.android@refactor-2.0 LoginViewModel.kt:257; ios@develop AuthenticationPasswordInitialInteractor.swift:82-83
Senha inicial = 4 últimos dígitos do CPFRegra da Pitzi, não do app nem da API: a API aceita a senha "exatamente como você quer entregá-la" e a grava como hash.api@develop docs/swagger-parceiro-4safe.yaml:545; docs/swagger-global-4safe.yaml:602
Código = Order Id com prefixo PTZConfere: o código é o prefixo do parceiro mais o número de ordem dele; o campo não se chama orderId porque já inclui o prefixo (exemplo PTZ193737). O app só valida o prefixo.api@develop docs/swagger-parceiro-4safe.yaml:127-132
Padrão de layout (apps) x backendOs dois apps tratam layout ausente como A; o backend, quando não há layout salvo, devolve B.lib@develop partner.entity.ts:117; ios@develop PartnerWelcomeLayout.swift:8
Comentário do WelcomeActivity: layout C só recebe o logo da API (#2965)Comentário velho: o código lê também titleHighlight e buttonActivate. O código vale.android@refactor-2.0 WelcomeActivity.kt:57 x 193-214
Telefone de recuperação no primeiro acessoO backend aceita Basic no primeiro acesso, mas qualquer cabeçalho que comece com "Bearer " vai para a validação de sessão. O Android 2.0 envia Bearer nas duas chamadas (send-otp e vínculo), com o token vazio quando ainda não há sessão. Pelo código, o passo do cliente Pitzi deve falhar com 401. Comentários do app dizem que as rotas só são usadas no Perfil, o que não vale para o primeiro acesso. Não executado: precisa de teste real.android@refactor-2.0 presentation/recovery/RecoveryPhoneViewModel.kt:123-131; presentation/otp/ValidateOtpViewModel.kt:152-157; api@develop src/common/auth/basic-or-session.guard.ts
Códigos de erro do backend que o app ignoraINITIAL_PASSWORD_LOCKED no iOS (alerta genérico). As rotas chamadas pelos apps (identify, validate-initial-password, recovery-phone, recovery-phone/send-otp, set-password, partner details) existem todas na API.api@develop auth.controller.ts:109, 190, 213, 240, 304
Layout C não lê o texto da API (versão anterior da página)Vale só para o ramo main do Android. No refactor-2.0 e no iOS o C lê titleHighlight e buttonActivate.android@refactor-2.0 WelcomeActivity.kt:194-212
Ordem iOS (card #2503): código, senha inicial, telefone com OTP, própria senhaConfere com o código, e é a mesma do Android.ios@develop AuthenticationPhoneInteractor.swift:121; AuthenticationPasswordInitialPresenter.swift:77; PhoneRecoveryRegisterPresenter.swift:74-77, 119

Não confirmado