Commit graph

45 commits

Author SHA1 Message Date
michael
caf4539e1d Fix analytics pass rate calculation and add Analysis Errors stat
- 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>
2026-01-24 09:19:44 -06:00
michael
a4d67fdf46 Format campaign last modified date for better readability
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 09:09:10 -06:00
michael
f1776df710 Persist navigation state in URL for browser refresh support
- 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>
2026-01-24 09:04:04 -06:00
michael
e2fd9549f7 Add support email functionality via Mailgun
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>
2026-01-24 07:03:11 -06:00
michael
b119951f93 Fix retry button for failed proofs and hook up download asset button
- 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>
2026-01-24 07:01:58 -06:00
michael
94a37f3ed8 Add migration to cleanup duplicate dropdown options
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>
2026-01-23 13:22:44 -06:00
michael
874c1fceee Add debugging for proof types not showing in dropdown
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>
2026-01-23 13:09:25 -06:00
michael
3b868f7415 Fix proof types not loading for sub-channels in dropdown hierarchy
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>
2026-01-23 13:01:39 -06:00
michael
d2d01aaea7 Fix campaign update by re-fetching after flush
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>
2026-01-08 10:27:26 -06:00
michael
f4fd850a49 Force recreate backend container on deploy
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>
2026-01-08 10:24:43 -06:00
michael
37c2532263 Fix async SQLAlchemy MissingGreenlet error on campaign update
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>
2026-01-08 10:20:56 -06:00
michael
96d459c322 Center text in PDF report status badges
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 10:13:20 -06:00
michael
091f9ecd87 Add proof types for Meta sub-channel
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 10:07:28 -06:00
michael
74930d623f Replace agent icons with clean Heroicons
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>
2026-01-08 10:02:28 -06:00
michael
8038e4014e Make Workfront Campaign ID optional and propagate to proofs
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>
2026-01-08 09:49:23 -06:00
michael
abfcb6aae2 Fix campaign status change not persisting in UI
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>
2026-01-08 09:31:59 -06:00
michael
5d5bfd571b Update browser tab title to Barclays Mod Comms
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:24:27 -06:00
michael
5fc36e358f Add Download Report button to proof detail view
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>
2026-01-08 09:15:18 -06:00
michael
e59960b23b Fix home page responsiveness on small screens
- 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>
2025-12-19 10:07:46 -06:00
michael
9c25677563 Make Agency Lead field editable in campaign creation
- 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>
2025-12-19 10:00:23 -06:00
michael
7e24c9bd50 Filter health check logs from uvicorn access log
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>
2025-12-19 06:37:56 -06:00
michael
8eb0821c9f Delete associated files when proof or campaign is deleted
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>
2025-12-19 06:25:02 -06:00
michael
c3396be029 Fix download button in proof detail view
The download button was only logging to console instead of
downloading the proof file. Added handleDownload function that
supports both data URLs and remote URLs with proper CORS handling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 06:16:07 -06:00
michael
6bdb02d78b Seed database with agencies, brand guidelines, and dropdown options
Backend:
- Update migration to seed agencies (OLIVER Agency, Barclays, etc.)
- Seed brand guidelines (Barclays, Barclaycard) in dropdown_options
- Seed channel/sub-channel/proof-type hierarchy
- Add /api/agencies endpoint to list all agencies
- Update DropdownOptionsResponse to include brand_guidelines
- Update dropdown repository to return brand guidelines

Frontend:
- Update DropdownOptions interface to include brandGuidelines
- CreateCampaignModal now receives brand guidelines from API
- Settings UsersTab fetches agencies from API instead of hardcoded list
- Add getAgencies() method to apiService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 17:16:23 -06:00
michael
d080a20ee1 Add migration to seed default dropdown options
Populates the dropdown_options table with default channels,
sub-channels, and proof types that were previously hardcoded:
- Social (Meta, X, LinkedIn, TikTok, YouTube)
- Display (Programmatic, Direct Buy, Rich Media)
- Email (Marketing, Transactional)
- Print (Magazine, Newspaper, Direct Mail)
- OOH (Billboard, Transit, Street Furniture)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 17:09:05 -06:00
michael
0e6f5be46d Support both v1.0 and v2.0 Azure AD token issuer formats
Azure AD issues tokens with different issuer formats depending on the
app registration's accessTokenAcceptedVersion setting:
- v1.0: https://sts.windows.net/{tenant}/
- v2.0: https://login.microsoftonline.com/{tenant}/v2.0

Update backend to accept both formats by trying each issuer in sequence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 17:03:47 -06:00
michael
dd5ee09d07 Fix JWT signature verification by requesting correct token audience
- Change frontend apiTokenRequest scopes from OpenID-only to CLIENT_ID/.default
  This makes Azure AD issue tokens with audience = app client ID instead of Graph API
- Add diagnostic logging in backend to show token claims before verification
- Fixes 401 Unauthorized errors on all API calls after login

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 16:59:54 -06:00
michael
c07c66a583 Connect frontend to PostgreSQL database via API
- Replace all localStorage-based state management with API calls
- Load campaigns, proofs, and audit items from database
- Persist proof analysis results to database via WebSocket
- Add dropdown options CRUD API endpoints (channels, sub-channels, proof types)
- Create DropdownRepository for managing dropdown options
- Update Analytics component to fetch data from API
- Remove demo data and localStorage persistence code

Frontend changes:
- App.tsx: Initialize apiService with MSAL, use API for all CRUD operations
- apiService.ts: Add dropdown options API methods
- Analytics.tsx: Fetch stats from /api/analytics

Backend changes:
- New dropdown_repository.py for dropdown CRUD
- routes.py: Add 7 dropdown endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:50:37 -06:00
michael
6ff69cc308 Display actual user name in sidebar from MSAL
- Add userName and userEmail props to Sidebar component
- Pass user info from MSAL to Sidebar in App.tsx
- Replace hardcoded "Steve O'Donoghue" with actual logged-in user

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:23:28 -06:00
michael
04527d65db Add MSAL debug logging to frontend and backend
- Frontend: Set MSAL log level to Info, add [MSAL] prefix
- Frontend: Add [MSAL Auth] logs for token acquisition
- Frontend: Add [MSAL Login] logs for login popup flow
- Backend: Add [MSAL Backend] logs for token verification
- Backend: Add [MSAL Backend] logs for auth dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:11:30 -06:00
Michael Clervi
dc17cd087c permissions changes 2025-12-18 16:51:27 +00:00
michael
5b9e824da9 Use OpenID scopes instead of custom API scopes
- Change frontend scopes from api://{client_id}/.default to
  openid, profile, email for simpler authentication
- Update backend token validation to expect ID token format:
  - Audience: client_id (not api://{client_id})
  - Issuer: v2.0 endpoint

This avoids requiring Application ID URI setup in Azure AD.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:50:02 -06:00
michael
cc2c68bb02 Auto-discard package-lock.json changes before git pull
The package-lock.json changes when npm install runs on different
platforms/npm versions. Since deploy.sh runs npm install anyway,
discard local changes to this file before pulling to avoid conflicts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:42:54 -06:00
michael
e06dd414c9 Don't overwrite frontend/.env.local in deploy script
- Remove auto-generation of frontend/.env.local
- Instead, check that it exists and fail with helpful message if not
- Update .env.deploy.example to document manual .env.local setup

This allows manual management of frontend credentials without
the deploy script overwriting them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:41:14 -06:00
michael
fed9bb26bf Add Azure AD MSAL variables to deploy script
- Include VITE_AZURE_CLIENT_ID, VITE_AZURE_TENANT_ID, and
  VITE_AZURE_REDIRECT_URI in frontend .env.local generation
- Document these variables in .env.deploy.example

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:39:15 -06:00
michael
3f1e1b5227 Fix React version mismatch with MSAL packages
Downgrade React from 19.x to 18.3.1 for compatibility with
@azure/msal-react v3.x which requires React 18.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:31:01 -06:00
michael
0742cc0aa4 Fix DISABLE_AUTH check in get_current_user dependency
The auth dependency was requiring the Authorization header before
checking DISABLE_AUTH, causing API endpoints to fail in dev mode.
Now returns mock user immediately when DISABLE_AUTH=true.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:15:37 -06:00
michael
99af0164e6 Add PostgreSQL database support with Alembic migrations
Backend:
- Add PostgreSQL service to docker-compose with health checks
- Add SQLAlchemy async models for all entities (Agency, User, Campaign,
  Proof, ProofVersion, FlaggedItem, ResolvedItem, ErrorItem)
- Add Alembic migration framework with initial schema migration
- Add repository layer for CRUD operations
- Add REST API endpoints for campaigns, proofs, and audit items
- Add file storage service for proof uploads
- Update WebSocket handler to optionally persist analysis results

Frontend:
- Add apiService.ts for REST API communication
- Update geminiService.ts to support database persistence options

Deployment:
- Update deploy.sh to handle database migrations (6-step process)
- Update Dockerfile to include alembic configuration
- Add PostgreSQL environment variables to .env templates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 12:27:18 -06:00
michael
321a9ca820 Implement Microsoft MSAL SSO with PKCE flow
Frontend:
- Add @azure/msal-browser and @azure/msal-react packages
- Create authConfig.ts with MSAL configuration for PKCE flow
- Create authService.ts for token acquisition and user info
- Wrap App with MsalProvider in index.tsx
- Replace dummy login with real MSAL loginPopup() in Login.tsx
- Update App.tsx to use useIsAuthenticated/useMsal hooks
- Update Profile.tsx to display real user data from claims
- Update geminiService.ts to include access_token in WebSocket messages
- Update WIPReviewer.tsx to pass msalInstance for auth

Backend:
- Add python-jose and httpx dependencies for JWT verification
- Create auth_service.py with Azure AD JWKS fetching and token verification
- Create auth.py FastAPI dependency for protected REST endpoints
- Update main.py to verify tokens on WebSocket and protect /info endpoint
- Add AZURE_TENANT_ID, AZURE_CLIENT_ID, DISABLE_AUTH to config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 08:43:30 -06:00
michael
3df1b9fb92 Auto-generate .env for docker compose commands
The deploy script now creates a .env file with COMPOSE_PROJECT_NAME
and BACKEND_PORT so that manual docker compose commands (ps, logs, etc.)
work without needing to set environment variables.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 06:37:41 -06:00
michael
27113a625a Support multiple instances (prod/dev) on same server
- Add COMPOSE_PROJECT_NAME for unique container names
- Add BACKEND_PORT for configurable port mapping
- Update deploy.sh to export variables for docker compose
- Update health checks to use configured port

Allows running prod and dev instances simultaneously by cloning
the repo twice with different .env.deploy configurations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 15:10:20 -06:00
michael
834de7d74c Add deployment script for Ubuntu server
- Add deploy.sh for automated deployment (idempotent)
- Add .env.deploy.example template for server configuration
- Update .gitignore to exclude .env.deploy

The script handles both first-time install and updates:
- Pulls latest code from git
- Builds frontend with production URLs
- Deploys to Apache document root
- Rebuilds and restarts Docker backend
- Includes health check verification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 14:50:49 -06:00
michael
1e2082b642 Add Docker support for backend
- Add Dockerfile for Python 3.12-slim based backend image
- Add docker-compose.yml for service orchestration
- Add .dockerignore to optimize build context
- Include health check and reference docs in container

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 14:34:18 -06:00
michael
808326ea36 Add README and update .gitignore
- Add comprehensive README with project overview, architecture,
  setup instructions, and API documentation
- Expand .gitignore with Python testing/linting, Vite cache,
  coverage reports, and additional IDE/OS entries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 14:14:11 -06:00
michael
e97d0e935c initial commit 2025-12-12 09:03:17 -06:00