Commit graph

19 commits

Author SHA1 Message Date
Vadym Samoilenko
447c4b2a95 Add CSV export of campaign data for super_admin and oversight_admin
Adds a server-side CSV export covering all campaign, proof, and version
data including agent RAG statuses. The export respects the active agency
filter so oversight admins can scope the download to a single agency.

- backend: `CampaignRepository.get_export_rows()` — flat join across
  Campaign → Proof → ProofVersion with Agency and User, extracts agent
  RAG statuses from the `agent_review` JSONB column
- backend: `GET /api/export/campaigns-csv` endpoint gated to
  super_admin / oversight_admin, streams a dated CSV file
- frontend: `apiService.downloadCampaignsCsv(agencyId?)` — fetches blob
  and triggers browser download
- frontend: threads `selectedAgencyId` prop from App → Campaigns →
  CampaignList so the export uses the active filter
- frontend: Export CSV button in CampaignList header, visible only to
  super_admin / oversight_admin, with spinner while downloading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 11:35:24 +00:00
Vadym Samoilenko
0432635153 Grant oversight_admin write access to campaigns and proofs
Oversight admins can now create campaigns, upload proofs, and
flag/resolve issues when they have an agency assigned. They retain
all existing cross-agency read access for analytics, auditing, and
user management. Oversight admins without an agency see a read-only
campaigns view.

Changes:
- Add oversight_admin to canWrite permission in UserContext
- Guard readOnly for oversight_admin without agency in App.tsx
- Remove oversight_admin block from require_write_access dependency
- Remove WebSocket oversight_admin upload block in main.py
- Require agency for oversight_admin campaign creation in routes.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:08:54 +00:00
michael
a25c7a9d31 Grant oversight_admin read-only access to User Management
Allow oversight_admin users to view the User Management screen with
read-only access. They can see users, roles, agencies, and change
history but cannot edit roles, assign agencies, or create agencies.

Backend: open GET /users and GET /users/{id}/change-history to
oversight_admin (PUT /users stays super_admin only).
Frontend: add oversight_admin to sidebar nav and context permission,
render static text instead of dropdowns and hide the add-agency form
for non-super-admin users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 13:35:07 -06:00
michael
e3575052ee Add per-agency analytics breakdown table for admin users
New GET /analytics/by-agency endpoint groups review metrics by agency.
The Analytics page now shows a sortable agency performance table with
pass rates, failures, errors, and legal review counts for each agency.
Only visible to super_admin and oversight_admin users. Selected agency
row is highlighted when the AgencyFilterBar is active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:33:48 -06:00
michael
bcc20260de Add sortable, filterable campaign list with "My Campaigns Only" toggle
- Backend: Expose created_by field on CampaignResponse schema and all
  response constructors in routes.py
- Frontend API layer: Add created_by to CampaignResponse interface and
  createdBy to the frontend campaign converter
- Campaign list: Add column sorting (click headers to toggle asc/desc),
  per-column text filter inputs below headers, and a "My Campaigns Only"
  toggle that filters to campaigns created by the current user
- Default sort is lastModified descending to match existing behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:43:07 -06:00
michael
407f11c003 Add user change history audit trail for compliance
Adds a user_change_logs table to track all role and agency changes made
to users by super admins. Includes a change history modal in the User
Management screen (clock icon per row) showing timestamped, human-readable
change descriptions with the actor who made each change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 08:41:16 -06:00
michael
ebfcd60c71 Fix campaign visibility bug for unassigned users after agency reassignment
Unassigned (no agency) non-admin users previously saw ALL campaigns due to
a truthiness check that treated None agency_id as "no filter". This was a
security bug — they should see NO campaigns and be blocked from creating them.

Backend: Add _NO_AGENCY sentinel to distinguish "no filter" from "no agency",
add early-returns at all 5 list/analytics endpoints, fix _check_campaign_access
to explicitly reject unassigned users, and block campaign creation with 403.

Frontend: Add isUnassigned boolean to UserContext, show informational empty
state on Campaigns view, and reinforce readOnly for defense-in-depth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:42:42 -06:00
michael
d21036a0de Add 4-tier RBAC backend: auth dependencies, role enforcement, agency filtering
- Add CHECK constraint migration for users.role (super_admin, oversight_admin, agency_admin, basic_user)
- Add get_current_db_user dependency resolving Azure claims to User ORM with agency
- Add require_role() factory and require_write_access() dependency
- Auto-promote dev user to super_admin when DISABLE_AUTH=true
- Add /api/me, PUT /api/users/{id}, POST /api/agencies endpoints
- Apply agency-based data filtering on campaigns, analytics, audit routes
- Block oversight_admin from all mutation routes (campaigns, proofs, flags, resolves)
- Restrict dropdown option mutations to super_admin only
- Add role check in WebSocket handler to block oversight_admin from analysis
- Add CurrentUserResponse, UserUpdate, AgencyCreate schemas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 08:28:23 -06:00
michael
220a97ab57 Wire up Errors tab in Auditing: auto-create ErrorItem on Analysis Error
- Create ErrorItem record when proof analysis results in "Analysis Error" status
- Add submitter_name/submitter_agency fields to ErrorItemResponse schema
- Eager-load proof creator and agency in error items query to avoid N+1
- Populate submitter fields from proof creator in the API route
- Update frontend ErrorItemResponse type and conversion to map submitter fields
- Fix ErrorsTable proof name styling to blue link (text-active-blue) matching Flags tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 13:55:16 -06:00
michael
2f547dc494 Detect identical file uploads via MD5 hashing
- 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>
2026-01-25 10:15:48 -06:00
michael
53351c86f3 Fix PDF pages route ordering for correct path matching
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>
2026-01-25 09:04:58 -06:00
michael
d97be02b0b Add PDF preview support with on-demand rasterization
- 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>
2026-01-25 08:56:23 -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
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
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
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
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 Clervi
dc17cd087c permissions changes 2025-12-18 16:51:27 +00: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