Skip to content

feat: Paid privacy opt-out, email thread entitlements, and settings cleanup#78

Merged
ajay-bhargava merged 1 commit intostagingfrom
feature/paid-privacy-email-entitlements
Feb 27, 2026
Merged

feat: Paid privacy opt-out, email thread entitlements, and settings cleanup#78
ajay-bhargava merged 1 commit intostagingfrom
feature/paid-privacy-email-entitlements

Conversation

@ajay-bhargava
Copy link
Copy Markdown
Contributor

Summary

Backend

  • Paid opt-out of training data: Schema fields, enforcement in conversationLogs (skips logging when opted out), Polar webhook handlers for subscription lifecycle
  • Email thread metering: 10 free outbound emails/month, automatic paywall email with checkout link on the 11th attempt via preflightOutboundEmail — no in-app payment UI
  • Preflight checks integrated into emailReply.ts and notes.ts
  • Auto-populate email from mentraUserId on user creation + backfillEmailsFromMentraId internal mutation for existing users
  • New email templates: OptOutCheckout, EmailThreadPaywall

Frontend

  • Settings: Training Data card sends opt-out instructions via email (no checkout redirect)
  • Removed all payment/billing/usage language from the web app
  • Removed Email Threads card entirely — entitlement is handled naturally via email during usage
  • Type safety fixes across ChatPage, FollowupsPage, MemoryPage, QueuePage

Screenshots

  • Added iPhone 15 mobile screenshots for all 5 pages (Home, Memory, Follow-ups, Queue, Settings)

Key Design Decision

All payment flows happen via email, not in the web app. Users never see pricing, usage counts, or checkout pages in the UI. When they exceed limits, the system sends an email with a checkout link automatically.

…leanup

Backend:
- Add paid opt-out of training data (schema, enforcement in conversationLogs, Polar webhooks)
- Add email thread metering: 10 free/month, auto-paywall email on 11th via preflightOutboundEmail
- Integrate preflight checks into emailReply.ts and notes.ts
- Add Polar webhook handlers for subscription lifecycle (create/update/cancel)
- Auto-populate email from mentraUserId on user creation
- Add backfillEmailsFromMentraId internal mutation for existing users
- New email templates: OptOutCheckout, EmailThreadPaywall

Frontend:
- Settings: add Training Data card (sends opt-out email, no in-app checkout)
- Remove all payment/billing/usage language from web app
- Remove Email Threads card entirely (entitlement handled via email)
- Type safety fixes across ChatPage, FollowupsPage, MemoryPage, QueuePage

Screenshots:
- Add iPhone 15 mobile screenshots for Home, Memory, Follow-ups, Queue, Settings

Amp-Thread-ID: https://ampcode.com/threads/T-019c9d33-f47d-73fa-b739-2873a25a4d6f
Co-authored-by: Amp <amp@ampcode.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 27, 2026

@ajay-bhargava must be a member of the With Context team on Vercel to deploy.
- Click here to add @ajay-bhargava to the team.
- If you initiated this build, request access.

Learn more about collaboration on Vercel and other options here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: edddb87f83

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +13 to +16
args: { mentraUserId: v.string() },
handler: async (ctx, args) => {
const user = await ctx.runQuery(api.users.getByMentraId, {
mentraUserId: args.mentraUserId,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bind opt-out checkout requests to the authenticated user

requestOptOutCheckoutEmail trusts a caller-provided mentraUserId and never checks ctx.auth or that the ID belongs to the caller, so any authenticated client can trigger paid opt-out checkout emails for another account if they know/guess that Mentra ID. This creates an account-level authorization gap (unsolicited billing emails and checkout links for other users) and should be restricted to the current authenticated user identity.

Useful? React with 👍 / 👎.

Comment on lines +50 to +51
if (used < FREE_EMAIL_THREAD_LIMIT) {
return { allowed: true as const, trackUsage: true };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce email quota atomically before allowing outbound sends

The entitlement gate returns allowed: true based on a read of current usage, but usage is only incremented later in separate mutations (notes.ts and emailReply.ts), so concurrent sends for the same user/period can both pass this check and exceed the 10-email free limit before paywalling. This race weakens billing enforcement and should be handled with an atomic check-and-increment path.

Useful? React with 👍 / 👎.

@ajay-bhargava ajay-bhargava merged commit 7faf9d9 into staging Feb 27, 2026
1 of 2 checks passed
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