Two bugs fixed:
1. Removed hardcoded year===2025 filter (data is already pre-filtered)
2. ASINs with ad spend but no sales records were silently dropped —
now appended as extra rows so the total PPC spend matches ADs Weekly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MktDataView now receives filteredData/filteredAdsData so the global
FilterBar controls the tab's data. Removed the local "All Categories"
dropdown that previously sat next to the Include COGS toggle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fetch-deals, fetch-promos, fetch-chargebacks with a single
/api/fetch-mkt-data?file=deals|promos|chargebacks endpoint.
Update MktDataView fetch calls accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all mock data in the Profitability Dashboard with live data:
- Add 3 new API routes (fetch-deals, fetch-promos, fetch-chargebacks) proxying Dropbox Excel files
- MktDataView now accepts rawData/adsData props and fetches+parses the 3 new files on mount
- SELL OUT and units aggregated globally across all marketplaces from rawData
- PPC Spend aggregated globally from adsData; ACoS calculated as spend/sales
- Deals (col A→C), Promos (col E→K), Chargebacks (col AN→B) parsed and summed per ASIN
- Category filter populated from product line metadata
- Loading skeleton shown while files are fetching
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BSRRecord.market is stored as short codes ('DE', 'IT', etc.) from the
Excel file, but the chart was comparing against full names ('Amazon DE',
'Amazon IT', etc.) — causing bsrRecordsForMarket to always be empty and
the BSR line to never render. Added normalizeBsrMarket() to map short
codes to full names before filtering. Also removed the debug strip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use React's useDeferredValue to decouple UI responsiveness from
expensive data reprocessing. Checkboxes now update immediately on
click; filterData/filterAdsData/filterBsrData and all downstream
useMemos run as a low-priority background pass. Added local optimistic
state in MultiSelectDropdown as a belt-and-suspenders layer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- winner if posterior probability > 50%, unsuccessful otherwise
- Removes inconclusive — binary outcome based on Bayesian signal
- Label "Loser" renamed to "Unsuccessful"
- Updated all stored experiment verdicts in DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split by comma/semicolon/newline first; only split by spaces for
non-LINE: tokens so "LINE:MAGIC DOUGH" isn't broken into two parts.
Also fix placeholder and repair stored experiment data via API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detail category BSR is more granular and relevant per ASIN. Falls back
to topLevelBSR if detailLevelBSR is null for a record.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Math.max(...largeArray) crashes when combinedAdsData has thousands of
records. Replaced with a simple for-loop to find the max year safely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New BSRUnitsCorrelationChart component added to the Vendor tab showing:
- Per-marketplace tabs (DE, ES, FR, IT, UK) with market accent colors
- Dual-axis combo chart: bars (units sold, right axis) + line (BSR rank, left axis)
- Inverted BSR axis by default (lower rank = top) with toggle to flip
- Pearson r correlation calculated and displayed with strength interpretation
- Wired to existing combinedAdsData (filtered) and filteredBsrData
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The badge was rendered outside the stockMap conditional, causing it to
appear independently of the Amazon stock badge. Now it's grouped inside
the block, always appearing immediately next to VendorStockBadge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Wrap component with memo() to prevent unnecessary re-renders
- Restructure DOM hierarchy to avoid nested inline-flex containers
- Center hover popup with left-1/2 -translate-x-1/2
- Add pointer-events-none to popup to prevent hover flickering
- Improve popup spacing and sizing
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
The BuyBoxWarningBadge was appearing twice - once next to the SKU and once next to Amazon stock. Now it only appears next to Amazon stock as requested.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Each market line (DE/ES/FR/IT/UK) now renders with its own color across
Top Level BSR, Detail Level BSR, and Average Rating charts, along with
per-market legend entries. Removes hardcoded single-color approach.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add translateCategory() with a full DE/FR/IT/ES → EN map covering
all top-level and detail categories found in the BSR data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use BarChart with rounded corners for modern look
- Remove vertical grid lines for cleaner appearance
- Add hover cursor effect on tooltip
- Y-axis reversed for BSR charts (lower = better)
- Normal Y-axis for Rating chart (higher = better)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Replace bar charts with area charts featuring:
- Gradient fill effects for modern look
- Smooth monotone curves
- Proper Y-axis orientation (reversed for BSR where lower is better)
- Color-coded by market with transparency
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Convert Top Level BSR, Detail Level BSR, and Average Rating charts
from LineChart to BarChart for better week-over-week comparison.
Each market now displays as colored bars per week instead of lines.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
FR/UK/DE sheets have a 'Status' column that appears before 'Reason',
causing the dynamic detector to pick the wrong column.
Use confirmed indices: FR=col S(18), UK=col J(9), DE=col N(13).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Inventory sheets like 'INV ITALY' were being incorrectly matched as
buybox sheets, adding all their ASINs as false BB lost entries.
Now only sheets starting with 'BB' are processed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fragile header/column-index approach with pattern-based ASIN detection:
- Scan all cells for Amazon ASIN pattern (B[0-9A-Z]{9}) to auto-detect the ASIN column regardless of headers or position
- Detect country from sheet name with flexible matching (no hardcoded sheet name list)
- Detect reason column from header keywords, no hardcoded column indices
- Remove all hardcoded fallback indices (col 13, 18, 9, etc.) that caused empty results
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Force reasonIdx to column N (13) for BB_ES sheet, same as DE/FR/UK, so dynamic header detection can't override to a wrong column
- Fall back to 'BB Lost' when reason cell is empty instead of skipping the ASIN entirely
- Add B095K8948Z to debug logging alongside B0D3874WSD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The badge was only rendered for dim==='asin'|'sku'. When pivoting by
title (the default view) the BuyBox warning was silently absent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous fix only handled the unambiguous case (day > 12). Dates like
"5/1/26" or "12/1/26" (Jan 5 / Jan 12, 2026) were falling through to
JS's new Date() which parsed them as US format MM/DD/YY, assigning them
to May and December instead of January.
Now any 3-part slash date with a 2-digit year in position 3 and a valid
month in position 2 is treated as DD/M/YY (Spanish/EU convention),
fixing weeks 2-3 of January (days 5-18) showing zero sell-out.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add support for European day-first date format (e.g. "23/2/26" = 23 Feb 2026)
in the sell-out CSV pipeline so months and years are correctly extracted from
column C of Amazon Sell Out 2023-2025.csv.
- normalizeMonth: detect DD/MM/YY when first part > 12, return "Mon-YY"
- mapRowToRecord: add 'C', 'Date', 'Fecha', 'DATA' to month column aliases
- validateSellOutHeaders: accept date columns as substitute for YEAR + MONTH
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Agregar tarjeta con SKU, ASIN y título al inicio de los gráficos
- Incluir Buy Box Warning Badge si el producto tiene issues
- Solo se muestra cuando hay un único ASIN seleccionado
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
All vendor files are linked via Dropbox, making manual upload unnecessary.
Removes the Upload Vendor CSV button, handleVendorUpload handler, and processVendorCSV import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The free-text ASIN search was unclear and not working as expected.
Replace it with a proper MultiSelectDropdown (same as Market/Category
filters) — selecting an ASIN now strictly filters chart data to that
ASIN only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add date? field to BSRRecord (ISO string YYYY-MM-DD)
- processBSRExcel now extracts and stores the Date column as an ISO date
(handles both Excel serial numbers and string dates)
- VendorDataView groups chart data by date (daily) when dates are available,
falling back to weekly buckets — eliminates straight-line charts caused
by only 2 weekly data points
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix critical regex bug: /\\d+/ was matching literal '\d' instead of
digits, causing all rows to be rejected (week always = 0)
- Add VendorCSV format support: 'Top Level Category (Rank)', 'Date', etc.
- Derive ISO week number from Date column when no Week column exists
- Process all sheets (not just first) to handle multi-tab workbooks
- Log column names on load to aid future debugging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrite api/fetch-bsr.ts to proxy BSR.xlsx from the Dropbox URL,
matching the same pattern as fetch-buybox.ts and other data sources
- Add /api/fetch-bsr proxy in vite.config.ts for local dev
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VendorDataView was refactored to receive BSR data as a prop but App.tsx
was not updated to pass it, causing the component to crash on undefined
and show a blank screen. Also fixes supabase.ts type errors and removes
dead code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change getWeekStartSunday to getISOWeekMonday for timestamp calculation
- Ensures week alignment between data aggregation and ISO week range calculation
- Fixes incorrect treatment_after average calculation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add ISO week calculation functions (getISOWeek, getISOWeekMonday, calculateISOWeekRange)
- Expand experiment dates to full ISO weeks (Monday-Sunday) instead of exact date ranges
- Use actual data.length for averaging metrics instead of theoretical durationWeeks
- Baseline now takes same number of complete weeks immediately before experiment
Fixes incorrect units sold average calculation (was 6.5, now correctly shows 4.33 for 13 units over 3 weeks)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
The generic regex /sale/i in ads column detection was matching "Advertising Cost
of Sales" (the ACOS % column) before reaching "7 day total sales" (the actual
attributed sales amount). This caused attributedSales30d to receive the ACOS
percentage instead of the real sales value, making experiment ACOS = 0 or 100%.
- Replace /sale/i with specific regexes: /\d+\s*day.*sale/i, /total\s+sale/i, etc.
- Replace /cost/i with regexes that exclude "cost of sales" columns
- Replace /unit/i with specific regexes for unit columns
- Add diagnostic logging for ads Excel column headers and first-row values
- Revert ACOS 100% fallback (root cause now fixed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change ?? to || for salesAds/units/revenue in weekly aggregation to guard against NaN
- Add || 0 fallback to ads-only records in mergeSalesAndAdsData
- Fix parseCurrency to check isNaN on all EU-format return paths
- Handle ACOS edge case: cost > 0 with adRevenue = 0 now returns 100% instead of 0%
- Add diagnostic console logging to computeDiD for data flow tracing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow pasting multiple ASINs separated by spaces in any MultiSelectDropdown
search field and pressing Enter to auto-select all matching options.
Also switch ads CSV/Excel parsing to header-based column mapping for
robustness across different file formats.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace undefined input-field CSS class with explicit Tailwind dark theme
classes (bg-slate-800, border-slate-700, text-slate-200) to prevent white
background on form fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the basic CRUD experiment tracker with a scientifically rigorous A/B testing system:
- Add DiD analysis engine (services/experimentAnalysis.ts) that computes treatment vs control
group comparisons across 7 metrics (units, sessions, CVR, CTR, ROAS, revenue, ACOS)
- Implement Bayesian verdict system (Winner/Loser/Inconclusive) using posterior probability
with normal CDF approximation (Abramowitz & Stegun erf, no external deps)
- Build counterfactual time series for trend charts (actual vs estimated without change)
- Rewrite ExperimentsView as single component with 3 inline sub-views (list, detail, create)
replacing the previous modal-based ExperimentDetail and ExperimentForm
- Add control group support, change annotations (before→after diffs), and SEO experiment type
- New types: ExperimentChangeAnnotation, DiDMetricResult, DifferenceInDifferencesResult,
ExperimentVerdict
- Simplify App.tsx by removing experiment modal state (5 useState hooks eliminated)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>