Skip to content

Org audience mass-email + org-level read-only viewer role - #51

Merged
ralyodio merged 1 commit into
masterfrom
feat/org-audience-and-viewer-role
Jun 11, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/org-audience-and-viewer-role

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Summary

Two features, both tested green (typecheck, next build, 327 tests).

1. Org audience mass-email

  • Connect each project's backing DB as a per-org data source: Supabase (service-role auth.users or a public table) or Turso (@libsql/client, read-only SELECT, guarded).
  • Sync pulls every user email into a deduped per-org audience; blast sends through the org's existing SMTP/Resend sender config.
  • Always adds one-click unsubscribe + List-Unsubscribe headers; skips per-org unsubscribes and globally-unsubscribed marketing_contacts.
  • Fix: an explicit resend org sender config is no longer hijacked by a global SMTP_HOST env.
  • New dashboard panels (data sources, sync, compose/preview/blast), /unsubscribe/org/[token], and connector tests.
  • Migration: 20260611140000_org_audience.sql

2. Org-level read-only "viewer" role

  • The missing role option in the org Team-members panel: invite as Member or Read-only, a Make read-only / Make editor toggle on existing members, and viewer badges.
  • Enforcement: viewers read everything org-wide (is_org_wide_member + is_project_member widened) but write nothing (is_org_owner / is_project_editor unchanged).
  • Role carried through organization_invitations.role and applied on accept.
  • Migration: 20260611150000_org_member_viewer_role.sql

Migrations

Both migrations have already been applied to the hosted Supabase project (supabase db push), so they're live on the shared DB.

Test plan

  • tsc --noEmit: clean
  • next build: compiled successfully
  • vitest run: 327 passed / 7 skipped

🤖 Generated with Claude Code

Org audience / mass email:
- Connect each project's backing DB (Supabase via service-role auth.users or
  a public table; Turso via @libsql/client read-only SELECT) as a per-org data
  source, sync every user email into a deduped org audience, and blast it
  through the org's existing SMTP/Resend sender config.
- Always adds one-click unsubscribe + List-Unsubscribe headers and skips both
  per-org unsubscribes and globally-unsubscribed marketing_contacts.
- Fix: an explicit "resend" org sender config is no longer hijacked by a global
  SMTP_HOST env (sendOutreachEmail now honors the provider choice).
- Migration 20260611140000_org_audience.sql; new lib/audience/*; dashboard
  panels; tests for connector normalization + query guard.

Org-level viewer role:
- Read-only org members ("viewer"): see every project in the org but cannot
  mutate any project or org data. Reads widened in is_org_wide_member +
  is_project_member; writes unchanged (is_org_owner / is_project_editor still
  owner/member only). Migration 20260611150000_org_member_viewer_role.sql.
- Team-members panel gets a Member/Read-only invite dropdown, a
  "Make read-only / Make editor" toggle, and viewer badges; role carried
  through organization_invitations.role and applied on accept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​libsql/​client@​0.17.310010010089100

View full report

@ralyodio
ralyodio merged commit 5d48fc7 into master Jun 11, 2026
8 checks passed
@ralyodio
ralyodio deleted the feat/org-audience-and-viewer-role branch July 1, 2026 03:35
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