Files
nick-doc/02 - Data Models/PurchaseRequest.md

10 KiB

title, tags, aliases
title tags aliases
PurchaseRequest
data-model
mongoose
Purchase Request
Buy Request
IPurchaseRequest

PurchaseRequest

Last updated: 2026-05-31 — budget.currency aligned with template/Postgres enum (USD, EUR, IRR, USDT, USDC); categoryId added to IRequestTableItem

The central buyer-side document. A PurchaseRequest captures what a buyer wants to acquire (physical product, digital product, service, or consultation), the budget envelope, urgency, delivery details, and the entire lifecycle from creation through payment, delivery, and completion. Sellers respond by attaching SellerOffer documents; the buyer accepts one, a Payment is opened, and delivery is verified by a 6-digit code.

[!note] Source backend/src/models/PurchaseRequest.ts:95 — schema definition backend/src/models/PurchaseRequest.ts:387 — model export

Schema

Field Type Required Default Validation Index Description
buyerId ObjectId → User yes yes Buyer that owns the request.
title String yes trim, maxlength 200 Short headline.
description String yes trim, minlength 5 (frontend), maxlength 2000 Long form description. Frontend enforces a 5-character minimum; the field is optional in the raw schema but the form will reject shorter values.
categoryId ObjectId → Category yes yes Category the request belongs to.
productType String no physical_product enum: physical_product / digital_product / service / consultation yes What kind of fulfilment is expected.
productLink String no trim, must match /^https?:\/\/.+/ Reference URL for the desired product.
size String no trim, maxlength 100 Product size.
color String no trim, maxlength 100 Product color.
brand String no trim, maxlength 100 Brand preference.
preferredSellerIds[] ObjectId → User no [] Targeted sellers for a private request.
quantity Number no 1 min 1 Unit count.
budget.min Number no min 0 Lower bound.
budget.max Number no min 0 Upper bound.
budget.currency String no USDT enum: USD / EUR / IRR / USDT / USDC Budget currency. Runtime Mongoose validation, request-template validation, and the PG budget_currency enum now share these values.
urgency String no medium enum: low / medium / high / urgent yes Buyer urgency.
status String no pending enum (13 values — see State Transitions below) yes Lifecycle state.
isPublic Boolean no true Public marketplace listing vs. private request.
tags[] String[] no trim Free-form tags.
specifications[].key String yes trim Spec key.
specifications[].value String yes trim Spec value.
specifications[].label String no trim Human label.
deliveryInfo.deliveryType String yes physical enum: physical / online Delivery channel.
deliveryInfo.address String no Physical address.
deliveryInfo.preferredDate Date no Buyer's target date.
deliveryInfo.notes String no Free-form notes.
deliveryInfo.deliveryAddress.name String no Recipient name.
deliveryInfo.deliveryAddress.phoneNumber String no Recipient phone.
deliveryInfo.deliveryAddress.fullAddress String no Full address string.
deliveryInfo.deliveryAddress.addressType String no e.g. Home / Office.
deliveryInfo.email String no email regex For digital delivery.
deliveryInfo.sellerDeliveryInfo.estimatedDeliveryDate Date no Seller's ETA date.
deliveryInfo.sellerDeliveryInfo.estimatedDeliveryTime String no Seller's ETA time.
deliveryInfo.sellerDeliveryInfo.trackingNumber String no Carrier tracking.
deliveryInfo.sellerDeliveryInfo.deliveryNotes String no Notes from seller.
deliveryInfo.sellerDeliveryInfo.shippingMethod String no Method label.
deliveryInfo.sellerDeliveryInfo.downloadLink String no Download URL for digital products.
deliveryInfo.sellerDeliveryInfo.digitalFiles[] String[] no Digital file URLs.
deliveryInfo.deliveryDateTime Date no Confirmed delivery datetime.
deliveryInfo.deliveryDate Date no Confirmed delivery date.
deliveryInfo.shippedAt Date no Timestamp of shipment.
deliveryInfo.deliveryCode String no trim, length 6 6-digit handoff code.
deliveryInfo.deliveryCodeGeneratedAt Date no When code was issued.
deliveryInfo.deliveryCodeExpiresAt Date no When code expires.
deliveryInfo.deliveryCodeUsed Boolean no false Whether the code has been redeemed.
deliveryInfo.deliveryCodeUsedAt Date no When it was redeemed.
deliveryInfo.deliveryCodeUsedBy ObjectId → User no Seller that redeemed.
deliveryInfo.deliveredAt Date no Final delivery timestamp.
deliveryInfo.deliveryAttempts[].sellerId ObjectId → User yes Seller making the attempt.
deliveryInfo.deliveryAttempts[].attemptedAt Date no Date.now When attempted.
deliveryInfo.deliveryAttempts[].success Boolean yes Whether it succeeded.
deliveryInfo.deliveryAttempts[].code String no Code entered (only stored on success).
serviceInfo.duration Number no min 0.5 Hours, only for service/consultation.
serviceInfo.sessionType String no enum: online / in_person / hybrid Service session type.
serviceInfo.location String no trim, maxlength 200 Service location.
serviceInfo.requirements[] String[] no trim Pre-requisites.
attachments[] String[] no Attached file URLs.
offers[] ObjectId → SellerOffer no Offers received.
selectedOfferId ObjectId → SellerOffer no null Accepted offer.
rating Number no null min 1, max 5 Buyer's post-delivery rating.
feedback String no null maxlength 1000 Buyer's feedback text.
deliveryConfirmed Boolean no false Buyer confirmation flag.
deliveryConfirmedAt Date no null Confirmation timestamp.
metadata.source String no manual enum: manual / template / api Where the request came from.
metadata.templateId String no trim Originating RequestTemplate id.
metadata.version String no trim Schema version.
createdAt Date auto yes (desc) Mongoose timestamp.
updatedAt Date auto Mongoose timestamp.

Status enum — all valid values

pending_payment · pending · active · received_offers · in_negotiation · payment · processing · delivery · delivered · confirming · completed · seller_paid · cancelled

Note: finalized and archived are not valid status values and do not appear in the IPurchaseRequest frontend type or the Mongoose schema enum. Using either would cause a validation error.

Virtuals

None defined.

Indexes

Single-field — backend/src/models/PurchaseRequest.ts:376-381:

  • { buyerId: 1 }
  • { categoryId: 1 }
  • { productType: 1 }
  • { status: 1 }
  • { createdAt: -1 }
  • { urgency: 1 }

Compound — backend/src/models/PurchaseRequest.ts:384-385:

  • { productType: 1, status: 1 }
  • { categoryId: 1, productType: 1 }

Pre/Post Hooks

None declared at the schema level.

Instance Methods

None defined.

Static Methods

None defined.

Relationships

  • References: User (buyerId, preferredSellerIds[], deliveryInfo.deliveryCodeUsedBy, deliveryInfo.deliveryAttempts[].sellerId), Category (categoryId), SellerOffer (offers[], selectedOfferId).
  • Referenced by: SellerOffer (purchaseRequestId), Payment (purchaseRequestId), Dispute (purchaseRequestId), Chat (relatedTo.id when relatedTo.type === 'PurchaseRequest'), Review (purchaseRequestId).

State Transitions

stateDiagram-v2
    [*] --> pending_payment
    [*] --> pending
    pending_payment --> pending : payment confirmed
    pending --> active : published
    active --> received_offers : first offer
    received_offers --> in_negotiation : buyer engages
    in_negotiation --> payment : offer accepted
    payment --> processing : payment captured
    processing --> delivery : shipped
    delivery --> delivered : handed over
    delivered --> confirming : code redeemed
    confirming --> completed : buyer confirms
    completed --> seller_paid : payout released
    pending --> cancelled
    active --> cancelled
    received_offers --> cancelled
    in_negotiation --> cancelled
    completed --> [*]
    seller_paid --> [*]
    cancelled --> [*]

Common Queries

// Buyer's open requests
PurchaseRequest.find({ buyerId, status: { $in: ['pending', 'active', 'received_offers'] } });

// Public marketplace feed
PurchaseRequest.find({ isPublic: true, status: 'active' }).sort({ createdAt: -1 });

// Sellers' eligible queue
PurchaseRequest.find({ productType, status: 'active', categoryId });

// Populate offers
PurchaseRequest.findById(id).populate('offers').populate('selectedOfferId');

// Redeem delivery code
PurchaseRequest.findOneAndUpdate(
  { _id: id, 'deliveryInfo.deliveryCode': code, 'deliveryInfo.deliveryCodeUsed': false },
  { $set: { 'deliveryInfo.deliveryCodeUsed': true, 'deliveryInfo.deliveryCodeUsedAt': new Date() } }
);

Related: SellerOffer, Payment, Chat, Dispute, Review, RequestTemplate, Category.