Onboarding completo para solicitação de crédito empresarial, com múltiplas etapas, regras condicionais e fluxo real de uma fintech.
O Stepay Onboarding é um fluxo de solicitação de empréstimo empresarial com múltiplas etapas, caminhos condicionais e lógica de negócio complexa. O objetivo da refatoração foi reconstruir a aplicação do zero com padrões de mercado modernos, mantendo a fidelidade ao produto original.
O projeto cobre:
- Coleta de dados pessoais e empresariais
- Simulação de crédito com slider interativo
- Validação de CPF com lógica condicional (sócio único, vários sócios, fora do quadro)
- Motor de crédito mockado com 4 cenários (aprovado, análise manual, negado, 90 dias)
- Gestão de documentos por upload
- Confirmação de proposta com dados bancários
- Fluxos de desistência com coleta de motivo
- Sistema white-label com tema dinâmico por cliente
O projeto é organizado por domínio de negócio, não por tipo de arquivo. Cada etapa do fluxo é um módulo isolado com suas próprias páginas, schemas, hooks e componentes.
src/
├── app/ # Router, providers, configuração global
├── features/
│ └── onboarding/
│ ├── primeira-etapa/
│ ├── segunda-etapa/
│ ├── terceira-etapa/
│ └── quarta-etapa/
├── shared/ # Componentes, hooks e utilitários globais
├── store/ # Zustand stores
└── theme/ # Sistema white-label
Essa estrutura facilita leitura, manutenção e remoção de módulos inteiros sem impacto no restante da aplicação.
Todos os formulários utilizam React Hook Form + Zod. Cada página de formulário tem seu próprio schema tipado — o tipo do formulário é inferido diretamente do schema, eliminando duplicação entre tipo e validação.
// O tipo é derivado do schema — zero duplicação
export const dadosPessoaisSchema = z.object({ ... });
export type DadosPessoaisForm = z.infer<typeof dadosPessoaisSchema>;O estado do onboarding é persistido em localStorage com criptografia AES via crypto-js. Em caso de refresh ou navegação, o usuário retorna exatamente onde parou.
Zustand state → JSON.stringify → AES encrypt → localStorage
localStorage → AES decrypt → JSON.parse → Zustand state
O DadosModel é estruturado com objetos aninhados por etapa. Isso mantém o setModel nas páginas limpo e previsível:
// Em qualquer página de formulário — sempre o mesmo padrão
setModel({ ...(model ?? {}), detalhesPedido: values });Padrões repetidos foram extraídos em componentes base ao invés de copiar código entre páginas:
| Componente | Reutilizado em |
|---|---|
IdentificacaoBase |
Identificacao + IdentificacaoMaisSocios |
ProximosPassosBase |
ForaQuadro + Socios + Socio |
DesistenciaBase |
3 telas de desistência (3ª e 4ª etapas) |
PropostaResumoCard |
Confirmacao + ConclusaoSolicitacao + VisualizacaoSolicitacao |
SimulacaoCard |
Todas as telas de próximos passos |
Lógica de negócio fica em hooks, não nas páginas:
useHydrateForm— hidrata qualquer form a partir do store com uma linhauseMockCpfValidation— lógica condicional de validação de CPF (sócio único / vários / fora do quadro)useMockMotorCredito— decisão do motor de crédito (aprovado / análise manual / negado / 90 dias)useShareLink— geração de link de compartilhamento para sóciosuseMockProposta— dados financeiros derivados do store para a quarta etapa
O tema é resolvido automaticamente na seguinte ordem de prioridade:
querystring (?client=X) → localStorage → variável de ambiente → hostname → default
Permite múltiplos clientes (tenants) sem rebuild — basta apontar para o hostname correto.
| Categoria | Tecnologia |
|---|---|
| Framework | React 18 + TypeScript (strict) |
| Build | Vite |
| Estado global | Zustand + persist middleware |
| Persistência | AES encrypt + localStorage |
| Formulários | React Hook Form + Zod |
| UI | Material UI v7 |
| Roteamento | React Router v6 (lazy loading + Suspense) |
| Máscaras | React Number Format |
| HTTP | Axios (preparado para integração) |
| Estilo | styled-components + sx prop (MUI) |
INÍCIO
└── Dados Pessoais
└── Detalhes do Pedido
└── Simulação
└── Solicitar CPF
└── Consulta Motor
├── Aprovado ──────────── Confirmação ──── Segunda Etapa
├── Análise Manual ─────── Análise Manual
├── Negado ─────────────── Pedido Negado
└── 90 Dias ────────────── Modal (finalizar)
SEGUNDA ETAPA
└── Identificação do sócio
├── Fora do quadro ──── Identificacao ──── ConclusaoNaoSocio
├── Sócio único ──────── ProximosPassosSocio ──── Terceira Etapa
└── Vários sócios ────── IdentificacaoMaisSocios ── ProximosPassosSocios ── Terceira Etapa
TERCEIRA ETAPA
└── Documentos
└── Criar Senha
└── Solicitação Concluída
QUARTA ETAPA
└── Confirmação da Proposta
├── Aceitar ─── Conclusão da Solicitação
└── Negar ───── Desistência Proposta
Cada etapa possui também caminhos de desistência e páginas de estado (pedido cancelado, expirado).
O projeto está estruturado para integração com backend real sem refatoração de páginas. A lógica mockada fica isolada em hooks e constantes com comentários // TODO:
Para testar os cenários localmente:
| Último dígito do CNPJ | Cenário |
|---|---|
| 1, 2 ou 3 | ✅ Aprovado |
| 4, 5 ou 6 | 🔍 Análise manual |
| 7, 8 ou 9 | ❌ Negado |
| 0 | ⏳ Proposta nos últimos 90 dias |
| Soma dos dígitos do CPF | Cenário |
|---|---|
| Par | Sócio único |
| Ímpar | Fora do quadro societário |
| Último dígito 0 | Vários sócios |
# instalar dependências
npm install
# rodar em desenvolvimento
npm run dev
# build de produção
npm run buildPara testar com um cliente específico (white-label):
# via subdomínio
http://clientB.localhost:5173
# via querystring
http://localhost:5173/?client=clientA
# via localStorage (console do browser)
localStorage.setItem("app-theme", "clientC")
location.reload()
# via variável de ambiente
VITE_CLIENT=clientC npm run dev- Fluxo completo de onboarding real
- Arquitetura escalável baseada em domínio
- Domínio de tipagem de formulários
- Gerenciamento de estado global com persistência criptografada
- Separação clara entre regras de negócio (hooks), estado (store) e apresentação UI
- Sistema multi-tenant com tema dinâmico
- Preparado para integração com API (backend)
O projeto continuará evoluindo com foco em robustez e integração com serviços reais:
- Implementação de testes automatizados (unitários e de integração) com foco nas regras de negócio e fluxos críticos
- Integração com backend real para substituição dos mocks de crédito, validação e proposta
- Tratamento avançado de estados assíncronos (loading, erro, retry)
- Observabilidade e logging para análise de comportamento do usuário
- Melhorias de acessibilidade (a11y) e experiência do usuário