# 📋 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