Marketplace Packages (Phase 1)

Adds the packages marketplace pattern: sellers bundle multiple listings/slots/services into a single-price offering; buyers purchase the whole bundle with one transaction and track per-component delivery.

Adds the packages marketplace pattern: sellers bundle multiple listings/slots/services into a single-price offering; buyers purchase the whole bundle with one transaction and track per-component delivery.

Data model

Migration e2f3a4b5c6d7 adds:

  • marketplace_packages — seller-owned bundle records (title, bundle_price, validity, max_quantity, sold_count, status)
  • marketplace_package_components — the items included in a package (listing / availability_slot / service / custom, quantity, snapshotted title+description)
  • marketplace_deal_components — per-component tracking on bought packages (status: pending → delivered → approved)
  • marketplace_deals.is_package BOOLEAN + package_id UUID NULL — additive, nullable, backward-compatible

Backend endpoints (all under `/marketplace`)

Seller CRUD (SOURCE / VENDOR / AGENCY):

  • POST/GET/PATCH/DELETE /packages (+ /mine for own list, /{id}/publish | /pause | /archive)
  • Draft-only component management: POST/PATCH/DELETE /packages/{id}/components[/{cid}] + /components/reorder

Buyer (advertiser / agency):

  • GET /packages/browse — restriction-filtered (respects advertiser brand_category)
  • POST /packages/{id}/purchase — atomic: creates deal + snapshots components + increments sold_count + flips to sold_out if capped

Per-component deal actions:

  • POST /marketplace/deals/{id}/components/{cid}/submit-proof (seller)
  • POST /marketplace/deals/{id}/components/{cid}/approve (buyer — auto-completes deal when last one approves)
  • POST /marketplace/deals/{id}/components/{cid}/reject (buyer — seller can resubmit)

Frontend

  • /marketplace/packages — seller dashboard with KPIs, status pills, publish/pause/archive/delete
  • /marketplace/packages/new + /[id]/edit — shared PackageForm component (Basics / Components / Pricing / Availability with drag reorder)
  • /marketplace/packages/[id] — buyer detail page (hero, components list, price summary, Buy Package modal)
  • /marketplace — new Listings / Packages tab switcher
  • /marketplace/deals/[id] — new PackageComponentsSection renders only when is_package=true; per-component submit / approve / reject UI with progress bar

Verified live

  • Full end-to-end: create → publish → browse → purchase → submit proof → approve → auto-complete
  • All existing marketplace flows unaffected (listings, deals, bids, forward listings, pipeline, notifications)
  • Non-package deals render identically to before (is_package: false, components: [])

Scope deferred (Phase 2+)

  • Real "savings %" calculation on PackageForm (needs to fetch underlying listing/slot prices)
  • Inline package-level reviews (currently links to seller's media kit)
  • Component-level dispute
  • Subscription / retainer packages
  • Multi-seller packages + revenue split
  • SA "featured packages" curation
  • Agency-internal packages across multiple vendors

Side-effect fix

  • backend/config/settings.py now has extra = "ignore" — previous pydantic v2 setup rejected the ESIMPLIFIED_* env vars and broke alembic CLI. Fixed by allowing unrelated env keys.

---

Want to see it in your own workspace?

Bring planning, discovery, delivery, and measurement into one platform.