Este guia assume que você leu o Setup do Frontend e já tem o projeto rodando localmente.
Visão geral do sistema
O OmniDom é uma plataforma de gestão para sellers de marketplace. É composta de dois repositórios independentes:| Repositório | Tecnologia | Porta padrão | Responsabilidade |
|---|---|---|---|
hub-marketplace | Next.js 16 | 3001 | Interface do usuário (SPA) |
| Backend (NestJS) | NestJS + PostgreSQL | 3000 | API REST + regras de negócio |
Como é uma feature completa
Toda funcionalidade no frontend segue este fluxo:Criando uma nova feature
1. Criar a estrutura de pastas
2. Definir os tipos
3. Criar o service
4. Criar os hooks
5. Criar os componentes
6. Criar a página no App Router
Pontos críticos para entender
Autenticação (leia com atenção)
O token de acesso fica em memória (Zustand). Ao recarregar a página (F5), o Zustand é zerado. OProtectedLayout detecta isso e faz um silent refresh automático usando o cookie HttpOnly. Isso significa:
- Nunca salve o token em localStorage — quebrará a segurança.
- Não tente ler o token diretamente — use
useAuthStore().accessTokense precisar. - O interceptor Axios cuida de tudo automaticamente.
Multi-tenancy
Cada usuário pertence a um tenant. OtenantId é resolvido no login e armazenado no useAuthStore (via user.tenantId) e também no useTenantStore. O interceptor Axios injeta o header x-tenant-id em todas as requisições automaticamente. Você não precisa fazer nada para isso funcionar nas suas chamadas de API.
Paginação
A API usa cursor-based pagination para todas as listagens. Nunca implemente paginação por offset (page 1, página 2). Use o cursor retornado pelo backend para carregar mais itens.Padrões a seguir
| Situação | Fazer | Não fazer |
|---|---|---|
| Chamada HTTP | Criar service em services/ | Usar Axios diretamente no componente |
| Estado do servidor | TanStack Query (useQuery/useMutation) | useState + useEffect + fetch |
| Estado de UI local | useState | Zustand com estado efêmero |
| Estado global persistente | Zustand | Context API para estado frequente |
| Validação de formulário | Zod schema | Validação manual com if |
| Regra de negócio | Confiar na resposta da API | Reimplementar lógica do backend |
| Estilização | Tailwind + cn() utility | Inline styles, CSS modules |
Boas práticas de PR
- Um PR por feature ou fix — PRs grandes são difíceis de revisar.
- Teste o fluxo completo antes de abrir o PR — login, autenticação e a funcionalidade nova.
- Tipos explícitos — sem
anynão justificado. - Nomeação descritiva —
useCreateProduct, nãouseForm. - Sem
console.logem código de produção.
Perguntas frequentes
Onde fica a lógica de validação de um produto KIT?
Onde fica a lógica de validação de um produto KIT?
No backend. O frontend envia os dados e o backend retorna erro se a regra for violada. O frontend apenas exibe o erro ao usuário.
Como faço para acessar o tenant do usuário logado?
Como faço para acessar o tenant do usuário logado?
tenantId também está disponível em useAuthStore().user?.tenantId.Posso usar SWR ao invés de TanStack Query?
Posso usar SWR ao invés de TanStack Query?
O projeto já tem
swr como dependência, mas o padrão estabelecido é TanStack Query. Use TanStack Query para novas features para manter consistência.Como adiciono uma nova rota protegida?
Como adiciono uma nova rota protegida?
Crie a pasta e o
page.tsx dentro de src/app/(protected)/. A proteção é automática pelo ProtectedLayout.Como lido com erros de API nos componentes?
Como lido com erros de API nos componentes?
TanStack Query expõe
isError e error no hook. Use sonner para notificações toast: