Pular para o conteúdo principal

Status: Approved · v2 · SPEC-ARCH-FRONTEND-001

depends_on: SPEC-CONTRACTS-RESPONSE-001, SPEC-MOCKS-CONTRACTS-001

used_by: IS-ZERO-00.2, IS-MVP-01.1, IS-MVP-16.1

Arquitetura de services e dados no frontend

Camadas compartilhadas entre Expo e Next para trocar mocks pela API sem reescrever telas.

Arquitetura

Fluxo canônico

Route/Page
→ Screen/Feature Container
→ Feature Hook
→ Domain Service
→ HttpClient
→ ApiClient | MockClient
  • Routes resolvem parâmetros e composição de alto nível.
  • Screens coordenam estados visuais e componentes; não conhecem URLs.
  • Hooks convertem ApiResponse em idle/loading/success/empty/error, mutations e refetch.
  • Services expõem linguagem do domínio e conhecem paths/request/response.
  • Clients executam transporte e autenticação.
  • Componentes de @raizfc/ui recebem props e nunca buscam dados.

Estrutura

packages/shared/src/
clients/
services/
hooks/
state/
navigation/
errors/
utils/

HttpClient

export interface HttpClient {
get<T extends object>(path: string, query?: QueryParams): Promise<ApiResponse<T>>;
post<T extends object>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
patch<T extends object>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
put<T extends object>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
delete<T extends object>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
}

Cache MVP

Cache simples em memória por query key, TTL curto para páginas públicas e invalidation explícita após mutations. Não duplicar server data em Zustand. TanStack Query pode ser adotado após a primeira capability se resolver um problema observado e for compatível com mobile/web.

Erros

Um mapper central transforma códigos em título, mensagem, ação e severity. Formulários recebem fieldErrors; 401 ativa AuthIntent; 403 explica permission; 404/merged/suspended usam estados específicos.

Auth e armazenamento

  • ApiClient recebe getAccessToken e onUnauthorized; não importa storage concreto.
  • Mobile adapter usa SecureStore; web usa cookies/sessão conforme estratégia do app.
  • Refresh é coordenado para evitar múltiplas renovações simultâneas.

Uploads

  • Hook pede presign, envia para URL e confirma asset.
  • Progress é UI state; asset final vem do backend.
  • Falha de upload não cria entidade parcial sem regra explícita.

Testes

  • Service com fake HttpClient.
  • Hook com service injetado/provider.
  • Screen com hooks/providers mockados.
  • Contract assertions para paths e payloads críticos.

Anti-padrões

  • fetch/axios em screen.
  • Endpoint string em component/hook.
  • Fixture importada por app.
  • Toast/navigation dentro de service.
  • DTO privado em página pública.

Critérios de aceite

  • Mock/API trocados por factory/config.
  • Loading/empty/error consistentes.
  • Apps não importam mocks diretamente.
  • Services são por domínio e testáveis.