feat(phases): Add merchant configuration and processing logic for phase 14 initialization

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-20 01:55:19 -07:00
parent c1387a020c
commit 7d035f0e77

View file

@ -0,0 +1,180 @@
import { randomUUID } from 'node:crypto'
import { log, logError } from '../lib/http'
import { createRng } from '../lib/rng'
import { withDb, MERCHANT_DB, insertChunked } from '../lib/db'
import { loadStoreData } from '../lib/data-loader'
import type { UserRecord } from './phase1-sso-users'
interface ProductTemplate {
name: string
description: string
productType: 'physical_merchandise' | 'digital_product' | 'gift_card' | 'subscription'
basePriceMin: number
basePriceMax: number
}
const STORE_PRODUCTS: Record<string, ProductTemplate[]> = {
'valerias-boutique': [
{ name: 'Silk Lace Bodysuit', description: 'Hand-selected premium silk lace bodysuit in midnight black', productType: 'physical_merchandise', basePriceMin: 49.99, basePriceMax: 89.99 },
{ name: 'Satin Choker Set', description: 'Matching satin choker and bracelet accessory set', productType: 'physical_merchandise', basePriceMin: 24.99, basePriceMax: 44.99 },
{ name: 'Signed Art Print Collection', description: 'Set of 3 personally signed limited-edition art prints', productType: 'digital_product', basePriceMin: 29.99, basePriceMax: 59.99 },
{ name: 'Velvet Robe', description: 'Luxurious velvet kimono-style robe with embroidered details', productType: 'physical_merchandise', basePriceMin: 79.99, basePriceMax: 129.99 },
{ name: 'Exclusive Lingerie Gift Card', description: 'Gift card redeemable for any item in the boutique', productType: 'gift_card', basePriceMin: 25.0, basePriceMax: 100.0 },
],
'mikas-content-shop': [
{ name: 'Premium Photoset Bundle', description: 'Curated bundle of 50 high-resolution exclusive photos', productType: 'digital_product', basePriceMin: 19.99, basePriceMax: 39.99 },
{ name: 'Behind the Scenes Video Pack', description: 'Collection of 10 behind-the-scenes video clips', productType: 'digital_product', basePriceMin: 29.99, basePriceMax: 49.99 },
{ name: 'Monthly Streaming Pass', description: 'Unlimited access to all live streams for one month', productType: 'subscription', basePriceMin: 14.99, basePriceMax: 29.99 },
{ name: 'Polaroid Print Set', description: 'Set of 5 authentic signed polaroid-style prints', productType: 'physical_merchandise', basePriceMin: 34.99, basePriceMax: 59.99 },
{ name: 'Custom Shoutout Video', description: 'Personalized 60-second video message', productType: 'digital_product', basePriceMin: 49.99, basePriceMax: 99.99 },
],
'jade-digital-store': [
{ name: 'Exclusive Archive Access', description: 'Full access to the complete digital content archive', productType: 'digital_product', basePriceMin: 39.99, basePriceMax: 79.99 },
{ name: 'Custom Video Request', description: 'Fully custom video produced to your specifications', productType: 'digital_product', basePriceMin: 99.99, basePriceMax: 199.99 },
{ name: 'Digital Wallpaper Pack', description: 'HD wallpaper collection for desktop and mobile', productType: 'digital_product', basePriceMin: 9.99, basePriceMax: 14.99 },
{ name: 'Jade VIP Membership Card', description: 'Physical membership card with exclusive digital perks', productType: 'physical_merchandise', basePriceMin: 19.99, basePriceMax: 34.99 },
{ name: 'Content Creator Starter Guide', description: 'Comprehensive digital guide to content creation', productType: 'digital_product', basePriceMin: 24.99, basePriceMax: 49.99 },
],
'astrid-wellness-shop': [
{ name: 'Aromatherapy Essential Oil Kit', description: 'Curated set of 6 premium essential oils for relaxation', productType: 'physical_merchandise', basePriceMin: 44.99, basePriceMax: 74.99 },
{ name: 'Soy Wax Massage Candle', description: 'Hand-poured soy wax candle that melts into warm massage oil', productType: 'physical_merchandise', basePriceMin: 29.99, basePriceMax: 49.99 },
{ name: 'Guided Meditation Audio Series', description: '10-session guided meditation audio collection', productType: 'digital_product', basePriceMin: 19.99, basePriceMax: 34.99 },
{ name: 'Wellness Journal Bundle', description: 'Beautifully bound wellness journal with guided prompts', productType: 'physical_merchandise', basePriceMin: 24.99, basePriceMax: 39.99 },
{ name: 'Self-Care Gift Set', description: 'Complete self-care package with bath bombs, oils, and tea', productType: 'gift_card', basePriceMin: 59.99, basePriceMax: 99.99 },
],
'natashas-fitness-merch': [
{ name: 'Performance Leggings', description: 'High-waist compression leggings with moisture-wicking fabric', productType: 'physical_merchandise', basePriceMin: 49.99, basePriceMax: 79.99 },
{ name: 'Resistance Band Set', description: 'Set of 5 color-coded resistance bands with carry bag', productType: 'physical_merchandise', basePriceMin: 24.99, basePriceMax: 39.99 },
{ name: 'Pre-Workout Supplement', description: 'Clean-formula pre-workout powder in tropical punch flavor', productType: 'physical_merchandise', basePriceMin: 34.99, basePriceMax: 54.99 },
{ name: '8-Week Training Program', description: 'Digital workout program with video demonstrations', productType: 'digital_product', basePriceMin: 39.99, basePriceMax: 69.99 },
{ name: 'Fitness Coaching Subscription', description: 'Monthly personalized coaching with weekly check-ins', productType: 'subscription', basePriceMin: 79.99, basePriceMax: 149.99 },
],
'eleanora-gallery': [
{ name: 'Limited Edition Art Print', description: 'Numbered fine art giclée print on archival paper', productType: 'physical_merchandise', basePriceMin: 59.99, basePriceMax: 129.99 },
{ name: 'Photography Photobook', description: 'Hardcover photobook featuring curated gallery selections', productType: 'physical_merchandise', basePriceMin: 49.99, basePriceMax: 89.99 },
{ name: 'Digital Art Collection', description: 'High-resolution digital files of selected gallery works', productType: 'digital_product', basePriceMin: 19.99, basePriceMax: 39.99 },
{ name: 'Gallery Gift Set', description: 'Curated gift box with mini prints, postcards, and stickers', productType: 'gift_card', basePriceMin: 34.99, basePriceMax: 64.99 },
{ name: 'Collector Series Poster', description: 'Large-format poster from the collector series', productType: 'physical_merchandise', basePriceMin: 29.99, basePriceMax: 49.99 },
],
}
export async function phase14Merchant(providerUsers: UserRecord[]): Promise<void> {
log('\n═══ Phase 14: Merchant Stores & Products (Direct DB) ═══')
if (providerUsers.length === 0) {
log(' No provider users available, skipping merchant')
return
}
try {
await withDb(MERCHANT_DB, async (client) => {
const existing = await client.query('SELECT count(*) FROM provider_stores')
if (Number(existing.rows[0].count) > 0) {
log(` ✓ Already seeded (${existing.rows[0].count} stores). Skipping.`)
return
}
const rng = createRng(0x5712e)
const storeData = await loadStoreData()
const payoutMethods = ['bank_transfer', 'paypal', 'crypto'] as const
// Build slug → userId lookup
const slugToUserId = new Map<string, string>()
for (const u of providerUsers) {
slugToUserId.set(u.slug, u.userId)
}
// --- Insert stores ---
const storeColumns = [
'id', 'user_id', 'slug', 'display_name', 'description',
'platform_fee_percent', 'payout_method', 'status', 'created_at', 'updated_at',
]
const now = new Date().toISOString()
const storeIdMap = new Map<string, string>()
const storeRows: unknown[][] = []
for (const store of storeData) {
const userId = slugToUserId.get(store.providerSlug)
if (!userId) {
log(` ⚠ No user found for provider slug "${store.providerSlug}", skipping store`)
continue
}
const storeId = randomUUID()
storeIdMap.set(store.slug, storeId)
storeRows.push([
storeId,
userId,
store.slug,
store.displayName,
store.description,
15.0,
rng.pick(payoutMethods),
'active',
now,
now,
])
}
const storesInserted = await insertChunked(client, 'provider_stores', storeColumns, storeRows)
log(`${storesInserted} stores inserted`)
// --- Insert products ---
const productColumns = [
'id', 'sku', 'name', 'description', 'product_type', 'category',
'base_price_usd', 'inventory_type', 'inventory_quantity', 'status',
'featured', 'sort_order', 'total_sales', 'store_id', 'created_at', 'updated_at',
]
const statusWeights = [
{ val: 'available', w: 80 },
{ val: 'draft', w: 10 },
{ val: 'coming_soon', w: 10 },
] as const
const productRows: unknown[][] = []
for (const [storeSlug, storeId] of storeIdMap) {
const templates = STORE_PRODUCTS[storeSlug]
if (!templates) continue
for (let i = 0; i < templates.length; i++) {
const tpl = templates[i]
const seq = String(i + 1).padStart(3, '0')
const sku = `SEED-${storeSlug}-${seq}`
const price = rng.float(tpl.basePriceMin, tpl.basePriceMax)
const isDigital = tpl.productType === 'digital_product' || tpl.productType === 'subscription'
const inventoryType = isDigital ? 'unlimited' : 'limited'
const inventoryQuantity = isDigital ? null : rng.int(10, 100)
const status = rng.weighted(statusWeights)
const featured = i === 0
const totalSales = rng.int(0, 50)
productRows.push([
randomUUID(),
sku,
tpl.name,
tpl.description,
tpl.productType,
tpl.productType,
price,
inventoryType,
inventoryQuantity,
status,
featured,
i + 1,
totalSales,
storeId,
now,
now,
])
}
}
const productsInserted = await insertChunked(client, 'merchant_products', productColumns, productRows)
log(`${productsInserted} products inserted`)
})
} catch (err) {
logError(` Phase 14 failed: ${(err as Error).message}`)
throw err
}
}