{"name":"7-figure dropshipping workflow","nodes":[{"id":"7f000001-1111-4222-8333-444455550001","name":"Daily 07:00 Trigger","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[-160,300],"parameters":{"rule":{"interval":[{"field":"days","daysInterval":1}]}}},{"id":"7f000002-1111-4222-8333-444455550002","name":"Fetch Shopify Orders (24h)","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[80,300],"parameters":{"url":"https://STORE.myshopify.com/admin/api/2024-10/orders.json","sendQuery":true,"queryParameters":{"parameters":[{"name":"status","value":"any"},{"name":"created_at_min","value":"={{ $now.minus({ days: 1 }).toISO() }}"},{"name":"fields","value":"id,subtotal_price,total_line_items_price,total_discounts,total_refunded,customer,line_items"},{"name":"limit","value":"250"}]},"options":{}}},{"id":"7f000003-1111-4222-8333-444455550003","name":"Fetch Meta Blended Spend","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[80,100],"parameters":{"url":"https://graph.facebook.com/v21.0/act_ID/insights","sendQuery":true,"queryParameters":{"parameters":[{"name":"fields","value":"campaign_name,spend,purchase_roas,impressions,frequency,ctr,cpm,actions"},{"name":"level","value":"campaign"},{"name":"date_preset","value":"yesterday"}]},"options":{}}},{"id":"7f000004-1111-4222-8333-444455550004","name":"Fetch Google Ads Spend","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[80,500],"parameters":{"url":"https://googleads.googleapis.com/v18/customers/CUSTOMER_ID/googleAds:search","method":"POST","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ query: \"SELECT campaign.name, metrics.cost_micros, metrics.conversions, metrics.conversions_value, metrics.impressions FROM campaign WHERE segments.date DURING YESTERDAY\" }) }}","options":{}}},{"id":"7f000005-1111-4222-8333-444455550005","name":"Merge Paid Channels","type":"n8n-nodes-base.merge","typeVersion":3,"position":[320,300],"parameters":{"mode":"combine","combineBy":"combineByPosition","options":{}}},{"id":"7f000006-1111-4222-8333-444455550006","name":"Merge Revenue And Spend","type":"n8n-nodes-base.merge","typeVersion":3,"position":[560,300],"parameters":{"mode":"combine","combineBy":"combineByPosition","options":{}}},{"id":"7f000007-1111-4222-8333-444455550007","name":"Compute Blended Economics","type":"n8n-nodes-base.code","typeVersion":2,"position":[800,300],"parameters":{"jsCode":"// ---- Blended daily economics: revenue vs spend vs margin ----\n// Input 0 side: Shopify orders payload. Input 1 side: merged paid-channel spend.\nconst CFG = {\n  cogsRate: 0.32,          // landed product cost as % of net revenue\n  shipRate: 0.11,          // fulfilment + shipping as % of net revenue\n  pspRate: 0.029,          // payment processing\n  pspFlat: 0.30,           // per-order processing fee\n  fixedDaily: 1450,        // team, apps, warehouse, amortised daily\n  monthRevenueTarget: 1000000 / 12,\n  organicUpliftFloor: 0.05 // ignore channel noise below this share\n};\n\nconst rows = $input.all().map(i => i.json);\n\n// Shopify: sum net revenue + orders across the day's order pages\nlet grossRevenue = 0, discounts = 0, refunds = 0, orders = 0, newCustomerRevenue = 0;\nfor (const r of rows) {\n  const list = r.orders || (r.id ? [r] : []);\n  for (const o of list) {\n    grossRevenue += Number(o.total_line_items_price || o.subtotal_price || 0);\n    discounts    += Number(o.total_discounts || 0);\n    refunds      += Number(o.total_refunded || o.refunds_total || 0);\n    orders       += 1;\n    if ((o.customer && o.customer.orders_count || 1) <= 1) {\n      newCustomerRevenue += Number(o.subtotal_price || 0);\n    }\n  }\n}\nconst netRevenue = Math.max(0, grossRevenue - discounts - refunds);\n\n// Paid channels: Meta (spend, purchase_roas) + Google (cost_micros, conversions_value)\nlet metaSpend = 0, metaRevenue = 0, metaImpr = 0, metaFreqW = 0;\nlet googleSpend = 0, googleRevenue = 0;\nfor (const r of rows) {\n  for (const d of (r.data || [])) {           // Meta insights shape\n    const spend = Number(d.spend || 0);\n    const roas  = Number((d.purchase_roas && d.purchase_roas[0] && d.purchase_roas[0].value) || 0);\n    metaSpend   += spend;\n    metaRevenue += spend * roas;\n    metaImpr    += Number(d.impressions || 0);\n    metaFreqW   += Number(d.frequency || 0) * Number(d.impressions || 0);\n  }\n  for (const g of (r.results || [])) {        // Google Ads GAQL shape\n    googleSpend   += Number(g.metrics && g.metrics.cost_micros || 0) / 1e6;\n    googleRevenue += Number(g.metrics && g.metrics.conversions_value || 0);\n  }\n}\n\nconst adSpend = metaSpend + googleSpend;\nconst trackedRevenue = metaRevenue + googleRevenue;\nconst aov = orders ? netRevenue / orders : 0;\n\n// Cost stack -> contribution margin AFTER ads\nconst cogs = netRevenue * CFG.cogsRate;\nconst shipping = netRevenue * CFG.shipRate;\nconst psp = netRevenue * CFG.pspRate + orders * CFG.pspFlat;\nconst grossProfit = netRevenue - cogs - shipping - psp;\nconst contribution = grossProfit - adSpend;\nconst netProfit = contribution - CFG.fixedDaily;\n\n// Blended metrics a 7-figure operator actually reads\nconst blendedRoas = adSpend ? netRevenue / adSpend : 0;\nconst mer = blendedRoas;                                   // same number, ops name\nconst trackedRoas = adSpend ? trackedRevenue / adSpend : 0;\nconst attributionGap = trackedRevenue ? netRevenue / trackedRevenue : 1; // >1 = under-reporting\nconst marginRate = netRevenue ? grossProfit / netRevenue : 0;\nconst breakevenRoas = marginRate > 0 ? 1 / marginRate : 99;  // ROAS where contribution = 0\nconst targetRoas = breakevenRoas * 1.35;                     // 35% cushion = the real floor\nconst acos = netRevenue ? adSpend / netRevenue : 0;\nconst cac = orders ? adSpend / orders : 0;\nconst avgFrequency = metaImpr ? metaFreqW / metaImpr : 0;\nconst newCustomerShare = netRevenue ? newCustomerRevenue / netRevenue : 0;\n\n// Month pacing projection (linear run-rate on days elapsed)\nconst now = new Date();\nconst dayOfMonth = now.getUTCDate();\nconst daysInMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate();\nconst mtdRevenue = netRevenue * dayOfMonth;                 // proxy: today's rate held so far\nconst projectedMonth = (mtdRevenue / dayOfMonth) * daysInMonth;\nconst pacePct = CFG.monthRevenueTarget ? projectedMonth / CFG.monthRevenueTarget : 0;\nconst revenueNeededPerDay = Math.max(0,\n  (CFG.monthRevenueTarget - mtdRevenue) / Math.max(1, daysInMonth - dayOfMonth));\n\nconst round = (n, d = 2) => Math.round(n * 10 ** d) / 10 ** d;\n\nreturn [{ json: {\n  date: now.toISOString().slice(0, 10),\n  orders,\n  net_revenue: round(netRevenue),\n  aov: round(aov),\n  ad_spend: round(adSpend),\n  meta_spend: round(metaSpend),\n  google_spend: round(googleSpend),\n  tracked_revenue: round(trackedRevenue),\n  tracked_roas: round(trackedRoas),\n  attribution_gap: round(attributionGap),\n  blended_roas: round(blendedRoas),\n  mer: round(mer),\n  breakeven_roas: round(breakevenRoas),\n  target_roas: round(targetRoas),\n  margin_rate: round(marginRate, 4),\n  gross_profit: round(grossProfit),\n  contribution_margin: round(contribution),\n  net_profit: round(netProfit),\n  acos: round(acos, 4),\n  cac: round(cac),\n  avg_frequency: round(avgFrequency, 2),\n  new_customer_share: round(newCustomerShare, 4),\n  projected_month_revenue: round(projectedMonth),\n  pace_vs_target: round(pacePct, 3),\n  revenue_needed_per_day: round(revenueNeededPerDay),\n  headroom_vs_breakeven: round(blendedRoas - breakevenRoas)\n} }];"}},{"id":"7f000008-1111-4222-8333-444455550008","name":"Blended ROAS Under Breakeven?","type":"n8n-nodes-base.if","typeVersion":2,"position":[1040,300],"parameters":{"conditions":{"options":{"caseSensitive":true,"version":2},"combinator":"and","conditions":[{"id":"c1","leftValue":"={{ $json.blended_roas }}","rightValue":"={{ $json.breakeven_roas }}","operator":{"type":"number","operation":"lt"}}]},"options":{}}},{"id":"7f000009-1111-4222-8333-444455550009","name":"Flag Margin Emergency","type":"n8n-nodes-base.set","typeVersion":3.3,"position":[1280,100],"parameters":{"assignments":{"assignments":[{"id":"a1","name":"margin_state","value":"emergency","type":"string"},{"id":"a2","name":"spend_guardrail","value":"={{ Math.round($json.ad_spend * 0.7) }}","type":"number"},{"id":"a3","name":"note","value":"=Blended {{ $json.blended_roas }} vs breakeven {{ $json.breakeven_roas }} — cap spend today","type":"string"}]},"options":{}}},{"id":"7f00000a-1111-4222-8333-44445555000a","name":"Mark Margin Healthy","type":"n8n-nodes-base.set","typeVersion":3.3,"position":[1280,500],"parameters":{"assignments":{"assignments":[{"id":"a1","name":"margin_state","value":"healthy","type":"string"},{"id":"a2","name":"spend_guardrail","value":"={{ Math.round($json.ad_spend * 1.2) }}","type":"number"},{"id":"a3","name":"note","value":"=Headroom {{ $json.headroom_vs_breakeven }} above breakeven — scale is allowed","type":"string"}]},"options":{}}},{"id":"7f00000b-1111-4222-8333-44445555000b","name":"Fetch Inventory Snapshot","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1520,300],"parameters":{"url":"https://STORE.myshopify.com/admin/api/2024-10/products.json","sendQuery":true,"queryParameters":{"parameters":[{"name":"fields","value":"id,title,variants"},{"name":"limit","value":"250"}]},"options":{}}},{"id":"7f00000c-1111-4222-8333-44445555000c","name":"Score Inventory Risk","type":"n8n-nodes-base.code","typeVersion":2,"position":[1760,300],"parameters":{"jsCode":"// ---- Inventory days-of-cover risk scoring ----\n// Shopify inventory levels joined with 7/30-day sell-through velocity.\nconst LEAD_TIME_DAYS = 21;      // China -> 3PL door to door\nconst SAFETY_DAYS = 10;         // buffer on top of lead time\nconst OVERSTOCK_DAYS = 90;      // capital sitting still\nconst rows = $input.all().map(i => i.json);\n\nconst skus = [];\nfor (const r of rows) {\n  for (const v of (r.variants || r.inventory_levels || (r.sku ? [r] : []))) {\n    const sold7  = Number(v.units_sold_7d ?? v.sold_7d ?? 0);\n    const sold30 = Number(v.units_sold_30d ?? v.sold_30d ?? sold7 * 4);\n    // weighted velocity: recent demand matters more, but 30d damps a spike day\n    const velocity = (sold7 / 7) * 0.65 + (sold30 / 30) * 0.35;\n    const onHand = Number(v.available ?? v.inventory_quantity ?? 0);\n    const inbound = Number(v.incoming ?? v.inbound_quantity ?? 0);\n    const price = Number(v.price ?? 0);\n    const daysCover = velocity > 0 ? onHand / velocity : 999;\n    const daysCoverWithInbound = velocity > 0 ? (onHand + inbound) / velocity : 999;\n    const reorderPoint = Math.ceil(velocity * (LEAD_TIME_DAYS + SAFETY_DAYS));\n    const reorderQty = Math.max(0, Math.ceil(velocity * (LEAD_TIME_DAYS + SAFETY_DAYS + 30)) - onHand - inbound);\n    const revenueAtRisk = Math.round(velocity * price * Math.max(0, LEAD_TIME_DAYS - daysCoverWithInbound));\n    const capitalIdle = daysCover > OVERSTOCK_DAYS ? Math.round(onHand * price * 0.4) : 0;\n\n    let status = 'healthy';\n    if (daysCoverWithInbound < LEAD_TIME_DAYS) status = 'stockout_risk';\n    else if (daysCover < LEAD_TIME_DAYS + SAFETY_DAYS) status = 'reorder_now';\n    else if (daysCover > OVERSTOCK_DAYS) status = 'overstock';\n\n    // risk score 0-100: urgency (how far under lead time) x money on the line\n    const urgency = Math.max(0, Math.min(1, (LEAD_TIME_DAYS - daysCoverWithInbound) / LEAD_TIME_DAYS));\n    const money = Math.min(1, (revenueAtRisk + capitalIdle) / 5000);\n    const riskScore = Math.round((urgency * 0.6 + money * 0.4) * 100);\n\n    skus.push({\n      sku: v.sku || v.inventory_item_id || 'unknown',\n      product: v.title || v.product_title || '',\n      on_hand: onHand,\n      inbound,\n      velocity_per_day: Math.round(velocity * 100) / 100,\n      days_of_cover: Math.round(daysCover * 10) / 10,\n      days_of_cover_with_inbound: Math.round(daysCoverWithInbound * 10) / 10,\n      reorder_point: reorderPoint,\n      reorder_qty: reorderQty,\n      revenue_at_risk: revenueAtRisk,\n      capital_idle: capitalIdle,\n      status,\n      risk_score: riskScore\n    });\n  }\n}\n\n// dedupe by sku (a SKU can appear in several locations) — keep worst cover, sum stock\nconst bySku = new Map();\nfor (const s of skus) {\n  const prev = bySku.get(s.sku);\n  if (!prev) { bySku.set(s.sku, s); continue; }\n  prev.on_hand += s.on_hand;\n  prev.inbound += s.inbound;\n  prev.days_of_cover = Math.min(prev.days_of_cover, s.days_of_cover);\n  prev.risk_score = Math.max(prev.risk_score, s.risk_score);\n  prev.revenue_at_risk += s.revenue_at_risk;\n}\n\nconst list = [...bySku.values()].sort((a, b) => b.risk_score - a.risk_score);\nconst critical = list.filter(s => s.status === 'stockout_risk' || s.status === 'reorder_now');\n\nreturn [{ json: {\n  skus: list,\n  critical_skus: critical,\n  critical_count: critical.length,\n  overstock_count: list.filter(s => s.status === 'overstock').length,\n  total_revenue_at_risk: critical.reduce((a, s) => a + s.revenue_at_risk, 0),\n  worst_sku: list[0] ? list[0].sku : null,\n  worst_days_cover: list[0] ? list[0].days_of_cover_with_inbound : null\n} }];"}},{"id":"7f00000d-1111-4222-8333-44445555000d","name":"Any SKU Inside Lead Time?","type":"n8n-nodes-base.if","typeVersion":2,"position":[2000,300],"parameters":{"conditions":{"options":{"caseSensitive":true,"version":2},"combinator":"and","conditions":[{"id":"c1","leftValue":"={{ $json.critical_count }}","rightValue":0,"operator":{"type":"number","operation":"gt"}}]},"options":{}}},{"id":"7f00000e-1111-4222-8333-44445555000e","name":"Create Restock POs","type":"n8n-nodes-base.airtable","typeVersion":2.1,"position":[2240,100],"parameters":{"operation":"create","base":{"__rl":true,"value":"appXXXXXXXX","mode":"id"},"table":{"__rl":true,"value":"tblRESTOCK","mode":"id"},"columns":{"mappingMode":"autoMapInputData","value":{}},"options":{}}},{"id":"7f00000f-1111-4222-8333-44445555000f","name":"Note Inventory Clear","type":"n8n-nodes-base.set","typeVersion":3.3,"position":[2240,500],"parameters":{"assignments":{"assignments":[{"id":"a1","name":"inventory_state","value":"clear","type":"string"},{"id":"a2","name":"note","value":"=No SKU inside the 21-day lead time. Worst cover: {{ $json.worst_days_cover }} days","type":"string"}]},"options":{}}},{"id":"7f000010-1111-4222-8333-444455550010","name":"Build Morning Briefing","type":"n8n-nodes-base.code","typeVersion":2,"position":[2480,300],"parameters":{"jsCode":"// ---- Morning briefing: the three actions that actually matter today ----\nconst e = $('Compute Blended Economics').first().json;\nconst inv = $('Score Inventory Risk').first().json;\n\nconst money = n => '$' + Math.round(Number(n) || 0).toLocaleString('en-US');\nconst pct = n => Math.round((Number(n) || 0) * 100) + '%';\n\n// Every candidate action carries an impact estimate in dollars/day.\n// Ranking is impact x confidence, so we never ship a \"nice to know\" as action #1.\nconst candidates = [];\n\nif (e.blended_roas < e.breakeven_roas) {\n  candidates.push({\n    action: 'Cut spend on the bottom-decile ad sets today',\n    why: 'Blended ROAS ' + e.blended_roas + ' is under breakeven ' + e.breakeven_roas + ' — every extra dollar is buying losses.',\n    impact: Math.round(Math.abs(e.contribution_margin)),\n    confidence: 0.95\n  });\n} else if (e.blended_roas > e.target_roas) {\n  candidates.push({\n    action: 'Raise budgets 20% on the top 3 spenders',\n    why: 'Blended ROAS ' + e.blended_roas + ' clears the ' + e.target_roas + ' target with ' + e.headroom_vs_breakeven + ' of headroom.',\n    impact: Math.round(e.ad_spend * 0.2 * (e.blended_roas - e.breakeven_roas) * e.margin_rate * 10),\n    confidence: 0.8\n  });\n}\n\nif (e.attribution_gap > 1.35) {\n  candidates.push({\n    action: 'Trust blended, not platform ROAS — reset bid targets',\n    why: 'Platform reports ' + e.tracked_roas + ' vs blended ' + e.blended_roas + ' (gap ' + e.attribution_gap + 'x). Under-reporting is hiding winners.',\n    impact: Math.round(e.ad_spend * 0.15),\n    confidence: 0.6\n  });\n}\n\nif (e.avg_frequency > 2.4) {\n  candidates.push({\n    action: 'Ship 3 new creative angles — frequency is at ' + e.avg_frequency,\n    why: 'Above 2.4 on a 7-day window CPMs climb and CVR decays within a week.',\n    impact: Math.round(e.ad_spend * 0.12),\n    confidence: 0.65\n  });\n}\n\nif (e.new_customer_share < 0.55) {\n  candidates.push({\n    action: 'Shift budget to prospecting — new-customer revenue is ' + pct(e.new_customer_share),\n    why: 'Retargeting is inflating blended ROAS while the top of funnel starves.',\n    impact: Math.round(e.net_revenue * 0.05),\n    confidence: 0.55\n  });\n}\n\nfor (const s of (inv.critical_skus || []).slice(0, 3)) {\n  candidates.push({\n    action: 'Reorder ' + s.sku + ' — ' + s.reorder_qty + ' units (' + s.days_of_cover_with_inbound + ' days cover)',\n    why: money(s.revenue_at_risk) + ' of revenue goes dark if the PO slips past today.',\n    impact: s.revenue_at_risk,\n    confidence: 0.9\n  });\n}\n\nif (inv.overstock_count > 0) {\n  candidates.push({\n    action: 'Bundle or discount ' + inv.overstock_count + ' overstocked SKUs',\n    why: 'Over 90 days of cover — that is working capital sitting in a warehouse.',\n    impact: 800,\n    confidence: 0.5\n  });\n}\n\nif (e.pace_vs_target < 0.9) {\n  candidates.push({\n    action: 'Pace gap: need ' + money(e.revenue_needed_per_day) + '/day to hit target',\n    why: 'Projected month ' + money(e.projected_month_revenue) + ' = ' + pct(e.pace_vs_target) + ' of target.',\n    impact: Math.round(e.revenue_needed_per_day * 0.3),\n    confidence: 0.7\n  });\n}\n\n// dedupe identical actions, rank by expected value, keep three\nconst seen = new Set();\nconst top3 = candidates\n  .filter(c => (seen.has(c.action) ? false : seen.add(c.action)))\n  .map(c => ({ ...c, ev: Math.round(c.impact * c.confidence) }))\n  .sort((a, b) => b.ev - a.ev)\n  .slice(0, 3);\n\nconst verdict = e.blended_roas < e.breakeven_roas ? '🔴 BURNING'\n  : e.blended_roas < e.target_roas ? '🟡 THIN'\n  : '🟢 PROFITABLE';\n\nconst lines = [\n  '*' + verdict + ' — ' + e.date + '*',\n  'Revenue ' + money(e.net_revenue) + '  |  Spend ' + money(e.ad_spend) + '  |  Net ' + money(e.net_profit),\n  'Blended ROAS ' + e.blended_roas + ' (breakeven ' + e.breakeven_roas + ', target ' + e.target_roas + ')',\n  'AOV ' + money(e.aov) + '  |  CAC ' + money(e.cac) + '  |  Margin ' + pct(e.margin_rate),\n  'Pace ' + pct(e.pace_vs_target) + ' of target — projecting ' + money(e.projected_month_revenue),\n  'Inventory: ' + inv.critical_count + ' SKUs critical, ' + money(inv.total_revenue_at_risk) + ' at risk',\n  '',\n  '*Do these three today:*',\n  ...top3.map((c, i) => (i + 1) + '. ' + c.action + '\\n    → ' + c.why + ' (est. ' + money(c.ev) + '/day)')\n];\n\nreturn [{ json: {\n  ...e,\n  verdict,\n  critical_skus: inv.critical_count,\n  revenue_at_risk: inv.total_revenue_at_risk,\n  actions: top3,\n  action_1: top3[0] ? top3[0].action : 'Hold — no action clears the impact bar today',\n  action_2: top3[1] ? top3[1].action : '',\n  action_3: top3[2] ? top3[2].action : '',\n  briefing: lines.join('\\n')\n} }];"}},{"id":"7f000011-1111-4222-8333-444455550011","name":"Send Briefing To Slack","type":"n8n-nodes-base.slack","typeVersion":2.2,"position":[2720,140],"parameters":{"select":"channel","channelId":{"__rl":true,"value":"#daily-ops","mode":"name"},"text":"={{ $json.briefing }}","otherOptions":{}}},{"id":"7f000012-1111-4222-8333-444455550012","name":"Log Daily Snapshot","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[2720,460],"parameters":{"operation":"append","documentId":{"__rl":true,"value":"SHEET_ID","mode":"id"},"sheetName":{"__rl":true,"value":"gid=0","mode":"list","cachedResultName":"DailyPnL"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[]},"options":{}}},{"id":"7f0000s1-1111-4222-8333-4444555500s1","name":"Note: Pull The Numbers","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[-200,-160],"parameters":{"content":"## 1. PULL THE NUMBERS\nShopify net revenue + Meta spend/purchase_roas + Google cost_micros, all for yesterday. Merged so one Code node can see revenue and spend side by side.","height":300,"width":520,"color":4}},{"id":"7f0000s2-1111-4222-8333-4444555500s2","name":"Note: Margin Math","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[780,-160],"parameters":{"content":"## 2. BLENDED ROAS vs BREAKEVEN\nCOGS 32% + ship 11% + PSP 2.9% -> margin rate -> breakeven ROAS = 1/margin, target = breakeven x 1.35. Under breakeven caps spend at 70%; above it unlocks a 20% scale.","height":300,"width":520,"color":3}},{"id":"7f0000s3-1111-4222-8333-4444555500s3","name":"Note: Inventory + Briefing","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[1740,-160],"parameters":{"content":"## 3. DAYS OF COVER + THE THREE ACTIONS\nVelocity = 65% of 7d rate + 35% of 30d rate. Cover under the 21-day lead time = stockout risk -> Airtable PO. Every candidate action is ranked by impact x confidence; only the top 3 ship.","height":300,"width":520,"color":5}}],"connections":{"Daily 07:00 Trigger":{"main":[[{"node":"Fetch Shopify Orders (24h)","type":"main","index":0},{"node":"Fetch Meta Blended Spend","type":"main","index":0},{"node":"Fetch Google Ads Spend","type":"main","index":0}]]},"Fetch Meta Blended Spend":{"main":[[{"node":"Merge Paid Channels","type":"main","index":0}]]},"Fetch Google Ads Spend":{"main":[[{"node":"Merge Paid Channels","type":"main","index":1}]]},"Fetch Shopify Orders (24h)":{"main":[[{"node":"Merge Revenue And Spend","type":"main","index":0}]]},"Merge Paid Channels":{"main":[[{"node":"Merge Revenue And Spend","type":"main","index":1}]]},"Merge Revenue And Spend":{"main":[[{"node":"Compute Blended Economics","type":"main","index":0}]]},"Compute Blended Economics":{"main":[[{"node":"Blended ROAS Under Breakeven?","type":"main","index":0}]]},"Blended ROAS Under Breakeven?":{"main":[[{"node":"Flag Margin Emergency","type":"main","index":0}],[{"node":"Mark Margin Healthy","type":"main","index":0}]]},"Flag Margin Emergency":{"main":[[{"node":"Fetch Inventory Snapshot","type":"main","index":0}]]},"Mark Margin Healthy":{"main":[[{"node":"Fetch Inventory Snapshot","type":"main","index":0}]]},"Fetch Inventory Snapshot":{"main":[[{"node":"Score Inventory Risk","type":"main","index":0}]]},"Score Inventory Risk":{"main":[[{"node":"Any SKU Inside Lead Time?","type":"main","index":0}]]},"Any SKU Inside Lead Time?":{"main":[[{"node":"Create Restock POs","type":"main","index":0}],[{"node":"Note Inventory Clear","type":"main","index":0}]]},"Create Restock POs":{"main":[[{"node":"Build Morning Briefing","type":"main","index":0}]]},"Note Inventory Clear":{"main":[[{"node":"Build Morning Briefing","type":"main","index":0}]]},"Build Morning Briefing":{"main":[[{"node":"Send Briefing To Slack","type":"main","index":0},{"node":"Log Daily Snapshot","type":"main","index":0}]]}},"settings":{"executionOrder":"v1"},"pinData":{}}