Pular para o conteúdo

8. Conceitos transversais

  • Sessão em cookie gerida pelo Better Auth, configurado uma vez em @moldape/auth (createMoldapeAuth) e instanciado em apps/web/src/lib/auth/auth.ts, com os plugins admin e jwt (o openAPI só fora de produção). O prefixo do cookie é moldape, a validade é de 30 dias e o cookie vale entre subdomínios de moldape.com.
  • No Fastify, requireAuth() lê moldape.session_token (ou a variante __Secure-), busca a sessão no Redis e, se não achar, no PostgreSQL. requireAdmin() exige também role = admin.
  • No Next.js, em duas camadas:
    1. o proxy.ts (antigo middleware) roda só em /home, /studio, /partial e /admin e redireciona para o login quando não há cookie de sessão — sem I/O;
    2. os layouts protegidos validam a sessão de verdade no servidor (@/server/session: requireUser() em (customer)/layout.tsx e requireAdmin() em admin/(panel)/layout.tsx, que também confere o papel). Cookie expirado ou de não-admin cai no login antes de qualquer HTML ser gerado.
  • A autorização dos dados continua na API (requireAuth/requireAdmin).
Camada Ferramenta
Formulários (web) Zod 4 + TanStack Form (lib/schemas.ts)
Entrada HTTP (API) JSON Schema do Fastify (presentation/schemas)
Domínio Value objects (CustomerName, Email, Quantity, códigos de entidade)
  • Exceções de domínio em domain/exceptions são convertidas em respostas HTTP no handler global de erro do server.ts.
  • As respostas seguem um envelope (ResponseFactory.success/error) com success, data e message.
  • Efeitos colaterais não bloqueiam o fluxo principal: falha ao gerar PDF ou enviar e-mail é registrada em log, mas não reverte a mudança de status.
  • @moldape/logger (wrapper isomórfico) e business-event-logger para eventos de negócio.
  • Log de requisições ativado por ENABLE_REQUEST_LOGGING=true, que remove os headers authorization e x-api-key.
  • Health checks: /health, /health/detailed, /health/redis, /health/cache/info.
  • Atenção: há muitos console.log em produção, incluindo um no checkout que imprime nome, endereço e valor do pagamento no console do navegador. Ver Riscos.

O web é SSR primeiro: as páginas (page.tsx) são Server Components que buscam os dados no servidor e entregam o HTML já preenchido; a parte interativa fica em componentes 'use client' colocados ao lado (*-view.tsx).

sequenceDiagram
    participant B as Navegador
    participant N as Next (servidor)
    participant A as order-lifecycle
    B->>N: GET /home/drafts (cookie)
    N->>N: requireUser() — sessão no Better Auth
    N->>A: GET /me/drafts (mesmo cookie repassado)
    A-->>N: rascunhos
    N-->>B: HTML + estado do React Query (dehydrate)
    Note over B: hidrata sem nova requisição;<br/>mutations e polling seguem no cliente
  • Uma definição por consulta: lib/query/queries.ts define chave e função de cada consulta (queryOptions). O servidor usa com os serviços autenticados por cookie (@/server/api), o cliente com clientServices. Como a chave é a mesma, o dado pré-carregado é exatamente o que o hook procura.
  • Prefetch e hidratação: prefetch() + <HydrateClient> (@/server/query). Só consultas concluídas com sucesso vão para o cliente; uma falha no servidor não derruba a página, o cliente tenta de novo.
  • Usuário logado: a consulta currentUser é semeada a partir da sessão no layout da área do cliente; o AuthProvider lê dela (o usuário não é mais guardado no localStorage).
  • HTTP: @moldape/api-client (fetch nativo). No navegador o cookie vai com credentials: include; no servidor ele é repassado no header cookie, pela URL interna ORDER_LIFECYCLE_INTERNAL_URL quando definida.
Camada O que guarda Invalidação
Data Cache do Next (fetch com next.tags) Só conteúdo público: slide show do login, documentos (termos, catálogo) e itens de ajuda (@/server/public-data) Tags slide-shows, documents, help-info: a server action revalidatePublicData chama updateTag após cada edição no admin; senão, expira em 1 h
TanStack Query (navegador) Dados do usuário e do admin invalidateQueries nas mutations
Redis (API) Sessões e, com ENABLE_CACHING=true, respostas públicas TTL
Vetorização do estúdio Estado do canvas e imagens (vectorization-store, image-cache) Inalterado nesta versão, para não afetar o salvamento

Dados de usuário nunca entram no Data Cache do Next: o cliente HTTP do servidor usa cache: 'no-store' e um QueryClient por requisição.

  • Redis guarda sessões e, com ENABLE_CACHING=true, respostas públicas.
  • Rate limit com @fastify/rate-limit, ativado por ENABLE_RATE_LIMITING (RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_MS).
  • Upload multipart (@fastify/multipart) ou em partes (/upload/chunk, /upload/chunk/complete) para arquivos grandes.
  • Tipos aceitos para plantigrafia: JPEG, PNG, WebP e PDF, até 5 MB. PDFs são convertidos em imagem no servidor (pdf2pic + GraphicsMagick).
  • Tudo fica em UPLOAD_DIRECTORY, em subpastas por tipo: plantigraphies, vectorized-plantigraphies, creation-images, pdfs, products, pieces, coverages, coverage-logos, banners, temp. A pasta é servida em /uploads/.
  • Valores monetários são Decimal no Prisma e decimal.js no domínio, para evitar erro de ponto flutuante.
  • Para o gateway, o total é convertido em centavos inteiros (Math.round(total * 100)).
  • Na interface, o formato deveria ser sempre Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }). O checkout hoje mostra R$ 196.07 (com ponto); ver Avaliação heurística.
Tipo de estado Ferramenta
Estado do servidor (rascunhos, catálogo, sacola, pedidos) TanStack Query 5: pré-carregado no servidor e hidratado; hooks de query e mutation por recurso (hooks/use*.ts) sobre lib/query/queries.ts
Usuário logado Consulta currentUser (hidratada pela sessão) exposta por useAuth()
Estado local do estúdio (seleção, zoom, elementos) Zustand 4 (stores/)
Canvas Konva / react-konva
Notificações sonner e o toast do @moldape/ui

Os identificadores legíveis seguem padrões definidos em domain/value-objects/codes.ts, por exemplo ORD-<timestamp>-<n> para pedidos e TX001, EN001 para taxas. As chaves primárias são cuid().

Desenvolvido e documentado por
Nós Tecnologia · Desenvolvimento Criativo