openpyxl's default (read/write) loader deserializes pivot cache
records, which hangs for minutes on Amazon media plans that use pivot
tables. The GCP LB then cuts the request off with "upstream request
timeout" / "stream timeout".
read_only=True skips pivot cache parsing entirely, and our code only
uses iter_rows / sheetnames which are both supported in that mode.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Upload Excel media plans per client. On QC analysis, automatically
match the uploaded file's name against the media plan's Asset IDs
to validate dimensions and file type, and include the media plan
context (country, language, placement, vendor) in QC check prompts.
- New backend/media_plan_processor.py: Excel parsing, fuzzy filename
matching, dimension/file-type validation, prompt context builder
- New backend/media_plans/ directory for storage
- API endpoints: POST/GET/DELETE /api/media_plan
- Settings modal: new "Media Plan" tab for upload/manage
- Analysis flow: auto-match + validation in response + context in prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>