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(+/minefor 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— sharedPackageFormcomponent (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]— newPackageComponentsSectionrenders only whenis_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.pynow hasextra = "ignore"— previous pydantic v2 setup rejected theESIMPLIFIED_*env vars and brokealembicCLI. Fixed by allowing unrelated env keys.
---

