056c47581f
Ships the second dashboard surface — a Pattern Library + Preview Theatre — that presents the 4-section PDP pilot batch back to Umar, compliance, and the board in an editorial format. Adds the full data layer that drives it: 5 source-backed per-SKU drafts at QA 100/100, 15 competitor PDP semantic extracts, PubMed evidence packs, EFSA claims library extension, JV brand voice guide, hand-curated product FAQs, and the Matrixify-ready CSV exports for Lewis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
121 lines
5.5 KiB
TypeScript
121 lines
5.5 KiB
TypeScript
#!/usr/bin/env bun
|
|
import { mkdirSync, writeFileSync } from 'fs'
|
|
import { join } from 'path'
|
|
|
|
const root = process.cwd()
|
|
const outRoot = join(root, 'content_population_exports')
|
|
mkdirSync(outRoot, { recursive: true })
|
|
|
|
function csv(rows: any[], headers: string[]) {
|
|
const esc = (value: any) => {
|
|
if (value === undefined || value === null) value = ''
|
|
if (Array.isArray(value)) value = value.join(' | ')
|
|
value = String(value)
|
|
return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
|
|
}
|
|
return [headers.join(','), ...rows.map(row => headers.map(header => esc(row[header])).join(','))].join('\n') + '\n'
|
|
}
|
|
|
|
const generatedAt = new Date().toISOString()
|
|
const rows = [
|
|
{
|
|
Provider: 'DataForSEO',
|
|
Stage: '1',
|
|
PricingItem: 'Amazon Reviews API standard queue',
|
|
Unit: 'every 10 reviews',
|
|
Price: '$0.00075',
|
|
SourceUrl: 'https://dataforseo.com/apis/reviews-api/amazon-reviews-api',
|
|
SourceCheckedAt: generatedAt,
|
|
AppliesToPlan: 'Stage 1 uses depth=10 per ASIN, so the first 9-ASIN pilot should be estimated from 9 units of 10 reviews before any buffer.',
|
|
Caveat: 'Official page uses USD pricing. Convert/record the working budget currency in data/sources/budgets/source-acquisition-cost-plan.json before approvals.'
|
|
},
|
|
{
|
|
Provider: 'DataForSEO',
|
|
Stage: '1',
|
|
PricingItem: 'Amazon Reviews API priority queue',
|
|
Unit: 'every 10 reviews',
|
|
Price: '$0.0015',
|
|
SourceUrl: 'https://dataforseo.com/apis/reviews-api/amazon-reviews-api',
|
|
SourceCheckedAt: generatedAt,
|
|
AppliesToPlan: 'Priority queue is not the default pilot recommendation; use only if turnaround time matters more than cost.',
|
|
Caveat: 'Keep the pilot in standard queue unless a human explicitly updates the cost plan and approval.'
|
|
},
|
|
{
|
|
Provider: 'DataForSEO',
|
|
Stage: '1',
|
|
PricingItem: 'Depth billing rule',
|
|
Unit: '10-review increments',
|
|
Price: 'round depth up to the next 10-review block',
|
|
SourceUrl: 'https://dataforseo.com/help-center/get-amazon-reviews',
|
|
SourceCheckedAt: generatedAt,
|
|
AppliesToPlan: 'Depth=10 avoids accidental double billing; depth=11 would be charged as 20 reviews.',
|
|
Caveat: 'Do not change depth from 10 in asin-map.csv without updating the cost plan and approval cap.'
|
|
},
|
|
{
|
|
Provider: 'Apify',
|
|
Stage: '2',
|
|
PricingItem: 'Actor compute units on Creator/standard public pricing reference',
|
|
Unit: 'compute unit',
|
|
Price: '$0.2 per CU',
|
|
SourceUrl: 'https://apify.com/pricing/creator-plan',
|
|
SourceCheckedAt: generatedAt,
|
|
AppliesToPlan: 'Stage 2 must stay one actor run, first 3 targets, 3 requests per brand, then dataset inspection.',
|
|
Caveat: 'Actor-specific runs can also incur proxy/data/storage usage; inspect actual run usage before any second run.'
|
|
},
|
|
{
|
|
Provider: 'Apify',
|
|
Stage: '2',
|
|
PricingItem: 'Actor usage drivers',
|
|
Unit: 'memory x duration plus platform services',
|
|
Price: 'varies by CU, transfer, proxy, storage',
|
|
SourceUrl: 'https://docs.apify.com/platform/actors/running/usage-and-resources',
|
|
SourceCheckedAt: generatedAt,
|
|
AppliesToPlan: 'Browser actors and heavy pages cost more; Stage 2 should use Apify only for named gaps after DataForSEO review.',
|
|
Caveat: 'Use the first dataset run as the real cost sample; do not estimate full-catalogue scraping from generic CU pricing.'
|
|
}
|
|
]
|
|
|
|
const manifest = {
|
|
generatedAt,
|
|
ready: true,
|
|
note: 'Official pricing references for filling source-acquisition-cost-plan.json. This report does not unlock spend; budget, cost-plan, approval, preflight, and spend gates still control paid usage.',
|
|
counts: {
|
|
references: rows.length,
|
|
providers: [...new Set(rows.map(row => row.Provider))].length,
|
|
dataforseoReferences: rows.filter(row => row.Provider === 'DataForSEO').length,
|
|
apifyReferences: rows.filter(row => row.Provider === 'Apify').length
|
|
},
|
|
guardrails: [
|
|
'Record current provider pricing source and timestamp before enabling budget caps.',
|
|
'Keep DataForSEO Stage 1 at depth=10 and 9 ASINs until raw quality and actual cost are reviewed.',
|
|
'Keep Apify Stage 2 behind a DataForSEO review decision and named gap.',
|
|
'This reference report is not a substitute for checking account billing pages before spend.'
|
|
],
|
|
references: rows
|
|
}
|
|
|
|
writeFileSync(join(outRoot, 'source_acquisition_pricing_references.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
|
|
writeFileSync(join(outRoot, 'source_acquisition_pricing_references.csv'), csv(rows, ['Provider', 'Stage', 'PricingItem', 'Unit', 'Price', 'SourceUrl', 'SourceCheckedAt', 'AppliesToPlan', 'Caveat']), 'utf8')
|
|
writeFileSync(join(outRoot, 'source_acquisition_pricing_references.md'), [
|
|
'# Source acquisition pricing references',
|
|
'',
|
|
`Generated: ${generatedAt}`,
|
|
'',
|
|
manifest.note,
|
|
'',
|
|
'## Guardrails',
|
|
...manifest.guardrails.map(item => `- ${item}`),
|
|
'',
|
|
'## References',
|
|
...rows.map(row => `- ${row.Provider} Stage ${row.Stage}: ${row.PricingItem} — ${row.Price} per ${row.Unit}. Source: ${row.SourceUrl}. Caveat: ${row.Caveat}`),
|
|
'',
|
|
'## How to use this',
|
|
'- Copy the relevant source URL, checked timestamp, unit cost, and estimated total into `data/sources/budgets/source-acquisition-cost-plan.json`.',
|
|
'- Then rerun `bun run source:cost-plan`, `bun run source:approvals`, and `bun run source:spend-gate`.',
|
|
'- Do not run provider APIs just because this reference file exists.',
|
|
''
|
|
].join('\n'), 'utf8')
|
|
|
|
console.log(`Source acquisition pricing references ready: ${manifest.ready}`)
|
|
console.log(`References: ${manifest.counts.references}`)
|