veza/veza-backend-api/cmd/tools/seed/seed_marketplace.go
senke 2eff5a9b10 refactor(backend): split seed tool into domain-specific modules
Extract monolithic seed main.go into separate files per domain:
users, tracks, playlists, chat, analytics, marketplace, social,
content, live, moderation, notifications, and misc. Add config,
fake data helpers, and utility modules. Update Makefile targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 23:35:07 +01:00

225 lines
7.3 KiB
Go

package main
import (
"database/sql"
"fmt"
"time"
)
// SeededProduct holds product data.
type SeededProduct struct {
ID string
SellerID string
Title string
Price float64
}
// SeedMarketplace creates products, orders, order_items, product_reviews,
// seller_stripe_accounts, and seller_balances.
func SeedMarketplace(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) ([]SeededProduct, error) {
fmt.Println("\n═══ MARKETPLACE ═══")
artists := GetArtists(users)
listeners := GetListeners(users)
if len(artists) == 0 {
return nil, nil
}
products := make([]SeededProduct, 0, cfg.Products)
// ── 1. Products ──────────────────────────────────────────────────────────
p := NewProgress("products", cfg.Products)
productRows := make([][]interface{}, 0, cfg.Products)
for i := 0; i < cfg.Products; i++ {
id := newUUID()
seller := artists[rng.Intn(len(artists))]
genres := GenreForArtist(rng.Intn(len(artists)))
genre := genres[0]
title := GenProductTitle(genre.Name)
desc := fmt.Sprintf("Professional %s content by %s", genre.Slug, seller.DisplayName)
price := float64(randInt(999, 29999)) / 100.0 // €9.99 - €299.99
ptype := pick(productTypes)
license := pick([]string{"non-exclusive", "exclusive", "non-exclusive"})
category := pick(productCategories)
bpm := randInt(genre.BPMRange[0], genre.BPMRange[1])
key := ""
if len(genre.Keys) > 0 {
key = pick(genre.Keys)
}
// Optionally link to a track
var trackID interface{}
if ptype == "beat" && len(tracks) > 0 && randChance(50) {
// Find a track by this seller
for _, t := range tracks {
if t.CreatorID == seller.ID {
trackID = t.ID
break
}
}
}
createdAt := RandomTimeAfter(seller.CreatedAt)
prod := SeededProduct{ID: id, SellerID: seller.ID, Title: title, Price: price}
products = append(products, prod)
productRows = append(productRows, []interface{}{
id, seller.ID, title, desc, price, "EUR", "active",
ptype, trackID, license, bpm, key, category,
createdAt, createdAt,
})
}
_, err := BulkInsert(db, "products",
"id, seller_id, title, description, price, currency, status, product_type, track_id, license_type, bpm, musical_key, category, created_at, updated_at",
productRows)
if err != nil {
return nil, fmt.Errorf("insert products: %w", err)
}
p.Update(len(productRows))
p.Done()
// ── 2. Orders ────────────────────────────────────────────────────────────
p = NewProgress("orders + order_items", cfg.Orders)
orderRows := make([][]interface{}, 0, cfg.Orders)
itemRows := make([][]interface{}, 0, cfg.Orders*2)
allBuyers := append(listeners, users...) // Mix of listeners and all users
statuses := []string{"completed", "completed", "completed", "completed", "pending", "cancelled"}
for i := 0; i < cfg.Orders; i++ {
orderID := newUUID()
buyer := allBuyers[rng.Intn(len(allBuyers))]
status := pick(statuses)
createdAt := RandomTimeAfter(buyer.CreatedAt)
// 1-3 items per order
itemCount := randInt(1, 3)
totalAmount := 0.0
selectedProducts := pickN(products, itemCount)
for _, prod := range selectedProducts {
totalAmount += prod.Price
itemRows = append(itemRows, []interface{}{
newUUID(), orderID, prod.ID, prod.Price,
})
}
orderRows = append(orderRows, []interface{}{
orderID, buyer.ID, totalAmount, "EUR", status,
createdAt, createdAt,
})
}
_, err = BulkInsert(db, "orders",
"id, buyer_id, total_amount, currency, status, created_at, updated_at",
orderRows)
if err != nil {
return nil, fmt.Errorf("insert orders: %w", err)
}
_, err = BulkInsert(db, "order_items",
"id, order_id, product_id, price",
itemRows)
if err != nil {
return nil, fmt.Errorf("insert order_items: %w", err)
}
p.Update(cfg.Orders)
p.Done()
// ── 3. Product reviews ───────────────────────────────────────────────────
p = NewProgress("product_reviews", cfg.ProductReviews)
reviewRows := make([][]interface{}, 0, cfg.ProductReviews)
reviewSeen := make(map[string]bool)
reviewContents := []string{
"Excellent quality, exactly what I needed!", "Great sounds, well organized.",
"Good value for the price.", "Professional quality samples.",
"Perfect for my latest project.", "Would buy again!",
"Decent pack, some gems in there.", "Not what I expected but still useful.",
"Top-notch production quality.", "These beats are fire!",
"Clean mix, ready to use.", "Amazing variety in this pack.",
}
for i := 0; i < cfg.ProductReviews*2 && len(reviewRows) < cfg.ProductReviews; i++ {
prod := products[rng.Intn(len(products))]
reviewer := allBuyers[rng.Intn(len(allBuyers))]
if reviewer.ID == prod.SellerID {
continue
}
key := prod.ID + ":" + reviewer.ID
if reviewSeen[key] {
continue
}
reviewSeen[key] = true
reviewRows = append(reviewRows, []interface{}{
newUUID(), prod.ID, reviewer.ID,
randInt(3, 5), // rating 3-5 (realistic positive bias)
pick(reviewContents),
time.Now(), time.Now(),
})
}
_, _ = BulkInsert(db, "product_reviews",
"id, product_id, user_id, rating, content, created_at, updated_at",
reviewRows)
p.Update(len(reviewRows))
p.Done()
// ── 4. Seller stripe accounts ────────────────────────────────────────────
p = NewProgress("seller_stripe_accounts", len(artists))
sellerRows := make([][]interface{}, 0, len(artists))
for _, artist := range artists {
if !randChance(60) {
continue
}
sellerRows = append(sellerRows, []interface{}{
newUUID(), artist.ID,
fmt.Sprintf("acct_%s", newUUID()[:16]),
true, // is_onboarded
true, // payouts_enabled
true, // charges_enabled
"verified", // kyc_status
nil, nil, // kyc_verification_session_id, kyc_verified_at
nil, // kyc_last_error
time.Now(), time.Now(),
})
}
_, _ = BulkInsert(db, "seller_stripe_accounts",
"id, user_id, stripe_account_id, is_onboarded, payouts_enabled, charges_enabled, kyc_status, kyc_verification_session_id, kyc_verified_at, kyc_last_error, created_at, updated_at",
sellerRows)
p.Update(len(sellerRows))
p.Done()
// ── 5. Seller balances ───────────────────────────────────────────────────
p = NewProgress("seller_balances", len(artists))
balanceRows := make([][]interface{}, 0, len(artists))
for _, artist := range artists {
if !randChance(50) {
continue
}
totalEarned := int64(randInt(0, 100000))
totalPaid := totalEarned * int64(randInt(30, 80)) / 100
available := totalEarned - totalPaid - int64(randInt(0, 10000))
if available < 0 {
available = 0
}
pending := int64(randInt(0, 10000))
balanceRows = append(balanceRows, []interface{}{
newUUID(), artist.ID,
available, pending, totalEarned, totalPaid,
"EUR", time.Now(),
})
}
_, _ = BulkInsert(db, "seller_balances",
"id, seller_id, available_cents, pending_cents, total_earned_cents, total_paid_out_cents, currency, updated_at",
balanceRows)
p.Update(len(balanceRows))
p.Done()
return products, nil
}