creative-x-ferrero/MAPPINGS_GUIDE.md
DJP b20119b383 Add complete mapping system and automated Box.com monitoring service
Major Features:
- Complete Ferrero ↔ CreativeX mapping system with 93 brands
- Automated Box.com folder monitoring service
- Email notifications with score breakdowns
- Database integration for result storage

Mapping System (v2.0.0):
- mappings.json: 93 brand mappings, 44+ channel mappings
- core/mapping_resolver.py: Translates Ferrero codes to CreativeX format
- scripts/validate_mappings.py: Validation tool for brand/channel support
- scripts/generate_brand_mappings.py: Auto-mapping tool
- scripts/download_reports.py: Scorecard PDF download tool
- Updated scripts/upload.py: Integrated mapping validation
- Updated scripts/check_status.py: Added detailed score display with guidelines

Documentation:
- Updated README.md: Complete user guide with mapping system
- Updated STATUS.md: Production-ready status with test results
- MAPPINGS_GUIDE.md: Complete mapping documentation
- MAPPING_IMPLEMENTATION.md: Implementation summary
- BRAND_MAPPINGS_REVIEW.md: Brand mapping validation guide
- PRODUCTION_BRANDS_SUMMARY.md: Production brand catalog
- PRODUCTION_MAPPING_COMPLETE.md: Mapping completion summary

Automation Service (New):
- creativex-automation/: Complete automated Box monitoring service
- Monitors Box Ferrero-In folder (363284027140) for new files
- Automatically uploads to CreativeX
- Polls for completion (30 min intervals)
- Extracts scores and stores in PostgreSQL creativex_scores table
- Sends formatted emails to file uploader + daveporter@oliver.agency
- Moves processed files to Processed subfolder

Service Components:
- automation/box_monitor.py: Box folder monitoring with uploader detection
- automation/upload_processor.py: CreativeX upload integration
- automation/status_poller.py: CreativeX status polling
- automation/result_handler.py: Score extraction and email sending
- automation/orchestrator.py: Service coordination
- automation/processing_queue.py: JSON-based processing queue
- service.py: Main service entry point
- config.py: Service configuration loader
- requirements.txt: All dependencies
- deployment/systemd/: Systemd service unit file
- Updated shared/notifier.py: Added creativex_upload_complete and creativex_upload_failed templates

Testing:
- Supports --dry-run mode for configuration testing
- Supports --scan-once mode for Box folder testing
- Manual run mode for development/testing
- Comprehensive logging with rotation (10MB, 28 backups)

Database Integration:
- Uses existing creativex_scores table (no migrations needed)
- Compatible with existing Ferrero-Opentext workflows
- Stores full CreativeX API responses in JSONB

Email Templates:
- Matches Ferrero-Opentext styling (#9c27b0 purple for CreativeX)
- Includes score, tier, guidelines breakdown, scorecard URL
- Recipients: Box uploader + CC to daveporter@oliver.agency

Deployment:
- Runs locally for dev/testing
- Systemd service for production
- Auto-restart on failure
- Complete documentation in creativex-automation/README.md

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-01-29 09:51:16 -05:00

421 lines
No EOL
10 KiB
Markdown

# Creative X Mappings Guide
## Overview
The Ferrero naming convention and Creative X API use different codes and naming for brands, channels, and markets. This mapping system bridges the two systems to enable seamless uploads.
## Architecture
```
Ferrero Filename
[Filename Parser] → Extracts Ferrero codes
[Mapping Resolver] → Translates to Creative X format
[API Client] → Uploads with Creative X metadata
```
## Files
- **`mappings.json`** - Complete mapping tables (brands, channels, countries)
- **`core/mapping_resolver.py`** - Python module for resolving mappings
- **`scripts/upload.py`** - Upload script (uses mapping resolver)
---
## Mapping Tables
### 1. Brand Mappings
Maps Ferrero brand codes to Creative X brand names and IDs.
**Example:**
```json
{
"NUT": {
"creativex_name": "Nutella",
"creativex_id": 423,
"ferrero_name": "NUTELLA"
},
"RAF": {
"creativex_name": "Rafalleo",
"creativex_id": 422,
"ferrero_name": "RAFFAELLO"
}
}
```
**Current Status:**
- ✅ Nutella (NUT)
- ✅ Raffaello (RAF) - Note: Creative X spells it "Rafalleo"
- ❌ 103 other Ferrero brands not yet added to Creative X
### 2. Channel Mappings
Maps Ferrero social media codes to Creative X channel + publisher + placement combinations.
**Structure:**
```json
{
"FERRERO_CODE": {
"ferrero_name": "Human-readable name",
"creativex_channel": "channel_name",
"creativex_publisher": "publisher_name (optional)",
"creativex_placement": "placement_name (optional)",
"creativex_ad_format": "ad_format (optional for YouTube/DV360)"
}
}
```
**Examples:**
#### Facebook (requires channel + publisher + placement)
```
FBS → facebook_paid / facebook / facebook_stories
IGF → instagram_paid / instagram / feed
```
#### YouTube (requires channel + publisher + ad_format)
```
YTB → google_ads / youtube / Bumper
YTS → google_ads / youtube / Shorts
```
#### Simple channels (only need channel name)
```
TIK → tiktok_paid
PIN → pinterest
```
**Supported Channels:**
| Ferrero Code | Creative X Channel | Notes |
|--------------|-------------------|-------|
| FBS, FBF, etc. | facebook_paid | 15 Facebook placements |
| IGF, IGR, IST, etc. | instagram_paid | 11 Instagram placements |
| MSI, MSS | facebook_paid | 2 Messenger placements |
| ANC, ANI, ANR | facebook_paid | 3 Audience Network placements |
| YTB, YTI, YTS, etc. | google_ads | 5 YouTube ad formats |
| DV3 | dv360 | Display & YouTube |
| TIK | tiktok_paid | TikTok |
| SNA | snapchat_paid | Snapchat |
| PIN | pinterest | Pinterest |
| TWI | twitter_paid | Twitter/X |
| AMZ | amazon_paid | Amazon |
| GOO | google_ads | Generic Google |
### 3. Country Mappings
Most country codes use standard ISO 3166-1 alpha-2 codes and map directly.
**Special Cases:**
- **GL** = "Global" (not Greenland) - Creative X expects `market_name: "Global"` with no ISO code
- **CZ** = Czechia (Ferrero may use "Czech Republic")
- **US** = "United States of America" (not just "United States")
- **GB** = "United Kingdom"
- **KR** = "South Korea"
All other countries use standard ISO codes (DE, IT, FR, ES, etc.)
---
## How It Works
### 1. Parsing Phase
```python
from core.filename_parser import FerreroFilenameParser
parser = FerreroFilenameParser(data_loader)
parsed = parser.parse("NUT_GL_en_MOMENT_OLV_6S_1x1_FBS_xyz.mp4")
# Result:
{
'brand_code': 'NUT',
'brand_name': 'NUTELLA',
'country_code': 'GL',
'country_name': 'GLOBAL',
'language_code': 'en',
'social_media': 'FBS',
'channel': 'FB - Stories',
...
}
```
### 2. Mapping Phase
```python
from core.mapping_resolver import MappingResolver
resolver = MappingResolver('mappings.json')
creativex_payload = resolver.build_creativex_payload(parsed)
# Result:
{
'brand_name': 'Nutella',
'channel': 'facebook_paid',
'publisher': 'facebook',
'placement': 'facebook_stories',
'market_name': 'Global',
'language': 'en',
'dimensions': '1x1',
'duration': '6',
...
}
```
### 3. Upload Phase
```python
api_client.create_preflight({
'name': 'NUT_GL_en_MOMENT_OLV_6S_1x1_FBS_xyz.mp4',
'brand_name': 'Nutella',
'market_name': 'Global',
'channel': 'facebook_paid',
'publisher': 'facebook',
'placement': 'facebook_stories',
'language': 'en',
'dimensions': '1x1',
'duration': '6',
'creatives': [
{'source_url': 'https://s3.../file.mp4'}
]
})
```
---
## Validation
The system validates at multiple levels:
### 1. Brand Validation
```python
resolver.is_brand_supported('NUT') # True
resolver.is_brand_supported('ROC') # False - not in Creative X yet
```
### 2. Channel Validation
```python
resolver.is_channel_supported('FBS') # True
resolver.is_channel_supported('XXX') # False - not mapped
```
### 3. Full Metadata Validation
```python
is_valid, errors = resolver.validate_metadata_for_upload(parsed_data)
if not is_valid:
print("Errors:", errors)
```
---
## Adding New Mappings
### Add a New Brand
Edit `mappings.json`:
```json
{
"brand_mappings": {
"ROC": {
"creativex_name": "Ferrero Rocher",
"creativex_id": 424,
"ferrero_name": "ROCHER"
}
}
}
```
**Steps:**
1. Get Creative X brand ID from `/dimensions` endpoint
2. Add mapping to `mappings.json`
3. Test upload: `python scripts/upload.py --dry-run test_file.mp4`
### Add a New Channel
Edit `mappings.json`:
```json
{
"channel_mappings": {
"NEW_PLATFORM_CODES": {
"NPF": {
"ferrero_name": "New Platform - Feed",
"creativex_channel": "new_platform_paid",
"creativex_publisher": "new_platform",
"creativex_placement": "feed"
}
}
}
}
```
**Steps:**
1. Query `/dimensions` to see Creative X channel structure
2. Determine if channel needs publisher/placement/ad_format
3. Add mapping following existing patterns
4. Test validation
---
## Common Issues & Solutions
### Issue: "Brand 'XXX' is not supported in Creative X"
**Cause:** Brand not yet added to Creative X system
**Solutions:**
1. Check if brand exists: `python get_dimensions.py | grep -i brandname`
2. If exists, add mapping to `mappings.json`
3. If doesn't exist, contact Creative X to add brand
### Issue: "Social media code 'XXX' not mapped"
**Cause:** Ferrero social code not in `mappings.json`
**Solutions:**
1. Check Creative X channels: `python get_dimensions.py`
2. Identify correct channel/publisher/placement
3. Add mapping to `mappings.json`
### Issue: "Invalid placement for channel"
**Cause:** Mismatch between channel and placement
**Solutions:**
1. Verify placement exists: `python get_dimensions.py`
2. Check channel structure (some channels need publisher+placement, others don't)
3. Update mapping with correct structure
### Issue: "Market not found"
**Cause:** Country code mapping issue (usually GL = Global)
**Solutions:**
1. Check if country exists: `python get_dimensions.py | grep -i country`
2. For "Global" uploads, ensure GL maps to market_name="Global" (no ISO code)
3. Update `country_mappings.SPECIAL_CASES` if needed
---
## Testing Mappings
### 1. Dry Run Test
Test mapping without uploading:
```bash
python scripts/upload.py --dry-run /path/to/test_file.mp4
```
**Expected output:**
```
✓ File valid
✓ Brand: NUTELLA
✓ Market: GLOBAL
✓ Channel: FB - Stories
✓ Metadata valid
✓ Mappings valid
→ Brand: Nutella
→ Channel: facebook_paid
→ Publisher: facebook
→ Placement: facebook_stories
✓ DRY RUN: Would upload file
```
### 2. Query Available Dimensions
Check what's available in Creative X:
```bash
source venv/bin/activate
python get_dimensions.py > dimensions_output.txt
```
Review:
- Available brands
- Available channels (with publishers/placements)
- Available markets
### 3. Interactive Python Test
```python
from core.mapping_resolver import MappingResolver
resolver = MappingResolver('mappings.json')
# Test brand
brand = resolver.get_creativex_brand('NUT')
print(f"Brand: {brand}")
# Test channel
channel = resolver.get_creativex_channel_mapping('FBS')
print(f"Channel: {channel}")
# Test market
market = resolver.get_creativex_market('GL')
print(f"Market: {market}")
# List all supported
print(f"Supported brands: {resolver.get_all_supported_brands()}")
print(f"Supported channels: {resolver.get_all_supported_channels()}")
```
---
## Quick Reference
### Filename Format
```
BRAND_COUNTRY_LANG_SUBJECT_ASSETTYPE_DURATION_ASPECTRATIO_SOCIAL_hash.ext
NUT_GL_en_MOMENT_OLV_6S_1x1_FBS_xyz.mp4
│ │ │ │ │ │ │ │ └── Hash/random
│ │ │ │ │ │ │ └────── Social media code (FBS)
│ │ │ │ │ │ └────────── Aspect ratio (1x1)
│ │ │ │ │ └───────────── Duration (6S)
│ │ │ │ └───────────────── Asset type (OLV)
│ │ │ └──────────────────────── Subject (MOMENT)
│ │ └─────────────────────────── Language (en)
│ └────────────────────────────── Country (GL)
└────────────────────────────────── Brand (NUT)
```
### Upload Workflow
```
1. Parse filename → Extract Ferrero codes
2. Validate file → Check format/size
3. Validate Ferrero metadata → Check against data.json
4. Validate mappings → Check brand/channel exist in Creative X
5. Get presigned URL → From Creative X API
6. Upload to S3 → Direct to S3
7. Create preflight → With mapped metadata
```
---
## Support
**Issues:**
- Brand not mapped → Add to `brand_mappings` in `mappings.json`
- Channel not mapped → Add to `channel_mappings` in `mappings.json`
- Country not found → Check `country_mappings.SPECIAL_CASES`
**Testing:**
```bash
# Test with dry run
python scripts/upload.py --dry-run file.mp4
# Check dimensions
python get_dimensions.py
# Check logs
cat data/logs/creativex_upload_*.log
```
**Documentation:**
- Main README: `README.md`
- Project status: `STATUS.md`
- This guide: `MAPPINGS_GUIDE.md`