Skip to content

feat(notifications): setup reminders for brands + creators, policy warnings - #103

Merged
keithfawcett merged 5 commits into
mainfrom
feat/setup-reminders
Oct 13, 2026
Merged

keithfawcett merged 5 commits into
mainfrom
feat/setup-reminders

Conversation

@keithfawcett

Copy link
Copy Markdown
Contributor

Summary

Most brands and creators sign up and stall before they can earn anything. This adds setup reminders for both, an ops-console Notifications tab, and a manual marketplace policy warning.

  • Brand setup reminders.
    • brand-setup.ts builds one checklist (program, marketplace listing, conversion tracking, first partner) and feeds the reminders, the ops console and the dashboard.
    • Up to three platform-voice emails go to the brand's signed-in admin: 2 days after signup, then 4 days later, then 7 days later.
    • Each email is sent exactly once, using a claim row in BrandNotification.
    • Unsubscribe is signed and one-click (RFC 8058), and it never silences sign-in or billing mail.
  • Creator profile reminders. The Network sends these (https://github.com/getcoherence/openpartner-network/pull/3). openpartner's scheduler triggers the run, passing publicUrl: NETWORK_URL so unsubscribe links keep the /api prefix.
  • Both sweeps are off until an operator turns them on in the new ops-console Notifications tab, stored in the PlatformSetting table. The tab previews exactly who the next run would email and can send immediately. The Brands and Creators cards show setup and reminder history, with a manual "send reminder" button.
  • Marketplace policy warning (manual only). An action on the Brands card emails the brand a templated notice with the operator's findings and an end-of-day deadline, and records it in the audit log.
  • Portal.
    • Creators get a profile checklist and a site-wide "brands can't find you yet" banner, plus expectations set at signup.
    • The dashboard gets a conversion-tracking step, and the duplicated "Create your first program" step is fixed.

Merge note (mailer.ts)

This branch and #88 both added Message.platform. #88 uses it to skip brand colors; this branch uses it to send as "OpenPartner" with Reply-To PLATFORM_OPS_EMAIL. Both now apply under the one flag. Side effect on main's existing platform senders:

  • Ops alerts and the ops-console sign-in now also send as "OpenPartner" with the ops Reply-To.
  • Unified workspace sign-in (signin.ts) now sends as "OpenPartner" instead of " via OpenPartner".

Deploy order

Deploy https://github.com/getcoherence/openpartner-network/pull/3 first, then this. Migration 20261012000000_platform_notifications runs automatically on deploy.

Test plan

  • Merged with the latest main. The only conflict was mailer.ts, resolved as above.
  • pnpm typecheck is clean. pnpm lint: 0 errors (the 5 warnings were already there).
  • Portal: 4 files, 24 passed.
  • Full API suite on a throwaway database: 593 passed, 1 skipped, 8 failed. The 8 are the multi-tenant RLS tests that also fail locally on unmodified main; CI passes them.

⚠️ Merging to main auto-deploys to production.

🤖 Generated with Claude Code

keithfawcett and others added 5 commits October 12, 2026 22:10
…rnings

Most brands and creators sign up and stall before they can earn anything:
41 of 43 creators are hidden from discovery with incomplete profiles, and
brands stop before creating a program, listing it, or connecting tracking.

Brand setup reminders (openpartner):
- brand-setup.ts: one checklist (program, marketplace listing, conversion
  tracking, first partner) from local signals, batched across brands. Feeds
  the reminders, the ops console, and the dashboard's new tracking step.
- brand-setup-reminders.ts: up to 3 emails (2 days after signup, then 4 and
  7 days later) to the brand's signed-in admin, in the platform voice.
  Exactly-once via a BrandNotification claim row; failed sends release it.
- Signed one-click unsubscribe (GET confirm page, POST + RFC 8058
  List-Unsubscribe-Post), scoped so it never silences sign-in or billing.

Creator profile reminders: the Network sends them (it owns creators and
the unsubscribe flow, see openpartner-network feat/creator-profile-reminders);
openpartner's scheduler triggers the run and the console previews it.

Both sweeps are OFF until an operator turns them on in the new ops-console
Notifications tab (PlatformSetting table: runtime config in the DB, not
env), which previews exactly who the next run would email and can send now.
Brands and Creators cards show setup/reminder history and a manual "send
reminder" button.

Marketplace policy warning (manual, per Keith): Brands card action that
emails the brand a templated notice (the free listing means creators must
join and be tracked through OpenPartner; fix by the deadline or the listing
is removed) with the operator's findings, and records it in the audit log.

Creator portal: a checklist on the profile page of exactly what's missing
(now including the handle the directory already required), a site-wide
"brands can't find you yet" banner, and expectations set at signup.
Dashboard: fixes the duplicated "Create your first program" step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p the /api prefix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted card matches the discovery bar

The deadline was now+N days, so the email (UTC) and the console (local
time) could show different dates. The Discover card listed handle + bio +
apply, out of step with the real requirements; it now points at the same
checklist as the profile page and banner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict in mailer.ts: both sides added Message.platform. #88 uses it to
skip tenant brand colors; this branch uses it to send as "OpenPartner"
with Reply-To PLATFORM_OPS_EMAIL. Kept both behaviours under one flag
(same meaning: OpenPartner talking, not a brand) and kept this branch's
extra `headers` alongside #88's branded `html` in the SMTP send.

Side effect for main's existing platform senders: ops alerts and the
ops-console sign-in (DEFAULT_TENANT context) now also go out as
"OpenPartner" with the ops Reply-To, and the unified workspace sign-in
(signin.ts — whose tenant context is an arbitrary first-matched brand)
now sends as "OpenPartner" instead of "<that brand> via OpenPartner".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@keithfawcett
keithfawcett merged commit 796492d into main Oct 13, 2026
9 checks passed
@keithfawcett
keithfawcett deleted the feat/setup-reminders branch October 13, 2026 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant