Skip to content

Arquitetura Multi-Persona (Superapp)

Estrutura que prepara o app mobile para servir duas experiências dentro de um único binário Expo (Metro, sem microfrontend remoto): a experiência de Contrato (prestador por contrato, hoje funcional) e a experiência de Tomador (borrower, em construção).

Eixo da arquitetura

ExperiênciaPapel (UserRole)Escopo
ContratoproviderEntrada por contrato (/me/provider-contracts). Abas Horas, Compliance, Notas Fiscais, Histórico, Documentos.
TomadorborrowerÁrea completa de gestão (Dashboard, Contratos, Templates, Monitoramento, Prestadores, Equipe, Relatórios).

PF/PJ não é eixo de arquitetura. Dentro da experiência de Contrato, a natureza da parte (legal_entity / natural_person) é um discriminador de domínio derivado de contract_parts (XOR companyId/userId), nunca uma rota ou módulo separado. Ver ../../business/contratos.md.

Rotas (app/)

app/
├── _layout.tsx              # Providers + <RootGate/> + Stack[(auth),(access),(main)]
├── (auth)/
│   ├── _layout.tsx
│   └── login.tsx            # usa useAuth().login
├── (access)/
│   ├── _layout.tsx
│   └── index.tsx            # picker estilo Vue: "Meus contratos" / "Minhas empresas"
└── (main)/
    ├── _layout.tsx          # Stack[contract, borrower]
    ├── contract/            # experiência atual (URLs /contract/*)
    │   ├── _layout.tsx
    │   ├── (tabs)/...
    │   └── HoursEntry | HoursDetail | InvoiceDetail | InvoiceEmit
    │       | ComplianceDetail | Notifications | Settings
    └── borrower/            # NOVO  scaffold
        ├── _layout.tsx
        └── (tabs)/index.tsx

contract e borrower são segmentos reais (não route groups) para evitar colisão de (tabs) e ambiguidade de rota inicial. URLs: /contract/... e /borrower/....

Gate de navegação (RootGate)

modules/app/components/RootGate decide o redirect a partir do useAuth():

  1. não autenticado → /(auth)/login
  2. autenticado sem experiência escolhida → /(access)
  3. autenticado com experiência → /contract ou /borrower

O AuthContext deixou de renderizar LoginScreen diretamente; ele só expõe estado (isAuthenticated, experience, login, selectExperience, clearExperience). A escolha de experiência é persistida em SecureStore (EXPERIENCE_KEY) e limpa no logout.

Módulos

MóduloResponsabilidade
modules/contractExperiência de Contrato (refactor de modules/provider).
modules/borrowerExperiência de Tomador scaffold (stores/services/hooks/components/contexts/screens).
modules/accessPicker de experiência. Reutiliza getProviderContractsService; tab de empresas é placeholder até o módulo borrower evoluir.
modules/auth modules/notificationInfra de dominio (auth, push).
components/ui/UI compartilhada entre modulos (shell, layout, primitivos).
modules/appLegado — migrar UI para components/ui/ e escopo para modulos donos.

Pendências do módulo borrower

  • Listagem de empresas em (access) hoje usa a empresa única já persistida no AuthContext; deve ser substituída por uma listagem real quando o módulo borrower for implementado.
  • domain/auth ganhou AppExperience (contract | borrower) e EXPERIENCE_KEY.