Stack tecnológica
| Camada | Tecnologia |
|---|---|
| Framework | Next.js 16.0.7 (App Router) |
| Linguagem | TypeScript 5.x |
| UI / Estilos | Tailwind CSS v4.1, Radix UI, shadcn/ui pattern |
| Ícones | Lucide React |
| Animações | Framer Motion, tw-animate-css |
| Gráficos | Recharts |
| Notificações | Sonner (toast) |
| Estado global | Zustand v5 |
| Estado do servidor | TanStack Query v5 (React Query) |
| HTTP Client | Axios |
| Formulários | React Hook Form + Zod + @hookform/resolvers |
Estrutura de pastas
Padrão de Feature
Cada domínio emsrc/features/ segue a mesma estrutura interna:
services/ faz chamadas HTTP.
Autenticação e Sessão
Fluxo de tokens
accessToken nunca é salvo em localStorage. Fica exclusivamente no Zustand (useAuthStore) em memória.
Silent Refresh (ao recarregar a página)
Quando o usuário recarrega (F5), o Zustand é reiniciado e oaccessToken é perdido. O AuthProvider e o ProtectedLayout detectam esse estado e automaticamente chamam POST /auth/refresh usando o cookie HttpOnly:
Interceptor Axios (src/shared/lib/axios.ts)
Toda requisição passa pelo interceptor que:
- Injeta
Authorization: Bearer <accessToken>no header. - Injeta
x-tenant-id: <tenantId>no header. - Se receber
401, tenta renovar o token automaticamente via/auth/refresh. - Enquanto renova, coloca requisições paralelas em fila e as reexecuta após sucesso.
- Se o refresh falhar, chama
logout()e a fila de requisições é rejeitada.
Proteção de rotas
Todas as rotas emapp/(protected)/** requerem autenticação. O ProtectedLayout redireciona para /login se o usuário não estiver autenticado após a tentativa de silent refresh.
Estado Global (Zustand)
| Store | Localização | Responsabilidade |
|---|---|---|
useAuthStore | features/auth/store/auth-store | user, accessToken, isRefreshing, logout |
useTenantStore | features/tenant/store/tenant-store | Dados do tenant ativo, loadTenant() |
Fetching de dados (TanStack Query)
OQueryProvider está no root layout. Toda busca de dados de servidor usa useQuery e mutações usam useMutation, sempre encapsulados em custom hooks dentro de features/<nome>/hooks/.
Convenção:
Formulários e Validação
- React Hook Form gerencia o estado dos formulários.
- Zod valida os dados (schemas em
features/<nome>/schemas.ts). - A validação no frontend é limitada a UX e campos obrigatórios. Regras de negócio vêm do backend via resposta da API.
Convenções de código
| O que | Convenção |
|---|---|
| Diretórios | kebab-case |
| Componentes | PascalCase.tsx |
| Hooks / Services | camelCase.ts (ex: useProducts.ts, productService.ts) |
| Tipos | PascalCase (ex: Product, ProductResponse) |
'use client' | Apenas em leaf components (formulários, tabelas, interatividade) |
| Axios direto | ❌ Nunca em componentes ou hooks. Apenas em services/ |
| Estado global ad-hoc | ❌ Nunca use window, localStorage, ou singletons implícitos |
Módulos do frontend
Os 27 domínios emsrc/features/ correspondem às seguintes áreas do sistema:
| Feature | Descrição |
|---|---|
auth | Login, logout, sessão |
catalog | Catálogo de produtos |
products | Gestão de produtos |
products-dashboard | Dashboard de produtos |
inventory | Controle de estoque |
listings | Anúncios dos marketplaces |
integrations | Conexões OAuth com marketplaces |
imports | Importação de NF-e |
orders | Gestão de pedidos |
orders-dashboard | Dashboard de pedidos |
financial | Módulo financeiro |
fiscal | Módulo fiscal |
logistics | Logística |
dispatch | Expedição |
returns | Devoluções |
suppliers | Fornecedores |
partners | Parceiros |
brands | Marcas |
registries | Cadastros gerais |
tenant | Dados e configurações do tenant |
organization | Organização / empresa |
subscription/subscriptions | Planos e assinaturas |
plans | Planos disponíveis |
social-catalogs | Catálogos sociais |
social-catalogs-dashboard | Dashboard de catálogos sociais |
Variáveis de ambiente
| Variável | Obrigatória | Descrição |
|---|---|---|
NEXT_PUBLIC_API_URL | ✅ | URL base da API backend (ex: https://api.omnidom.com) |
NEXT_PUBLIC_APP_NAME | Nome exibido na interface (padrão: Hub Marketplace) |
.env.local para desenvolvimento local. Em produção, configure no serviço de hospedagem (Vercel, etc.).