Fixed two issues:
1. Removed 'Bearer' prefix from Authorization header (OMG API expects just the key)
2. Fixed private property access error (hardcoded endpoint URL instead of accessing $omgService->config)
OMG API now sends: Authorization: PeyJvcmciOiIy...
Instead of: Authorization: Bearer PeyJvcmciOiIy...
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issue: PHP deprecation warnings from league/csv were being output as HTML
(<br /><b>...) which broke JSON parsing in browser.
Fix: Set display_errors=0 in process-csv.php while keeping log_errors=1.
Errors still logged to error_log but not output to browser.
Reverted test-upload endpoint back to process-csv.php.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added log message at start to confirm correct version is running.
This helps identify if browser is caching old JavaScript or server is serving old PHP.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
OMG API Debug Logging:
- Log full URL being called
- Log API key (first 20 chars for security)
- Log HTTP response code
- Log response body (first 500 chars)
- Log campaign number and business area extraction
- Log business unit mapping result
ApplicationLogger Class:
- Structured JSON logging to logs/application.log
- Track all actions: master_asset_submission, global_to_local_transform, box_upload
- Capture user email, timestamp, IP address, user agent
- Methods for reporting: getRecentLogs(), getLogsByAction(), getLogsByUser()
- Generate statistics: total actions, by user, by action, errors
Email Configuration:
- Configured SMTP via Mailgun (smtp.mailgun.org:587)
- Using twist@mail.dev.oliver.solutions
- Emails sent to logged-in user
This enables full audit trail and troubleshooting capability.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Email Configuration:
- Added SMTP support via Mailgun (smtp.mailgun.org:587)
- EmailService now supports both Mailgun API and SMTP
- Configured to use twist@mail.dev.oliver.solutions
- Emails sent to logged-in user (SSO email or local dev email)
OMG API:
- Enabled OMG API lookup in process-csv.php
- API key configured in config.php
- Looks up business unit from campaign number
- Falls back to 'ERROR' if business unit not recognized
SMTP Implementation:
- Full SMTP protocol with AUTH LOGIN
- Proper error handling and logging
- Fallback to Mailgun API if SMTP fails
Notifications sent to user email:
- Process started notification
- Process completed notification (with file count)
- Error notifications
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issue: PHP's iterator_to_array() returns associative array with numeric keys
which JavaScript receives as an object {1: {...}, 2: {...}}, not an array.
Fix: Convert object to array using Object.values() before rendering table.
Added to both initial preview and file selector preview.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added console.log statements to track:
- Preview data availability
- Row count
- Headers extraction
- Table HTML generation
This will help identify why the table isn't rendering.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed {country} to {$country} in filename template.
Now generates correct filenames like:
- OMG1601654_GlobalACIngest_TESTING-GB_1763418477.csv
- OMG1601654_GlobalACIngest_TESTING-ES_1763418477.csv
etc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- Initial preview now displays immediately from response data
- Show ALL rows in preview table (not limited to 20)
- File selector properly switches between all 16 CSVs
- Each file shows complete data when selected
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive documentation:
- Updated app title to 'L'Oréal OMG Assistant Global'
- Detailed Global to Local workflow (6 stages)
- Input CSV requirements and format
- ISO codes configuration (16 markets in config.php)
- Output file naming and structure
- Preview and download options
- User approval workflow
- Error handling examples for all stages
- API endpoints documentation
- Configuration sections for OMG API and Email
Clarified that ISO codes are in config.php and fully editable.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Title Changes:
- App title: "L'Oréal OMG Assistant Global"
- Tab 1: "Master Global Asset Submission"
- Upload button: "Approve & Upload to OMG"
Preview Enhancements:
- Dropdown selector to preview all 16 CSV files individually
- Shows filename with ISO code (e.g., "en-GB - OMG1601654_...")
- Switch between files to view complete data for each
- Show ALL rows (not just first 20)
Download Features:
- "Download Current File" - Download the currently previewed CSV
- "Download All Files (ZIP)" - Download all 16 CSVs as a ZIP archive
- get-csv-preview.php: Endpoint to fetch any file for preview
- download-all-csv.php: Creates ZIP with all CSVs
UX Improvements:
- File selector styled with brand colors
- Clear labeling of which file is being previewed
- Easy navigation between all regional CSVs
- Test before upload with full data visibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Line 180 had */" which caused PHP parse error.
Changed to just */ to close comment block properly.
This was causing the 500 Internal Server Error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added error_log debugging to process-csv.php
- Fixed test-csv.php syntax (removed use statements in code)
- Created test-process2.php for step-by-step class loading test
- All service classes load successfully in tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed 'use' statements outside namespace context.
Changed to fully qualified class names:
- League\Csv\Reader
- League\Csv\Writer
- Carbon\Carbon
This fixes PHP 500 errors from improper use statements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Moved session_start() to top of process-csv.php before any output.
Removed duplicate session_start() call.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Key Changes:
- Fixed CSV transformation to create 16 separate files (one per ISO code)
- Each CSV has all input rows with Language/Country replaced
- Handles Excel Sep=, prefix correctly
- Parses date format "24 Mar 2025 00:00" from sample CSV
- Skip OMG API for testing (use business unit "TESTING")
- Upload all 16 CSVs to Box folder
- Show list of all files in preview
- Download preview functionality
PHP Compatibility:
- Downgraded nesbot/carbon to ^2.0 (supports PHP 7.1+)
- Downgraded league/csv to 9.8.0 (supports PHP 7.4+)
- Now compatible with PHP 7.4-8.0 servers
Preview Enhancements:
- Shows all 16 filenames with ISO codes
- Preview table shows first file as sample
- Summary shows file count and total rows
Testing:
- Added sample CSV: Project_1601654_mediaBookings.csv
- OMG API lookup commented out (ready to enable later)
- Using "TESTING" as business unit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Downgraded dependencies to support PHP 7.4+:
- nesbot/carbon: ^2.0 (PHP 7.1+)
- league/csv: 9.8.0 (PHP 7.4+)
This ensures the application works on servers with PHP 7.4-8.0.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Services Created:
- OMGService.php: OMG API integration with detailed error handling
- CSVTransformer.php: CSV parsing and transformation logic
- EmailService.php: Mailgun email notifications
- process-csv.php: Multi-stage CSV processing with progress tracking
- upload-to-box.php: Box upload with approval workflow
Features:
- Comprehensive validation at each stage (upload, parse, campaign, API, transform)
- Detailed error reporting with actionable messages
- Warning system for non-critical issues
- Progress tracking through all stages
- Session-based CSV storage for preview before upload
- Date transformation (parse + add 1 month per blueprint)
- 16x market multiplication per ISO codes
- Business unit mapping per Make.com blueprint logic
Dependencies Added:
- league/csv for CSV parsing
- nesbot/carbon for date manipulation
Configuration:
- Added global_to_local settings (ISO codes, business unit map)
- Added omg_api settings (placeholder for API key)
- Added email settings (Mailgun placeholders)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added detailed sections:
- Workflow Overview and Purpose
- Box folder structure requirements with visual diagram
- Complete data extraction breakdown (Box API, User Input, System)
- Step-by-step workflow (7 detailed steps)
- Data flow diagram
- Example webhook payload with full structure
- What happens after submission
- Comprehensive error handling documentation
This provides complete understanding of how the application extracts and processes campaign asset metadata.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Structure: Campaign Number → CAMPAIGN_ASSETS → SUPPLIED_ASSETS
- Changed to fetch parent, then parent's parent (proper two levels up)
- Previous logic was using path_collection which showed CAMPAIGN_ASSETS
- Now correctly retrieves the campaign number folder
- Uses two separate API calls to traverse up the hierarchy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from grandparent (two levels up) to parent (one level up).
- Renamed getGrandparentFolder() to getParentFolder()
- Uses folder's direct parent instead of path_collection traversal
- Master Campaign Number should now show the campaign number folder
- Updated validate-box.php to use 'parent' instead of 'grandparent'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed align-items to stretch for proper vertical alignment
- Added flex: 1 to input for proper width distribution
- Added flex-shrink: 0 to button to prevent shrinking
- Increased min-width to 120px for 'Looking up...' text
- Fixed transform on disabled state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Check folder name immediately after fetching folder info
- Stop processing if folder name is not SUPPLIED_ASSETS (case-insensitive)
- Return clear error message with actual folder name
- Prevents unnecessary API calls for invalid folders
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Make.com webhooks use the URL itself as authentication, not custom headers.
Removed 'Loreal-Webhook' header - only sending Content-Type: application/json.
Added payload logging for debugging.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issue: When webhook returned 401, PHP was setting http_response_code(401)
which made the browser think the PHP endpoint was unauthorized.
Fix: Always return 200 to client, but indicate webhook failure in JSON response.
Added detailed logging of webhook failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Display user email in top right of header bar
- Update header layout with flexbox
- Show email in yellow (#FFC407) color
- Always visible regardless of SSO mode
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Enable display_errors for debugging
- Add SSO status logging
- Add detailed error information in response
- Log authentication user details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from 'X-API-Key' to 'Loreal-Webhook' header to match Make.com webhook expectations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Features:
- Added "Lookup" button to trigger Box ID validation manually
- No automatic validation on typing - user must click Lookup
- Recursive folder contents fetching (3 levels deep)
- Collapsible nested folder display with expand/collapse buttons
- Visual hierarchy with indentation and folder icons
- Shows all files within nested folders
- Updated UI with better folder/file organization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Set up PHP application with Composer and JWT library
- Implemented SSO authentication with local dev mode
- Created Box API service for folder validation
- Built two-column form interface (form + preview)
- Added real-time Box ID validation with AJAX
- Integrated webhook submission with status response
- Auto-populate Master Campaign Number from Box folder hierarchy
- Responsive design with Montserrat font and black/yellow theme
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>