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)
- Abre o login na aba Telefone (a inicial) e digita o número.android@refactor-2.0 activities/LoginActivity.kt:135
- 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
- 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
- Sem parceiro no token: vai direto às permissões (onboarding).android@refactor-2.0 domain/boot/BootRoute.kt:119-123
Cliente Pitzi
- 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.
- 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)
- O servidor responde
authMethod = initialPassworde o app pede a Senha inicial.android@refactor-2.0 LoginViewModel.kt:297-298; ios@develop AuthenticationPhoneInteractor.swift:121 - Telefone de recuperação com código SMS.android@refactor-2.0 LoginViewModel.kt:177 (GoToRecoveryPhone); ios@develop AuthenticationPasswordInitialPresenter.swift:77
- 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
- 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
| Ponto | Cliente direto | Cliente Pitzi |
|---|---|---|
| Identificador | Número de telefone | Có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 credencial | Código por SMS | Senha 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 caminho | O 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 entrar | Permissões | Boas-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/.
- 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.
- 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.
- 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.
- 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 senhaiOS (Password/Authentication/Register/PasswordAuthenticationRegister.xcstrings): Crie sua senha; campos Informe uma senha / Confirme sua senha; botão Criar senha; sucesso Senha criada com sucesso!
- 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
- Banco de dados (backend). O branding fica na tabela
foursafe.partner, coluna JSONwelcomeMessage(cores, fonte, botão, layout e textos por idioma), e o logo na tabelafoursafe.partner_asset(tipo "logo").lib@develop src/entities/partner.entity.ts:119, 186; src/entities/partner-asset.entity.ts:17 - Backend, leitura.
PartnerBrandingService.getDetailsbusca o parceiro pelo id (senão 404 PARTNER_NOT_FOUND) e o logo; fundo ausente ou inválido vira #001B66; olayouté o salvo emwelcomeMessage.layoutse 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 - API, rota.
GET /v1/partner/:id/detailsexige 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 - App, chamada. Android:
DeviceService.partnerDetails(GET em URL montada com o partnerId do token), chamada peloLoadingViewModel.checkPartnerWelcome. iOS:PartnerService.details(id:)em/v1/partner/\(id)/details, chamada porfetchPartnerDetailslogo 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 - 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 - 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 - Tela, fundo. Layouts A e B: o fundo é
backgroundColorda API (padrão #001B66), aplicado porroot.setBackgroundColorno Android e porPartnerWelcomeBackgroundViewno 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 - Tela, logo e textos no layout C. Vêm da API o logo e os textos
titleHighlightebuttonActivate(Android) ou tambémtitle(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
- 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) - 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 - 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 - Apagada e licença ativada. Ao gravar a senha própria (set-password), o backend guarda o hash da nova senha, põe
firstTokenLogin = nulle 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 anterior | O que o código faz |
|---|---|
| Quem esquece a senha inicial é orientado a falar com o suporte | Nã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 tentativas | Android 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 CPF | Regra 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 PTZ | Confere: 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 backend | Os 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 acesso | O 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 ignora | INITIAL_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 senha | Confere 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
- O valor de
welcomeMessage.layout(e das cores) na linha da Pitzi emfoursafe.partner, em produção: precisa de leitura do banco, que não foi feita. - Se o passo do telefone de recuperação falha no Android 2.0 (ver Incoerências): precisa de teste em aparelho.