Geek Social — Documentação
Banco de dadosTables

offer_proposals

Rodadas de negociação dentro de uma offer (proposta inicial + counters).

Cada rodada de negociação dentro de uma offer é um row aqui. A primeira é criada junto com a offer (item_offers); counter-propostas adicionam novos rows. Apenas uma está pending por offer ao mesmo tempo (unique partial index).

A offer "como um todo" (item_offers.status) só evolui pra accepted quando uma rodada vira accepted. Rejeição de rodada NÃO mata a offer — pode-se contra-propor.

Colunas

ColunaTipoNullableDefault
id uuidNOT NULLgen_random_uuid()
offer_iduuidNOT NULL
proposer_iduuidNOT NULL
offered_pricenumericNULL ok
offered_item_iduuidNULL ok
messagetextNULL ok
statusenumcolumnNOT NULLpending
created_attimestampNOT NULLnow()
updated_attimestampNOT NULLnow()

primary key   unique

Funcionalidade dos campos

  • id — UUID, PK
  • offer_id — FK pra item_offers. Cascade delete.
  • proposer_id — quem fez essa rodada. Identifica de quem é o turno: o LADO OPOSTO precisa responder. Cascade delete.
  • offered_price — preço proposto nessa rodada (para buy)
  • offered_item_id — item oferecido nessa rodada (para trade). Set null em delete.
  • message — texto livre opcional explicando a contra-proposta
  • status — enum: pending (esperando ação do oposto), accepted (aceita — offer evolui), rejected (rejeitada — fim da rodada, mas offer pode continuar), superseded (substituída por counter-proposta nova)
  • created_at / updated_at — managed.

Foreign keys

Coluna(s)ReferênciaON DELETEON UPDATE
offer_iditem_offers.idcascadeno action
proposer_idusers.idcascadeno action
offered_item_iditems.idset nullno action

Índices

NomeÚnicoColunasWHERE (parcial)
offer_proposals_offer_idxnãooffer_id, created_at
offer_proposals_one_pending_uniqsimoffer_id[object Object] = 'pending'

Detalhes:

  • offer_proposals_offer_idx(offer_id, created_at). Usado pra listar todas as rodadas de uma offer em ordem cronológica
  • offer_proposals_one_pending_uniq — partial unique em offer_id WHERE status='pending'. Garante semântica de "1 rodada ativa por vez"

Constraints

  • PRIMARY KEY (id)

Estados e transições

       pending ──(accept)──→ accepted (offer.status → accepted; transação a confirmar)

          ├──(reject)──→ rejected (final desta rodada)

          └──(propose contraposta)──→ superseded (e nova proposal pending criada)

Helpers de turno (frontend)

A DTO OfferWithDetails carrega latestProposal: { id, proposerId, status }. UI usa pra decidir:

  • isMyTurnproposer_id !== currentUser.id AND status === 'pending'
  • canAcceptisMyTurn
  • canRejectisMyTurn (rejeita rodada, não offer)
  • canProposeisMyTurn (counter-propor)

Se proposer_id === currentUser.id, o usuário está esperando — só pode cancelar a oferta inteira.

Backfill em migration

A migration que adicionou essa tabela criou rows iniciais retroativos pra ofertas existentes — cada offer ganhou um proposal com os mesmos offered_price/offered_item_id e proposer_id = offerer_id, mantendo compatibilidade com o histórico.

Padrões de uso

  • Insert inicial — quando offer é criada
  • Accept — UPDATE status='accepted' — offer evolui
  • Reject — UPDATE status='rejected' — offer continua
  • Counter-proposta — UPDATE atual status='superseded' + INSERT novo status='pending' (transação)

Tabelas relacionadas

On this page