- Update UploadProofModal with new design system colors
- Update LoadingCell progress bar to active-blue
- Update DeleteConfirmationModal with pill buttons and rounded corners
- Update CampaignDeleteConfirmationModal styling
- Apply consistent border radius (10px) to all modals
- Update drag & drop zone colors to use success theme
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update Tailwind config with new color tokens (primary-blue, active-blue,
electric-violet, lime, grey-100/300/700/900, success, warning, error)
- Add Inter font from Google Fonts as Barclays Effra alternative
- Update Sidebar with primary-blue background and white active state
- Update Hero with electric-violet accent and pill-shaped buttons
- Update all tables with lime (#C3FB5A) header backgrounds
- Implement alternating row colors (white/grey-100) on tables
- Update status badges: In Progress (amber), Completed (green)
- Update tabs with active-blue underline styling
- Apply 10px border radius to cards and containers
- Update button styling to pill-shaped with active-blue
- Update input/dropdown borders to grey-700 with 2px
- Update selected state highlighting to info-light (#E7F0FB)
- Update FeedbackReport RAG status colors to new design system
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When analyzing proof revisions (version > 1), SubReviewCard now displays
issues in three distinct categories: Resolved Issues (green, collapsed by
default), Outstanding Issues (amber), and New Issues (red). Each section
is collapsible with count badges. Original mode (version 1) maintains
backward compatibility with the single "Actionable Issues" list.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add file_hash and is_identical_file columns to proof_versions table
- Compute MD5 hash on file upload and compare with previous version
- Display warning banner when uploading identical file as revision
- Return is_identical_file in WebSocket response and API endpoints
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a subsequent revision of a proof is uploaded, the analysis now takes
place in context of the previous version's results. The system identifies:
- Resolved issues: fixed in the new revision
- Outstanding issues: still present from previous version
- New issues: introduced in the new revision
Key changes:
- Add resolvedIssues, outstandingIssues, newIssues fields to SubReview
- Add PreviousReviewContext model for passing previous review data
- Update all specialist agents to accept previous_review context
- Extend GeminiService with include_revision_fields parameter
- Add get_latest_version_review() repository method
- Update LeadAgent to synthesize cross-version context in summary
- Fetch previous analysis in WebSocket handler for revisions
First version analysis continues to work exactly as before with revision
fields set to null.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Run all 4 specialist agents (Legal, Brand, Channel Best Practices,
Channel Tech Specs) concurrently instead of sequentially. This reduces
total analysis time to roughly the duration of the slowest agent rather
than the sum of all agent times.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed the AI model used for proof analysis from gemini-2.5-flash
to gemini-3-pro-preview for improved analysis capabilities.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move /files/{storage_key}/pages endpoint before the base /files/{storage_key}
endpoint so FastAPI matches the more specific route first.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Backend: Generate PDF thumbnail from first rasterized page on upload
- Backend: Add /files/{storage_key}/pages endpoint for PDF rasterization
- Frontend: Add getPdfPages() method to apiService
- Frontend: Create usePdfPages hook for on-demand PDF page loading
- Frontend: Pass pdfPages prop to ProofPreview in Campaigns view
This fixes the issue where PDF uploads showed no visual preview in results.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add formatFeedbackText() utility that converts raw HTML tags and
concatenated bullet points from Gemini API into properly formatted
React elements with proper line breaks and list styling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add persistent Docker volume for file storage to fix 404 download errors
- Set FILE_STORAGE_PATH env var in Dockerfile and docker-compose.yml
- Increase thumbnail generation limit from 500KB to 10MB for images
- Remove encodeURIComponent from file download URL to prevent path encoding
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CampaignDeleteConfirmationModal for campaign deletion confirmation
- Add checkbox selection column to CampaignList with select all/indeterminate state
- Add actions column with trash icon for single campaign deletion
- Add bulk actions bar showing selected count with Clear/Delete buttons
- Add handleDeleteCampaign handler in App.tsx using apiService.deleteCampaign
- Pass onDeleteCampaign prop through Campaigns component chain
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace removed toneAgentReview and channelAgentReview with the new
channelBestPracticesAgentReview and channelTechSpecsAgentReview in
the WebSocket handler. Update /info endpoint agent list to match.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces placeholder with detailed technical specifications including:
- Platform-specific dimensions and safe zones (Meta, TikTok, Pinterest, YouTube/PMAX, Snapchat)
- Exact pixel measurements for safe zones extracted from source templates
- Brand element placement rules for Barclays and Barclaycard
- File format, typography, and accessibility requirements
- Comprehensive violations checklist for analysis
Based on Barclays and Barclaycard Social Templates (August 2025).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the 60-line placeholder with a detailed 613-line spec covering:
- 6 core creative principles and trust paradox for financial services
- Platform-specific guidelines: LinkedIn, Reddit, Instagram, Facebook, Twitter/X, YouTube
- Performance metrics and benchmarks from industry research
- Short-form video guidelines based on System1 research
- Mobile-first design requirements with touch targets and safe zones
- Copy and headline guidelines with character limits by platform
- Comprehensive violations checklist for assessment
- Measurement benchmarks and KPIs by platform
Sources: LinkedIn Creative Handbook, Reddit Mega Deck, Global Creative
Inspiration Report, LinkedIn B2C Guide, System1 research, Barclays campaigns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove Tone Agent (tone is now part of Brand specs)
- Split Channel Agent into Channel Best Practices Agent and Channel Tech Specs Agent
- Convert Legal Agent from stub to full Gemini-powered implementation
- Add new prompt files for channel_best_practices.md, channel_tech_specs.md, legal.md
- Update ReferenceDocsService with new methods for loading specs
- Update schemas and analysis service to use new agent structure
- Update all frontend components to use new agent names and properties
- Update mock data in Projects.tsx and Campaigns.tsx
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates prompts/brand_barclays.md with complete brand guidelines including:
- Sacred assets (Eagle, Portal, Cyan)
- Logo/Eagle specifications with sizing rules
- Portal sizing and treatment guidelines
- Full masterbrand color palette (24 colors with hex codes)
- Typography rules (Barclays Effra, 5 weights)
- Digital, social media, email, and advertising guidelines
- Accessibility requirements (WCAG AA/AAA)
- Common violations checklist for brand assessment
This spec is sent to Gemini when users select "Barclays" brand for
proof analysis, providing condensed guidelines for accurate assessment.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add brand field to AnalyzeProofOptions interface and WebSocket message
- Pass campaign's brandGuidelines to analyzeProof in App.tsx (upload & retry)
- Extract brand from WebSocket message in handlers.py and pass to analysis
- Update AnalysisService.analyze_proof to accept brand parameter
- Refactor BrandAgent to dynamically select brand spec based on brand param
- Add get_barclays_brand_spec() method to ReferenceDocsService (placeholder)
The brand agent now uses the appropriate specification (Barclaycard spec or
Barclays spec when available) based on the campaign's brandGuidelines setting.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create prompts/brand_barclaycard.md with structured brand guidelines
covering logo, Card Portal, colors, typography, and accessibility
- Update ReferenceDocsService with get_barclaycard_brand_spec() method
- Update BrandAgent to use the new spec instead of raw reference docs
- Spec is ~15KB vs ~293KB of raw docs for more efficient analysis
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add lineHeight: 1 to RagStatusBadge component styling to ensure text
is tightly contained within its bounding box, allowing flexbox centering
to work correctly in PDF rendering engines.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit formatting instructions to agent prompts requesting bullet-point
output instead of verbose paragraphs. Update JSON schema descriptions for
feedback and summary fields to enforce concise, outline-style format.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add workflow instruction to commit and push after code changes
- Add backend development commands (Python venv, uvicorn)
- Add database commands (Alembic migrations)
- Expand environment setup for both frontend and backend
- Document backend architecture (agents, services, repositories, models)
- Add PostgreSQL and Alembic to tech stack
- Update data persistence section for backend storage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PDFs are now converted to PNG images at 200 DPI before being sent to
Gemini for analysis. This fixes the unreliable iframe-based PDF preview
and ensures all pages are properly analyzed.
- Add PyMuPDF dependency for PDF rasterization
- Create pdf_service.py with rasterize() and get_page_count()
- Update agent interfaces to accept list of images for multi-page support
- Add analyze_with_images() to Gemini service for multi-image analysis
- Return rasterized PDF pages via WebSocket for frontend display
- Add page navigation UI for multi-page PDFs in preview components
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Exclude errors from pass rate denominator since they weren't successfully reviewed
- Add missing Analysis Errors stat card to display error count
- Update grid layout to accommodate 5 stat cards
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add URL utility functions for parsing and building URL state
- Initialize app state from URL parameters on page load
- Sync navigation changes to URL via browser history API
- Handle browser back/forward navigation with popstate listener
- Support deep linking to campaigns and proofs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend:
- Add email_service.py with Mailgun API integration
- Add SupportEmailRequest schema for email endpoint
- Add Mailgun config settings (API URL, key, from address, support email)
- Update .env.example with Mailgun configuration variables
Frontend:
- Update Login.tsx SupportModal to send emails via /api/support/email
- Update Profile.tsx question form to send emails via apiService
- Add loading states, success/error feedback, and auto-close on success
The support forms on both the login page and profile page now actually
send emails to the support team instead of just showing alerts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GET /files/{storage_key:path} endpoint to serve stored files
- Add getFile() method to apiService to fetch files from backend
- Update convertProofToFrontend() to preserve fileStorageKey
- Update handleRetryAnalysis() to fetch file from backend when not in memory
- Update handleDownload() to download original file instead of thumbnail
After page refresh, the retry button now fetches the original file from
backend storage using the fileStorageKey, allowing failed proofs to be
reprocessed. The Download Asset button also now downloads the original
uploaded file rather than the preview thumbnail.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The staging database has duplicate sub-channels (5 "Meta", 2 "Magazine")
which causes the last duplicate (with 0 proof types) to overwrite the
correct one in the API response.
This migration:
1. Identifies duplicate sub-channels and channels
2. Keeps the one with the most children (proof types)
3. Deletes the duplicates
4. Adds unique partial indexes to prevent future duplicates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend logging:
- Log channel, sub-channel, and proof type counts in get_all_hierarchical()
- Log Meta proof types specifically
- Log API response for Social.Meta
Frontend logging:
- Log raw API response in apiService
- Log dropdown options in App.tsx when loaded
- Log available proof types in UploadProofModal when channel/subchannel selected
This will help diagnose why Meta proof types are not appearing on staging.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace nested selectinload chain with separate explicit queries for
channels, sub-channels, and proof types. The self-referential
selectinload chain didn't reliably load the third level (proof types)
in async SQLAlchemy.
Also add order_by to DropdownOption.children relationship for
consistent ordering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous refresh() call only reloaded relationships, not scalar
attributes like updated_at. Re-fetching via get_by_id ensures all
attributes and relationships are properly loaded.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures new code changes are picked up by using --force-recreate
flag when starting the backend container.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refresh campaign object after flush to reload expired attributes
and relationships, preventing lazy load failures in async context.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaced custom AI-generated icons with standard Heroicons for a more
professional appearance on the home page.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Workfront Campaign ID field is now optional when creating campaigns.
When provided, it is used as the base for proof workfront IDs instead of
generating random ones.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use optimistic update pattern to immediately reflect status changes
in the UI, with rollback on API error.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename Download button to Download Asset and add new Download Report
button that generates a PDF report for the current proof version directly
from the proof review screen.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make Hero height responsive (350px mobile, 400px tablet, 500px desktop)
- Remove overflow-hidden and flex-1 from ChecksOverview to allow
content to flow naturally and enable scrolling
- Add responsive padding to ChecksOverview for better mobile spacing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add agencyLead state and form field to CreateCampaignModal
- Remove disabled attribute and hardcoded value from Agency Lead input
- Pass agency_lead to backend API when creating campaigns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add HealthCheckFilter to suppress /health endpoint logs at INFO level,
reducing noise from Docker healthcheck requests every 30 seconds.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, deleting a proof or campaign only removed database records,
leaving orphaned files in the storage directory. Now the delete endpoints
extract file_storage_key from proof versions and delete files via
storage_service before removing database records.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>