Influencer Picker + Public Profile

Two major advertiser-side UX improvements and one creator-side overhaul. Influencers are now discoverable via a scored, tabbed picker (same pattern as the vendor picker). The Media Kit page is renamed to "Public Profile" with samples, past brands, and view analytics.

3rd release that day

Two major advertiser-side UX improvements and one creator-side overhaul. Influencers are now discoverable via a scored, tabbed picker (same pattern as the vendor picker). The Media Kit page is renamed to "Public Profile" with samples, past brands, and view analytics.

Influencer Discovery (advertiser side)

  • Migration c1d2e4f5a6b7 creates advertiser_favorite_influencers table
  • New endpoints on /influencers:
  • POST/DELETE /{ws}/favorite — idempotent star toggle
  • GET /favorites — starred influencers
  • GET /recent — influencers briefed in last 90 days
  • GET /search extended with sort=recommended|follower_count_desc|engagement_rate_desc|rating_desc
  • Every row now carries match_score, match_reasons[], has_restriction_conflict, is_favorite, rating_avg, rating_count, prior_briefs_count (4 batched queries, no N+1)
  • Scoring formula: 30% niche match + 10% collab types configured + 15% rating + 10% prior briefs + 8/4% verified + 5% engagement
  • Recommended tab auto-excludes restriction conflicts; other tabs flag them with red "Cannot book" banner
  • Frontend: /influencers page rewritten with 4 pill sub-tabs (Recommended / Favorites / Recent / All), URL persistence ?sub=, filters always visible, star toggle on cards, match-reason chips, "Starred N days ago" / "Sent brief N days ago" badges

Public Profile (creator side)

  • Migration d1e2f3a4b5c6 creates property_samples + media_kit_views (GDPR: SHA-256 IP hash only)
  • Sample Work — per-property CRUD via POST/GET/PATCH/DELETE /workspaces/{ws}/properties/{pid}/samples. 20 active cap, URL validation, sort_order, metrics JSONB (likes/views/comments/shares/reach)
  • Past Brands — stored in existing workspace.branding.past_brands JSONB array (no schema change). Up to 20 entries with name + logo_url
  • View tracking (no-auth): POST /public/media-kit/{slug-or-id}/track-view — fires on public page mount, 10-min IP-hash dedupe
  • Analytics (auth): GET /media-kit/analytics — total/7d/30d views, 30-day sparkline, top 5 referrers, unique visitors
  • Referrer normalization : hostnames only (linkedin.com not linkedin.com/feed), internal self-referrers filtered, no-referrer visits bucketed as "Direct"
  • Frontend:
  • Sidebar "Media Kit" → "Public Profile"
  • Properties page edit modal: SampleWorkManager component
  • Settings → Workspace: "Past Brands" editor with live preview strip
  • /profile/media-kit: analytics card at top (big 30-day count, recharts sparkline, top-3 referrers)
  • /public/media-kit/[slug]: sample work grid per property, past-brands strip, fires view tracking on mount
  • PDF template extended to include samples + past brands

Files (14 new, 12 modified)

Backend: 2 migrations + 3 models + media_kit_analytics.py + extensions to briefs/marketplace/public/workspaces. Frontend: SampleWorkManager component, public.ts API client, rewrites of influencers/properties/settings/profile-media-kit pages.

---

Want to see it in your own workspace?

Bring planning, discovery, delivery, and measurement into one platform.