feat: implement market page with QueryProvider and dynamic listings
- wrap root layout with QueryProvider for React Query - replace market UnderConstruction placeholder with MarketClient and real data fetching - implement search, pagination, and sort via search params using getActiveListings - add necessary client components and queries - update dependencies (e.g., prisma, pkg-types)
This commit is contained in:
1 parent
55eebde0ba
commit
ab37b477df
106 files changed
+15261
-301
No files matched your search
@@ -0,0 +1,163 @@
|
||||
# 🔍 Análise dos Erros Encontrados
|
||||
|
||||
## 📋 Problemas Identificados
|
||||
|
||||
### 1. ❌ Erro: "Decimal objects are not supported" (Linha 77-78)
|
||||
|
||||
**Causa:**
|
||||
- O Prisma retorna campos `Decimal` (PostgreSQL) como objetos `Prisma.Decimal`, não como números JavaScript
|
||||
- O Next.js não consegue serializar objetos `Decimal` ao passar dados de Server Components para Client Components
|
||||
- Apenas objetos "plain" (números, strings, arrays, objetos simples) podem ser serializados
|
||||
|
||||
**Campos afetados:**
|
||||
- `price_pix` (Decimal)
|
||||
- `current_bid_amount` (Decimal)
|
||||
- `min_bid_increment` (Decimal)
|
||||
- `initial_price_pix` (Decimal)
|
||||
|
||||
**Solução aplicada:**
|
||||
✅ Converter todos os campos `Decimal` para `number` usando `Number()` antes de retornar os dados
|
||||
|
||||
---
|
||||
|
||||
### 2. ⚠️ Warning: "Package postcss can't be external" (Linhas 15-20, 85-90, etc.)
|
||||
|
||||
**Causa:**
|
||||
- Dependência transitiva (`sanitize-html` → `postcss`) não está instalada diretamente
|
||||
- Next.js/Turbopack tenta externalizar o pacote mas não consegue resolvê-lo
|
||||
|
||||
**Impacto:**
|
||||
- ⚠️ Apenas um warning, não quebra a aplicação
|
||||
- Pode causar problemas em builds de produção
|
||||
|
||||
**Soluções possíveis:**
|
||||
1. **Instalar postcss diretamente** (recomendado):
|
||||
```bash
|
||||
pnpm add postcss
|
||||
```
|
||||
|
||||
2. **Adicionar ao package.json** explicitamente:
|
||||
```json
|
||||
"dependencies": {
|
||||
"postcss": "^8.4.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. ✅ Erro resolvido: "column does not exist" (Linha 45)
|
||||
|
||||
**Status:** ✅ **RESOLVIDO**
|
||||
- A migração 014 foi executada com sucesso
|
||||
- As colunas `min_bid_increment`, `initial_price_pix`, etc. foram adicionadas
|
||||
- O erro não aparece mais nos logs recentes (linhas 75-76, 115-116 mostram queries funcionando)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Correções Implementadas
|
||||
|
||||
### Arquivo: `lib/prisma/queries/listings.ts`
|
||||
|
||||
**Antes:**
|
||||
```typescript
|
||||
return {
|
||||
...listing,
|
||||
price_gold_coins: listing.price_gold_coins ? Number(listing.price_gold_coins) : null,
|
||||
// ❌ Campos Decimal não eram convertidos
|
||||
};
|
||||
```
|
||||
|
||||
**Depois:**
|
||||
```typescript
|
||||
// Converter todos os campos Decimal e BigInt para números JavaScript
|
||||
return {
|
||||
...listing,
|
||||
price_pix: listing.price_pix ? Number(listing.price_pix) : null,
|
||||
current_bid_amount: listing.current_bid_amount ? Number(listing.current_bid_amount) : null,
|
||||
min_bid_increment: listing.min_bid_increment ? Number(listing.min_bid_increment) : null,
|
||||
initial_price_pix: listing.initial_price_pix ? Number(listing.initial_price_pix) : null,
|
||||
price_gold_coins: listing.price_gold_coins ? Number(listing.price_gold_coins) : null,
|
||||
initial_price_gold_coins: listing.initial_price_gold_coins ? Number(listing.initial_price_gold_coins) : null,
|
||||
seller_character_name: character?.character_name || null,
|
||||
} as Listing;
|
||||
```
|
||||
|
||||
**Funções corrigidas:**
|
||||
- ✅ `createListing()`
|
||||
- ✅ `getListingById()`
|
||||
- ✅ `getListings()`
|
||||
- ✅ `updateListing()`
|
||||
- ✅ `placeBid()`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Resultado
|
||||
|
||||
### ✅ Resolvido:
|
||||
1. Erro de coluna não existente (migração executada)
|
||||
2. Erro de serialização Decimal (conversão implementada)
|
||||
|
||||
### ⚠️ Pendente (não crítico):
|
||||
1. Warning do postcss (pode ser ignorado ou resolvido instalando postcss)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Próximos Passos Recomendados
|
||||
|
||||
1. **Instalar postcss** (opcional, resolve warning):
|
||||
```bash
|
||||
pnpm add postcss
|
||||
```
|
||||
|
||||
2. **Testar a aplicação:**
|
||||
- Verificar se a página do marketplace carrega corretamente
|
||||
- Verificar se os preços são exibidos corretamente
|
||||
- Testar criação de anúncios
|
||||
- Testar leilões e lances
|
||||
|
||||
3. **Monitorar logs:**
|
||||
- Verificar se o erro "Decimal objects are not supported" não aparece mais
|
||||
- Verificar se as queries estão funcionando corretamente
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Por que isso acontece?
|
||||
|
||||
### Prisma + PostgreSQL + Decimal
|
||||
|
||||
O Prisma usa o tipo `Decimal` do Prisma para representar valores `DECIMAL` do PostgreSQL. Isso garante precisão decimal, mas cria objetos que não são serializáveis pelo React/Next.js.
|
||||
|
||||
**Fluxo do problema:**
|
||||
```
|
||||
PostgreSQL DECIMAL → Prisma.Decimal → ❌ Não serializável → Erro no React
|
||||
```
|
||||
|
||||
**Solução:**
|
||||
```
|
||||
PostgreSQL DECIMAL → Prisma.Decimal → Number() → ✅ number (serializável)
|
||||
```
|
||||
|
||||
### Serialização no Next.js
|
||||
|
||||
O Next.js precisa serializar dados ao passar de Server Components para Client Components. Ele usa JSON serialization, que não suporta:
|
||||
- Classes customizadas
|
||||
- Objetos `Decimal` do Prisma
|
||||
- Funções
|
||||
- Símbolos
|
||||
- etc.
|
||||
|
||||
Apenas tipos primitivos JSON são suportados:
|
||||
- ✅ `string`, `number`, `boolean`
|
||||
- ✅ `null`, `undefined`
|
||||
- ✅ Arrays e objetos simples
|
||||
|
||||
---
|
||||
|
||||
## 📚 Referências
|
||||
|
||||
- [Prisma Decimal Type](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-decimal-numbers)
|
||||
- [Next.js Serialization](https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#async-server-components)
|
||||
- [React Server Components](https://react.dev/reference/rsc/server-components)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
## 📋 ANÃLISE DO PROBLEMA
|
||||
|
||||
### Problema Identificado
|
||||
- O sistema usa SQLite com múltiplas tabelas (espadas, armaduras, etc)
|
||||
- Cada tabela tem seus próprios IDs que podem se repetir entre tabelas
|
||||
- Quando salvamos `item_id=1` no listing, não sabemos de qual tabela veio
|
||||
- Ao buscar com `getItemById(1)`, pode retornar o item errado
|
||||
|
||||
### Solução Proposta
|
||||
1. Criar tabela unificada `items` no PostgreSQL com IDs únicos
|
||||
2. Popular a tabela a partir do SQLite
|
||||
3. Usar JOINs nas queries para garantir consistência
|
||||
4. Atualizar sistema para usar sempre o ID unificado
|
||||
|
||||
@@ -0,0 +1,798 @@
|
||||
# 📋 Plano Detalhado: Melhorias do Marketplace
|
||||
|
||||
## 🎯 Objetivo Geral
|
||||
|
||||
Implementar um sistema completo de intenções de compra, melhorias na interface de gerenciamento de anúncios, sistema de notificações visual, exibição de vendedores, sistema de lances e telemetria completa.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Análise de Requisitos
|
||||
|
||||
### Requisitos Explícitos
|
||||
|
||||
1. **Sistema de Intenção de Compra**
|
||||
- Compra não remove item do mercado
|
||||
- Criar "intenção de compra" com método de pagamento escolhido
|
||||
- Notificar vendedor sobre cada intenção
|
||||
|
||||
2. **Melhorias na Página "Meus Anúncios"**
|
||||
- Exibir dados de compradores interessados
|
||||
- Mostrar informações de cada intenção de compra
|
||||
|
||||
3. **Ícone de Notificações**
|
||||
- Badge com contador de notificações não lidas
|
||||
- Visual no header/navbar
|
||||
|
||||
4. **Exibição de Vendedor**
|
||||
- Nome do vendedor nos cards
|
||||
- Avatar/imagem do vendedor (preparar para integração futura)
|
||||
|
||||
5. **Sistema de Lances (Bids)**
|
||||
- Permitir que usuários deem lances
|
||||
- Atualizar valor do item conforme lances
|
||||
- Integração completa no frontend
|
||||
|
||||
6. **Telemetria Completa**
|
||||
- Rastrear lances (valor, horário, usuário)
|
||||
- Acessos por dia/hora
|
||||
- Anúncios mais clicados
|
||||
- Análises de comportamento
|
||||
|
||||
### Requisitos Implícitos
|
||||
|
||||
- Sistema deve ser escalável
|
||||
- Performance não deve degradar com muitos dados
|
||||
- Interface responsiva e intuitiva
|
||||
- Notificações em tempo real (ou polling eficiente)
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Arquivos Afetados
|
||||
|
||||
### Backend (API + Queries)
|
||||
|
||||
1. **Novos Arquivos:**
|
||||
- `lib/db/migrations/015_add_purchase_intentions.sql`
|
||||
- `lib/prisma/queries/purchase-intentions.ts`
|
||||
- `app/api/listings/[id]/intentions/route.ts`
|
||||
- `app/api/listings/[id]/intentions/[intentionId]/route.ts`
|
||||
- `app/api/notifications/unread-count/route.ts`
|
||||
|
||||
2. **Arquivos Modificados:**
|
||||
- `app/api/listings/[id]/purchase/route.ts` (mudar para criar intenção)
|
||||
- `lib/prisma/queries/listings.ts` (adicionar queries relacionadas)
|
||||
- `lib/prisma/queries/notifications.ts` (melhorar queries)
|
||||
- `lib/prisma/queries/telemetry.ts` (adicionar eventos de lance)
|
||||
|
||||
### Frontend (Components)
|
||||
|
||||
1. **Novos Arquivos:**
|
||||
- `components/notifications/NotificationBell.tsx`
|
||||
- `components/notifications/NotificationDropdown.tsx`
|
||||
- `components/marketplace/PurchaseIntentionModal.tsx`
|
||||
- `components/marketplace/MyAdsIntentionList.tsx`
|
||||
- `components/marketplace/SellerInfo.tsx`
|
||||
|
||||
2. **Arquivos Modificados:**
|
||||
- `components/marketplace/PurchaseModal.tsx` (mudar para intenção)
|
||||
- `components/marketplace/MyAdsPanel.tsx` (adicionar seção de intenções)
|
||||
- `components/marketplace/AdCard.tsx` (adicionar SellerInfo, melhorar bids)
|
||||
- `components/Header.tsx` (adicionar NotificationBell)
|
||||
- `components/marketplace/BidModal.tsx` (melhorar UI e telemetria)
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Estrutura de Banco de Dados
|
||||
|
||||
### Nova Tabela: `purchase_intentions`
|
||||
|
||||
```sql
|
||||
CREATE TABLE purchase_intentions (
|
||||
intention_id SERIAL PRIMARY KEY,
|
||||
listing_id INTEGER NOT NULL REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
buyer_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
payment_method VARCHAR(20) NOT NULL CHECK (payment_method IN ('pix', 'tibia_coins', 'gold_coins', 'trade')),
|
||||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected', 'expired', 'completed')),
|
||||
buyer_message TEXT,
|
||||
seller_response TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
accepted_at TIMESTAMP,
|
||||
rejected_at TIMESTAMP,
|
||||
|
||||
UNIQUE(listing_id, buyer_id, status) WHERE status = 'pending',
|
||||
INDEX idx_listing_id (listing_id),
|
||||
INDEX idx_buyer_id (buyer_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
- `intention_id`: ID único
|
||||
- `listing_id`: Anúncio relacionado
|
||||
- `buyer_id`: Comprador interessado
|
||||
- `payment_method`: Método de pagamento escolhido
|
||||
- `status`: Estado da intenção (pending, accepted, rejected, expired, completed)
|
||||
- `buyer_message`: Mensagem opcional do comprador
|
||||
- `seller_response`: Resposta do vendedor
|
||||
- `expires_at`: Quando a intenção expira (opcional)
|
||||
- Timestamps para rastreamento
|
||||
|
||||
---
|
||||
|
||||
## 📝 Plano de Implementação
|
||||
|
||||
## FASE 1: Sistema de Intenções de Compra (Backend)
|
||||
|
||||
### Etapa 1.1: Migração de Banco de Dados
|
||||
|
||||
**Arquivo:** `lib/db/migrations/015_add_purchase_intentions.sql`
|
||||
|
||||
```sql
|
||||
-- Migration 015: Sistema de Intenções de Compra
|
||||
-- Criado em: 2025-01-29
|
||||
|
||||
CREATE TABLE IF NOT EXISTS purchase_intentions (
|
||||
intention_id SERIAL PRIMARY KEY,
|
||||
listing_id INTEGER NOT NULL REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
buyer_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
payment_method VARCHAR(20) NOT NULL CHECK (payment_method IN ('pix', 'tibia_coins', 'gold_coins', 'trade')),
|
||||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected', 'expired', 'completed')),
|
||||
buyer_message TEXT,
|
||||
seller_response TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
accepted_at TIMESTAMP,
|
||||
rejected_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- Índices para performance
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_listing_id ON purchase_intentions(listing_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_buyer_id ON purchase_intentions(buyer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_status ON purchase_intentions(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_created_at ON purchase_intentions(created_at DESC);
|
||||
|
||||
-- Constraint: apenas uma intenção pendente por listing+buyer
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_purchase_intentions_unique_pending
|
||||
ON purchase_intentions(listing_id, buyer_id)
|
||||
WHERE status = 'pending';
|
||||
|
||||
-- Trigger para atualizar updated_at
|
||||
CREATE OR REPLACE FUNCTION update_purchase_intentions_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_purchase_intentions_updated_at
|
||||
BEFORE UPDATE ON purchase_intentions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_purchase_intentions_updated_at();
|
||||
|
||||
-- Comentários para documentação
|
||||
COMMENT ON TABLE purchase_intentions IS 'Intenções de compra de anúncios - permite múltiplos compradores interessados';
|
||||
COMMENT ON COLUMN purchase_intentions.status IS 'pending: aguardando resposta do vendedor, accepted: aceita, rejected: rejeitada, expired: expirada, completed: concluída';
|
||||
```
|
||||
|
||||
**Tarefas:**
|
||||
- [ ] Criar arquivo de migração
|
||||
- [ ] Adicionar à lista de migrations em `run-migrations.ts`
|
||||
- [ ] Executar migração
|
||||
- [ ] Atualizar schema Prisma
|
||||
|
||||
---
|
||||
|
||||
### Etapa 1.2: Schema Prisma
|
||||
|
||||
**Arquivo:** `prisma/schema.prisma`
|
||||
|
||||
```prisma
|
||||
model PurchaseIntention {
|
||||
intention_id Int @id @default(autoincrement())
|
||||
listing_id Int
|
||||
buyer_id Int
|
||||
payment_method String @db.VarChar(20)
|
||||
status String @default("pending") @db.VarChar(20)
|
||||
buyer_message String? @db.Text
|
||||
seller_response String? @db.Text
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
expires_at DateTime?
|
||||
accepted_at DateTime?
|
||||
rejected_at DateTime?
|
||||
|
||||
listing Listing @relation(fields: [listing_id], references: [listing_id], onDelete: Cascade)
|
||||
buyer User @relation("BuyerIntentions", fields: [buyer_id], references: [user_id], onDelete: Cascade)
|
||||
|
||||
@@index([listing_id])
|
||||
@@index([buyer_id])
|
||||
@@index([status])
|
||||
@@index([created_at(sort: Desc)])
|
||||
@@unique([listing_id, buyer_id], where: { status: "pending" })
|
||||
@@map("purchase_intentions")
|
||||
}
|
||||
```
|
||||
|
||||
**Também atualizar:**
|
||||
- Adicionar relação `purchaseIntentions` no model `Listing`
|
||||
- Adicionar relação `purchaseIntentions` no model `User` (como `BuyerIntentions`)
|
||||
|
||||
---
|
||||
|
||||
### Etapa 1.3: Queries Prisma
|
||||
|
||||
**Arquivo:** `lib/prisma/queries/purchase-intentions.ts`
|
||||
|
||||
**Funções a criar:**
|
||||
1. `createPurchaseIntention(data)` - Criar intenção
|
||||
2. `getPurchaseIntentionsByListing(listingId, filters)` - Listar intenções de um anúncio
|
||||
3. `getPurchaseIntentionsByBuyer(buyerId, filters)` - Listar intenções de um comprador
|
||||
4. `getPurchaseIntentionById(intentionId)` - Buscar intenção específica
|
||||
5. `updatePurchaseIntentionStatus(intentionId, status, sellerResponse)` - Atualizar status
|
||||
6. `getPendingIntentionsCount(listingId)` - Contar intenções pendentes
|
||||
|
||||
**Detalhamento:**
|
||||
|
||||
```typescript
|
||||
export interface CreatePurchaseIntentionData {
|
||||
listing_id: number;
|
||||
buyer_id: number;
|
||||
payment_method: "pix" | "tibia_coins" | "gold_coins" | "trade";
|
||||
buyer_message?: string;
|
||||
expires_at?: Date;
|
||||
}
|
||||
|
||||
export interface PurchaseIntention {
|
||||
intention_id: number;
|
||||
listing_id: number;
|
||||
buyer_id: number;
|
||||
payment_method: string;
|
||||
status: "pending" | "accepted" | "rejected" | "expired" | "completed";
|
||||
buyer_message: string | null;
|
||||
seller_response: string | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
expires_at: Date | null;
|
||||
accepted_at: Date | null;
|
||||
rejected_at: Date | null;
|
||||
// Relacionamentos
|
||||
listing?: Listing;
|
||||
buyer?: User;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 1.4: API Routes
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/intentions/route.ts`
|
||||
|
||||
**Endpoints:**
|
||||
- `POST /api/listings/[id]/intentions` - Criar intenção de compra
|
||||
- `GET /api/listings/[id]/intentions` - Listar intenções (apenas vendedor)
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/intentions/[intentionId]/route.ts`
|
||||
|
||||
**Endpoints:**
|
||||
- `GET /api/listings/[id]/intentions/[intentionId]` - Buscar intenção
|
||||
- `PATCH /api/listings/[id]/intentions/[intentionId]` - Atualizar status (aceitar/rejeitar)
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/purchase/route.ts` (MODIFICAR)
|
||||
|
||||
**Mudança:**
|
||||
- Ao invés de mudar `listing_status` para "sold", criar uma `PurchaseIntention`
|
||||
- Notificar vendedor sobre nova intenção
|
||||
|
||||
---
|
||||
|
||||
## FASE 2: Sistema de Notificações Visual
|
||||
|
||||
### Etapa 2.1: API de Contagem de Notificações Não Lidas
|
||||
|
||||
**Arquivo:** `app/api/notifications/unread-count/route.ts`
|
||||
|
||||
```typescript
|
||||
// GET /api/notifications/unread-count
|
||||
// Retorna: { count: number }
|
||||
```
|
||||
|
||||
**Já existe função `getUnreadCount()` em `lib/prisma/queries/notifications.ts` - apenas criar rota**
|
||||
|
||||
---
|
||||
|
||||
### Etapa 2.2: Componente NotificationBell
|
||||
|
||||
**Arquivo:** `components/notifications/NotificationBell.tsx`
|
||||
|
||||
**Funcionalidades:**
|
||||
- Badge com contador de não lidas
|
||||
- Ícone de sino (Bell do lucide-react)
|
||||
- Dropdown ao clicar (usar `NotificationDropdown`)
|
||||
- Polling automático a cada 30 segundos
|
||||
- Animações quando há novas notificações
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface NotificationBellProps {
|
||||
userId?: number;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Estado:**
|
||||
- `unreadCount: number`
|
||||
- `isOpen: boolean`
|
||||
- `notifications: Notification[]`
|
||||
|
||||
---
|
||||
|
||||
### Etapa 2.3: Componente NotificationDropdown
|
||||
|
||||
**Arquivo:** `components/notifications/NotificationDropdown.tsx`
|
||||
|
||||
**Funcionalidades:**
|
||||
- Lista de notificações recentes (últimas 10)
|
||||
- Link "Ver todas" para página completa
|
||||
- Marcar como lida ao clicar
|
||||
- Diferentes tipos de notificação (compra, lance, etc.)
|
||||
- Timestamps formatados
|
||||
|
||||
---
|
||||
|
||||
### Etapa 2.4: Integrar no Header
|
||||
|
||||
**Arquivo:** `components/Header.tsx`
|
||||
|
||||
**Mudanças:**
|
||||
- Adicionar `NotificationBell` no navbar
|
||||
- Posicionar ao lado do menu de usuário
|
||||
- Apenas exibir se usuário estiver logado
|
||||
|
||||
---
|
||||
|
||||
## FASE 3: Exibição de Vendedor
|
||||
|
||||
### Etapa 3.1: Componente SellerInfo
|
||||
|
||||
**Arquivo:** `components/marketplace/SellerInfo.tsx`
|
||||
|
||||
**Funcionalidades:**
|
||||
- Avatar do vendedor (placeholder inicial, preparado para imagem)
|
||||
- Nome do personagem
|
||||
- Badge "Verificado" se aplicável
|
||||
- Link para perfil do vendedor (futuro)
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface SellerInfoProps {
|
||||
sellerId: number;
|
||||
sellerName: string;
|
||||
sellerImage?: string | null;
|
||||
verified?: boolean;
|
||||
serverName: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Design:**
|
||||
- Avatar circular com fallback (iniciais do nome)
|
||||
- Layout horizontal compacto
|
||||
- Responsivo
|
||||
|
||||
---
|
||||
|
||||
### Etapa 3.2: Integrar no AdCard
|
||||
|
||||
**Arquivo:** `components/marketplace/AdCard.tsx`
|
||||
|
||||
**Mudanças:**
|
||||
- Adicionar `SellerInfo` no card (modo grid e list)
|
||||
- Posicionar acima ou abaixo do preço
|
||||
- Estilizar consistentemente
|
||||
|
||||
---
|
||||
|
||||
## FASE 4: Sistema de Lances (Bids) - Frontend Completo
|
||||
|
||||
### Etapa 4.1: Melhorar BidModal
|
||||
|
||||
**Arquivo:** `components/marketplace/BidModal.tsx`
|
||||
|
||||
**Melhorias:**
|
||||
- Exibir histórico de lances (últimos 5)
|
||||
- Mostrar "Seu lance atual" se usuário já deu lance
|
||||
- Indicador visual de lance mínimo
|
||||
- Feedback imediato após dar lance
|
||||
- Refresh automático do valor do anúncio
|
||||
|
||||
**Novos campos:**
|
||||
- Histórico de lances
|
||||
- Timestamp do lance
|
||||
- Informações do último lanceador
|
||||
|
||||
---
|
||||
|
||||
### Etapa 4.2: API de Histórico de Lances
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/bids/route.ts`
|
||||
|
||||
**Endpoint:**
|
||||
- `GET /api/listings/[id]/bids` - Listar lances de um anúncio
|
||||
|
||||
**Resposta:**
|
||||
```typescript
|
||||
{
|
||||
bids: Array<{
|
||||
bid_id: number;
|
||||
bidder_id: number;
|
||||
bidder_name: string;
|
||||
bid_amount: number;
|
||||
bid_type: string | null;
|
||||
created_at: Date;
|
||||
}>;
|
||||
total: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 4.3: Atualizar BidModal com Histórico
|
||||
|
||||
**Mudanças:**
|
||||
- Buscar histórico ao abrir modal
|
||||
- Exibir lista de lances anteriores
|
||||
- Mostrar "Você está na liderança" se aplicável
|
||||
- Atualizar valor mínimo dinamicamente
|
||||
|
||||
---
|
||||
|
||||
### Etapa 4.4: Melhorar AdCard para Bids
|
||||
|
||||
**Arquivo:** `components/marketplace/AdCard.tsx`
|
||||
|
||||
**Melhorias:**
|
||||
- Exibir "X lances" ao invés de apenas valor atual
|
||||
- Indicador visual de leilão ativo
|
||||
- Contador regressivo se `auction_ends_at` estiver definido
|
||||
- Badge "Novo lance" se houver lance recente
|
||||
|
||||
---
|
||||
|
||||
## FASE 5: Telemetria Completa
|
||||
|
||||
### Etapa 5.1: Expandir Eventos de Telemetria
|
||||
|
||||
**Arquivo:** `lib/prisma/queries/telemetry.ts`
|
||||
|
||||
**Novos tipos de eventos:**
|
||||
- `bid_placed` - Lance realizado
|
||||
- `bid_viewed` - Histórico de lances visualizado
|
||||
- `purchase_intention_created` - Intenção de compra criada
|
||||
- `purchase_intention_viewed` - Intenção visualizada
|
||||
- `seller_profile_viewed` - Perfil do vendedor visualizado
|
||||
|
||||
**Atualizar interface:**
|
||||
```typescript
|
||||
export type TelemetryEventType =
|
||||
| "ad_view"
|
||||
| "ad_click"
|
||||
| "ad_exit"
|
||||
| "search"
|
||||
| "filter"
|
||||
| "favorite"
|
||||
| "unfavorite"
|
||||
| "purchase"
|
||||
| "purchase_intention_created" // NOVO
|
||||
| "purchase_intention_viewed" // NOVO
|
||||
| "bid_placed" // NOVO
|
||||
| "bid_viewed" // NOVO
|
||||
| "seller_profile_viewed" // NOVO
|
||||
| "inquiry"
|
||||
| "page_view"
|
||||
| "price_change";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 5.2: Tracking de Lances
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/bid/route.ts`
|
||||
|
||||
**Mudanças:**
|
||||
- Após criar lance com sucesso, registrar telemetria:
|
||||
```typescript
|
||||
await trackEvent({
|
||||
event_type: "bid_placed",
|
||||
ad_id: listingId,
|
||||
user_id: bidderId,
|
||||
metadata: {
|
||||
bid_amount: amount,
|
||||
payment_method: paymentMethod,
|
||||
previous_bid: listing.current_bid_amount,
|
||||
min_increment: listing.min_bid_increment,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 5.3: Tracking de Intenções de Compra
|
||||
|
||||
**Arquivo:** `app/api/listings/[id]/intentions/route.ts`
|
||||
|
||||
**Mudanças:**
|
||||
- Após criar intenção, registrar telemetria:
|
||||
```typescript
|
||||
await trackEvent({
|
||||
event_type: "purchase_intention_created",
|
||||
ad_id: listingId,
|
||||
user_id: buyerId,
|
||||
metadata: {
|
||||
payment_method: paymentMethod,
|
||||
listing_price_pix: listing.price_pix,
|
||||
listing_price_tc: listing.price_tibia_coins,
|
||||
listing_price_gp: listing.price_gold_coins,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 5.4: Tracking de Visualizações de Vendedor
|
||||
|
||||
**Arquivo:** `components/marketplace/SellerInfo.tsx`
|
||||
|
||||
**Mudanças:**
|
||||
- Ao montar componente, registrar telemetria:
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
trackEvent({
|
||||
event_type: "seller_profile_viewed",
|
||||
ad_id: listingId,
|
||||
metadata: {
|
||||
seller_id: sellerId,
|
||||
seller_name: sellerName,
|
||||
},
|
||||
});
|
||||
}, [sellerId, listingId]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 5.5: Analytics Dashboard (Opcional - Futuro)
|
||||
|
||||
**Arquivo:** `components/marketplace/AnalyticsDashboard.tsx` (já existe)
|
||||
|
||||
**Melhorias futuras:**
|
||||
- Gráfico de lances ao longo do tempo
|
||||
- Anúncios mais clicados
|
||||
- Horários de pico de acesso
|
||||
- Taxa de conversão de intenções
|
||||
|
||||
---
|
||||
|
||||
## FASE 6: Melhorias na Página "Meus Anúncios"
|
||||
|
||||
### Etapa 6.1: Componente MyAdsIntentionList
|
||||
|
||||
**Arquivo:** `components/marketplace/MyAdsIntentionList.tsx`
|
||||
|
||||
**Funcionalidades:**
|
||||
- Lista de intenções de compra para um anúncio específico
|
||||
- Filtros (pendentes, aceitas, rejeitadas)
|
||||
- Ações: aceitar, rejeitar, ver detalhes
|
||||
- Badge com contador de pendentes
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface MyAdsIntentionListProps {
|
||||
listingId: number;
|
||||
sellerId: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 6.2: Atualizar MyAdsPanel
|
||||
|
||||
**Arquivo:** `components/marketplace/MyAdsPanel.tsx`
|
||||
|
||||
**Mudanças:**
|
||||
- Adicionar seção de intenções em cada card de anúncio
|
||||
- Expandir/colapsar intenções
|
||||
- Mostrar resumo: "X intenções pendentes"
|
||||
- Link para ver todas as intenções
|
||||
|
||||
**Layout:**
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ [Anúncio: Item X] │
|
||||
│ Status: Active │
|
||||
│ │
|
||||
│ 📊 Intenções de Compra │
|
||||
│ └─ 3 pendentes │
|
||||
│ [Ver todas] [Expandir] │
|
||||
│ │
|
||||
│ 💰 Lances (se for leilão) │
|
||||
│ └─ 5 lances, atual: R$ 100 │
|
||||
│ [Ver histórico] │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Etapa 6.3: Modal de Detalhes de Intenção
|
||||
|
||||
**Arquivo:** `components/marketplace/IntentionDetailModal.tsx`
|
||||
|
||||
**Funcionalidades:**
|
||||
- Exibir informações completas da intenção
|
||||
- Dados do comprador (nome, personagem)
|
||||
- Método de pagamento escolhido
|
||||
- Mensagem do comprador (se houver)
|
||||
- Botões: Aceitar / Rejeitar
|
||||
- Campo para resposta do vendedor
|
||||
|
||||
---
|
||||
|
||||
## 📊 Sequência de Implementação Recomendada
|
||||
|
||||
### Sprint 1: Fundação (Backend)
|
||||
1. ✅ Migração de banco de dados (Fase 1.1)
|
||||
2. ✅ Schema Prisma (Fase 1.2)
|
||||
3. ✅ Queries Prisma (Fase 1.3)
|
||||
4. ✅ API Routes básicas (Fase 1.4)
|
||||
|
||||
### Sprint 2: Frontend Core
|
||||
5. ✅ Componente SellerInfo (Fase 3.1)
|
||||
6. ✅ Integrar SellerInfo no AdCard (Fase 3.2)
|
||||
7. ✅ NotificationBell e Dropdown (Fase 2.1-2.3)
|
||||
8. ✅ Integrar no Header (Fase 2.4)
|
||||
|
||||
### Sprint 3: Sistema de Intenções
|
||||
9. ✅ PurchaseIntentionModal (Fase 1 - Frontend)
|
||||
10. ✅ Modificar PurchaseModal para criar intenção
|
||||
11. ✅ MyAdsIntentionList (Fase 6.1)
|
||||
12. ✅ Atualizar MyAdsPanel (Fase 6.2)
|
||||
|
||||
### Sprint 4: Sistema de Lances
|
||||
13. ✅ API de histórico de lances (Fase 4.2)
|
||||
14. ✅ Melhorar BidModal com histórico (Fase 4.1, 4.3)
|
||||
15. ✅ Melhorar AdCard para bids (Fase 4.4)
|
||||
|
||||
### Sprint 5: Telemetria
|
||||
16. ✅ Expandir eventos (Fase 5.1)
|
||||
17. ✅ Tracking de lances (Fase 5.2)
|
||||
18. ✅ Tracking de intenções (Fase 5.3)
|
||||
19. ✅ Tracking de vendedor (Fase 5.4)
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Design e UX
|
||||
|
||||
### Componentes Visuais
|
||||
|
||||
1. **NotificationBell:**
|
||||
- Ícone: `Bell` do lucide-react
|
||||
- Badge vermelho com contador
|
||||
- Animação de pulse quando há novas
|
||||
- Dropdown com sombra e bordas arredondadas
|
||||
|
||||
2. **SellerInfo:**
|
||||
- Avatar: 40x40px, circular
|
||||
- Nome: texto médio, bold
|
||||
- Badge verificado: ícone de check, verde
|
||||
- Layout: flex horizontal, espaçamento adequado
|
||||
|
||||
3. **IntentionList:**
|
||||
- Cards compactos por intenção
|
||||
- Badge de status (pendente: amarelo, aceita: verde, rejeitada: vermelho)
|
||||
- Avatar do comprador
|
||||
- Método de pagamento com ícone
|
||||
|
||||
4. **BidHistory:**
|
||||
- Lista vertical com timestamps
|
||||
- Destaque para lance atual
|
||||
- Indicador de "seu lance"
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Considerações e Riscos
|
||||
|
||||
### Riscos Identificados
|
||||
|
||||
1. **Performance:**
|
||||
- Muitas intenções por anúncio pode degradar performance
|
||||
- **Mitigação:** Paginação e lazy loading
|
||||
|
||||
2. **Notificações:**
|
||||
- Polling pode sobrecarregar servidor
|
||||
- **Mitigação:** Polling inteligente (mais frequente quando há novas notificações)
|
||||
|
||||
3. **Concorrência:**
|
||||
- Múltiplos lances simultâneos
|
||||
- **Mitigação:** Transações e validação de incremento mínimo
|
||||
|
||||
4. **Telemetria:**
|
||||
- Muitos eventos podem sobrecarregar banco
|
||||
- **Mitigação:** Batch de eventos, agregação periódica
|
||||
|
||||
### Validações Necessárias
|
||||
|
||||
- ✅ Verificar se método de pagamento escolhido está disponível no anúncio
|
||||
- ✅ Validar que comprador não é o vendedor
|
||||
- ✅ Validar incremento mínimo de lance
|
||||
- ✅ Validar que anúncio ainda está ativo
|
||||
- ✅ Validar que leilão não expirou
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testes Necessários
|
||||
|
||||
### Testes Unitários
|
||||
|
||||
- [ ] Queries de purchase_intentions
|
||||
- [ ] Validação de métodos de pagamento
|
||||
- [ ] Cálculo de incremento mínimo de lance
|
||||
|
||||
### Testes de Integração
|
||||
|
||||
- [ ] Fluxo completo de criação de intenção
|
||||
- [ ] Notificação ao vendedor
|
||||
- [ ] Aceitar/rejeitar intenção
|
||||
- [ ] Sistema de lances com múltiplos usuários
|
||||
|
||||
### Testes E2E
|
||||
|
||||
- [ ] Comprador cria intenção → Vendedor recebe notificação
|
||||
- [ ] Vendedor aceita intenção → Comprador é notificado
|
||||
- [ ] Múltiplos lances → Valor atualiza corretamente
|
||||
- [ ] Telemetria registra todos os eventos
|
||||
|
||||
---
|
||||
|
||||
## 📈 Métricas de Sucesso
|
||||
|
||||
1. **Funcionalidade:**
|
||||
- ✅ Intenções de compra funcionando
|
||||
- ✅ Notificações aparecendo corretamente
|
||||
- ✅ Lances atualizando valor
|
||||
- ✅ Vendedores aparecendo nos cards
|
||||
|
||||
2. **Performance:**
|
||||
- Página de marketplace carrega em < 2s
|
||||
- Notificações atualizam em < 1s
|
||||
- Queries de intenções em < 500ms
|
||||
|
||||
3. **UX:**
|
||||
- Interface intuitiva e responsiva
|
||||
- Feedback visual claro
|
||||
- Mensagens de erro compreensíveis
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Próximos Passos
|
||||
|
||||
1. **Revisar este plano** e ajustar conforme necessário
|
||||
2. **Priorizar fases** baseado em necessidade do negócio
|
||||
3. **Iniciar Fase 1** (Backend de intenções)
|
||||
4. **Testar incrementalmente** cada fase antes de avançar
|
||||
|
||||
---
|
||||
|
||||
## 📚 Referências
|
||||
|
||||
- [Prisma Relations](https://www.prisma.io/docs/concepts/components/prisma-schema/relations)
|
||||
- [Next.js Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations)
|
||||
- [React Query/Polling](https://tanstack.com/query/latest/docs/react/guides/window-focus-refetching)
|
||||
|
||||
---
|
||||
|
||||
**Plano criado em:** 2025-01-29
|
||||
**Versão:** 1.0
|
||||
**Status:** Pronto para implementação
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
# 📊 Prisma Query Logs - Explicação Completa
|
||||
|
||||
## 🔍 O que são os logs `prisma:query`?
|
||||
|
||||
Os logs `prisma:query` são **queries SQL que o Prisma executa automaticamente** no banco de dados PostgreSQL. Eles aparecem no console durante o desenvolvimento para ajudar você a:
|
||||
|
||||
1. **Debugar** - Ver exatamente quais queries estão sendo executadas
|
||||
2. **Otimizar** - Identificar queries lentas ou desnecessárias
|
||||
3. **Entender** - Compreender o que o Prisma está fazendo "por baixo dos panos"
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuração Atual
|
||||
|
||||
No arquivo `lib/prisma/app.ts`, o Prisma está configurado assim:
|
||||
|
||||
```typescript
|
||||
export const prisma = new PrismaClient({
|
||||
log:
|
||||
process.env.NODE_ENV === "development"
|
||||
? ["query", "error", "warn"] // ← Loga queries em desenvolvimento
|
||||
: ["error"], // ← Apenas erros em produção
|
||||
});
|
||||
```
|
||||
|
||||
**Isso significa:**
|
||||
- ✅ **Em desenvolvimento**: Mostra todas as queries SQL
|
||||
- ✅ **Em produção**: Apenas mostra erros (não mostra queries)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Análise dos Logs do Seu Terminal
|
||||
|
||||
### 1. **INSERT de Telemetria** (Linhas 24-26, 58-59, 93-94)
|
||||
|
||||
```sql
|
||||
INSERT INTO "public"."telemetry_events"
|
||||
("event_type","ad_id","user_id","session_id","metadata","timestamp")
|
||||
VALUES ($1,$2,$3,$4,$5,$6)
|
||||
RETURNING ...
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- Registra eventos de telemetria (cliques, visualizações, etc.)
|
||||
- Executado quando o usuário interage com a página
|
||||
|
||||
**Por que aparece:**
|
||||
- O sistema de telemetria está ativo e registrando eventos
|
||||
|
||||
---
|
||||
|
||||
### 2. **SELECT de Listings** (Linhas 35-36, 79-80)
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) AS "_count$_all"
|
||||
FROM (SELECT "public"."listings"."listing_id"
|
||||
FROM "public"."listings"
|
||||
WHERE "public"."listings"."listing_status" = $1
|
||||
OFFSET $2) AS "sub"
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- Conta quantos anúncios ativos existem
|
||||
- Usado para paginação
|
||||
|
||||
**E depois:**
|
||||
|
||||
```sql
|
||||
SELECT "public"."listings"."listing_id",
|
||||
"public"."listings"."seller_id",
|
||||
"public"."listings"."item_id",
|
||||
-- ... todos os campos ...
|
||||
FROM "public"."listings"
|
||||
WHERE "public"."listings"."listing_status" = $1
|
||||
ORDER BY "public"."listings"."created_at" DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- Busca os anúncios ativos com paginação
|
||||
- Ordena por data de criação (mais recentes primeiro)
|
||||
- Limita a 20 resultados por página
|
||||
|
||||
**Por que aparece:**
|
||||
- A página do marketplace (`/en/market`) está carregando
|
||||
- Está buscando anúncios para exibir
|
||||
|
||||
---
|
||||
|
||||
### 3. **SELECT de Characters** (Linhas 37, 81)
|
||||
|
||||
```sql
|
||||
SELECT "public"."user_characters"."character_id",
|
||||
"public"."user_characters"."user_id",
|
||||
"public"."user_characters"."character_name",
|
||||
"public"."user_characters"."server_name",
|
||||
"public"."user_characters"."is_main",
|
||||
"public"."user_characters"."verified",
|
||||
"public"."user_characters"."created_at"
|
||||
FROM "public"."user_characters"
|
||||
WHERE ("public"."user_characters"."user_id" = $1
|
||||
AND "public"."user_characters"."server_name" = $2
|
||||
AND "public"."user_characters"."is_main" = $3)
|
||||
LIMIT $4 OFFSET $5
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- Busca o personagem principal do vendedor
|
||||
- Usado para exibir o nome do personagem nos cards de anúncio
|
||||
|
||||
**Por que aparece:**
|
||||
- Para cada anúncio, busca o nome do personagem do vendedor
|
||||
- Isso acontece porque implementamos a busca de `seller_character_name`
|
||||
|
||||
---
|
||||
|
||||
### 4. **SELECT de Servers** (Linha 66)
|
||||
|
||||
```sql
|
||||
SELECT "public"."servers"."server_id",
|
||||
"public"."servers"."server_name",
|
||||
-- ... outros campos ...
|
||||
FROM "public"."servers"
|
||||
WHERE "public"."servers"."is_active" = $1
|
||||
ORDER BY "public"."servers"."server_name" ASC
|
||||
OFFSET $2
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- Busca todos os servidores ativos
|
||||
- Usado para popular o filtro de servidores no marketplace
|
||||
|
||||
**Por que aparece:**
|
||||
- O componente de filtros está carregando a lista de servidores
|
||||
|
||||
---
|
||||
|
||||
### 5. **BEGIN / COMMIT** (Linhas 23, 27, 57, 60, 92, 95)
|
||||
|
||||
```sql
|
||||
BEGIN
|
||||
-- ... queries ...
|
||||
COMMIT
|
||||
```
|
||||
|
||||
**O que é:**
|
||||
- **Transações** do banco de dados
|
||||
- Garante que múltiplas operações sejam executadas atomicamente
|
||||
- Se uma falhar, todas são revertidas (ROLLBACK)
|
||||
|
||||
**Por que aparece:**
|
||||
- Operações que precisam de atomicidade (ex: inserir múltiplos eventos de telemetria em batch)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Por que isso é útil?
|
||||
|
||||
### ✅ Benefícios:
|
||||
|
||||
1. **Debugging:**
|
||||
- Ver exatamente quais queries estão sendo executadas
|
||||
- Identificar queries N+1 (muitas queries desnecessárias)
|
||||
- Verificar se os índices estão sendo usados
|
||||
|
||||
2. **Performance:**
|
||||
- Identificar queries lentas
|
||||
- Ver quantas queries estão sendo executadas
|
||||
- Otimizar queries que são executadas repetidamente
|
||||
|
||||
3. **Entendimento:**
|
||||
- Aprender como o Prisma traduz suas operações para SQL
|
||||
- Ver como os relacionamentos são resolvidos
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Como Controlar os Logs
|
||||
|
||||
### Opção 1: Desabilitar completamente (não recomendado em dev)
|
||||
|
||||
```typescript
|
||||
// lib/prisma/app.ts
|
||||
export const prisma = new PrismaClient({
|
||||
log: ["error"], // Apenas erros
|
||||
});
|
||||
```
|
||||
|
||||
### Opção 2: Apenas erros e warnings
|
||||
|
||||
```typescript
|
||||
export const prisma = new PrismaClient({
|
||||
log: ["error", "warn"],
|
||||
});
|
||||
```
|
||||
|
||||
### Opção 3: Logs mais detalhados (com informações de tempo)
|
||||
|
||||
```typescript
|
||||
export const prisma = new PrismaClient({
|
||||
log: [
|
||||
{ level: "query", emit: "event" },
|
||||
{ level: "error", emit: "stdout" },
|
||||
{ level: "warn", emit: "stdout" },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### Opção 4: Manter como está (recomendado)
|
||||
|
||||
```typescript
|
||||
// Atual (já está assim)
|
||||
export const prisma = new PrismaClient({
|
||||
log:
|
||||
process.env.NODE_ENV === "development"
|
||||
? ["query", "error", "warn"] // ← Bom para desenvolvimento
|
||||
: ["error"], // ← Otimizado para produção
|
||||
});
|
||||
```
|
||||
|
||||
**✅ Recomendação:** Manter como está! Os logs são úteis em desenvolvimento e não aparecem em produção.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Análise de Performance dos Seus Logs
|
||||
|
||||
### Queries que aparecem frequentemente:
|
||||
|
||||
1. **SELECT listings** (2 queries):
|
||||
- Uma para contar total
|
||||
- Uma para buscar os itens
|
||||
- **Status:** ✅ Normal (paginação requer ambas)
|
||||
|
||||
2. **SELECT user_characters** (1 por anúncio):
|
||||
- Busca o personagem do vendedor
|
||||
- **Status:** ⚠️ Potencial otimização
|
||||
- **Sugestão:** Já está otimizado com `Map` para evitar queries duplicadas
|
||||
|
||||
3. **INSERT telemetry_events** (em batch):
|
||||
- Múltiplos eventos inseridos em uma transação
|
||||
- **Status:** ✅ Otimizado (usa transação)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Níveis de Log do Prisma
|
||||
|
||||
O Prisma suporta diferentes níveis de log:
|
||||
|
||||
```typescript
|
||||
log: [
|
||||
"query", // Todas as queries SQL
|
||||
"info", // Informações gerais
|
||||
"warn", // Avisos
|
||||
"error", // Erros
|
||||
]
|
||||
```
|
||||
|
||||
**Ou com eventos:**
|
||||
|
||||
```typescript
|
||||
log: [
|
||||
{ level: "query", emit: "event" }, // Evento customizado
|
||||
{ level: "error", emit: "stdout" }, // Console padrão
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Conclusão
|
||||
|
||||
**Os logs `prisma:query` são:**
|
||||
- ✅ **Normais** - Esperados em desenvolvimento
|
||||
- ✅ **Úteis** - Ajudam a debugar e otimizar
|
||||
- ✅ **Automáticos** - Não afetam performance
|
||||
- ✅ **Desabilitados em produção** - Não aparecem em produção
|
||||
|
||||
**Você deve:**
|
||||
- ✅ **Manter** os logs em desenvolvimento
|
||||
- ✅ **Usar** para identificar problemas de performance
|
||||
- ✅ **Ignorar** se não estiver debuggando (são apenas informativos)
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Referências
|
||||
|
||||
- [Prisma Logging Documentation](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/logging)
|
||||
- [Prisma Query Performance](https://www.prisma.io/docs/guides/performance-and-optimization/query-optimization-performance)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user