listings
Anúncios da Vitrine — itens à venda ou disponíveis para troca.
Listings são a fonte de verdade da disponibilidade de um item na Vitrine. Antes da sessão 2026-04-28, essa info ficava em items.availability + items.asking_price — foi extraída pra cá pra modelar corretamente o ciclo "anunciei → pausei → encerrei → excluí".
Cada listing tem status (active, paused, closed) e modo (availability: sale, trade, both). Apenas active é visível no marketplace público; paused é invisível mas restaurável; closed é histórico (encerrado pelo dono ou após sale).
Colunas
| Coluna | Tipo | Nullable | Default |
|---|---|---|---|
| id ● | uuid | NOT NULL | gen_random_uuid() |
| item_id | uuid | NOT NULL | — |
| owner_id | uuid | NOT NULL | — |
| availability | enumcolumn | NOT NULL | — |
| asking_price | numeric | NULL ok | — |
| payment_methods | array | NOT NULL | [] |
| status | enumcolumn | NOT NULL | active |
| disclaimer_accepted_at | timestamp | NOT NULL | — |
| created_at | timestamp | NOT NULL | now() |
| updated_at | timestamp | NOT NULL | now() |
● primary key ◆ unique
Funcionalidade dos campos
id— UUID, PKitem_id— FK pro item anunciado. Cascade delete: apagar item apaga listing (geralmente você apaga listing primeiro).owner_id— FK pro dono. Denormalizado pra otimizar queries de listagem; sempre igual aoitems.collection.user_id.availability— enum (sale,trade,both). Não pode sernoneaqui (esse valor existe no enum por legacy mas listing implica disponibilidade).asking_price—numeric(10, 2). Nullable; obrigatório pro frontend seavailability ∈ (sale, both). Pode ser zero (doação).payment_methods— array de strings (pix,paypal,cash, etc.). Texto livre acordado entre as partes; backend não valida formato.status— enum:active(visível),paused(invisível, retomável),closed(encerrado, ficou pra histórico).disclaimer_accepted_at— timestamp em que o user aceitou o disclaimer da Vitrine ("Geek Social não intermedia a transação"). Required no insert.created_at/updated_at— managed.
Foreign keys
| Coluna(s) | Referência | ON DELETE | ON UPDATE |
|---|---|---|---|
| item_id | items.id | cascade | no action |
| owner_id | users.id | cascade | no action |
Índices
| Nome | Único | Colunas | WHERE (parcial) |
|---|---|---|---|
| listings_item_active_uniq | sim | item_id | [object Object] = 'active' |
| listings_owner_status_idx | não | owner_id, status, created_at | — |
| listings_active_updated_idx | não | updated_at | [object Object] = 'active' |
Detalhes dos índices:
listings_item_active_uniq— partial unique index garantindo que cada item tem no máximo 1 listingactive. Permite paused/closed múltiplos historicamente.CREATE UNIQUE INDEX ... ON listings(item_id) WHERE status = 'active';listings_owner_status_idx—(owner_id, status, created_at). Usado em "Meus anúncios" filtrando por status.listings_active_updated_idx— partial emupdated_at WHERE status = 'active'. Usado no marketplace pra ordenar "mais recentes primeiro".
Constraints
PRIMARY KEY (id)
Ciclo de vida
[criar listing]
↓
active ←──── (reativar) ──── paused
↓ ↑
(pausar) ─────────────────────┘
↓
close()
↓
closed ──── (delete permanente, hard) ──── ✗Estados possíveis:
active— aparece na vitrine pública, aceita ofertaspaused— invisível, dono pode reativar a qualquer momentoclosed— encerrado manualmente ou após confirm de transação. Dono pode deletar permanentemente (?hard=true).
Auto-rejeição em close/delete
Quando um listing é encerrado ou deletado com offers pending, todas elas viram rejected automaticamente via OffersService.autoRejectByListing. Isso é gatilhado pelo ListingsService via setter (setOffersIntegration) pra quebrar dependência circular. Notificações offer_rejected são enviadas aos ofertantes.
Padrões de uso
- Criar — INSERT com
status='active',disclaimer_accepted_at=now() - Pausar/Reativar — UPDATE status
- Encerrar — UPDATE status='closed' + auto-reject de pending offers
- Hard delete — DELETE (apenas listings closed). Endpoint:
DELETE /listings/:id?hard=true - Confirmar transação — flow envolve item_offers + offer_proposals; após
executeTransfer, listing ficaclosed
Tabelas relacionadas
items— anunciado (cascade)users— owner (cascade)item_offers— ofertas referemlisting_id(set null em delete pra preservar histórico)offer_proposals— rodadas de negociação dentro das ofertaslisting_ratings— avaliação após transação