Status and intended outcome
Draft for decisions; no product implementation or launch authorization. Add customer-owned sending domains and sender identities, independent workspace newsletter tiers, and a complete newsletter workspace atmail.tuturuuu.com. Infrastructure
owns platform approval and operations. Supabase remains authoritative; Cloudflare
owns new schedules, queues and dispatch compute. Amazon SES is the chosen
newsletter/bulk delivery provider; Polar owns subscription payments.
Unapproved workspaces have zero newsletter sends, including on Free. Free
provides 10/day only after workspace newsletter approval. Default access is denied. A workspace request, its sending domain, and each sender
address require separate platform-admin approval. Buying a subscription never
bypasses approval, consent, suppression, abuse controls or provider limits.
Existing personal/connected mail and transactional notifications retain their rules.
The user approved SES for newsletters on 2026-10-25. Cloudflare Email Service
remains available for existing transactional mail only; its marketing restriction
is no longer a newsletter launch dependency. Cloudflare still owns all new
scheduling and fan-out compute. Live SES account/region production access, verified
customer-domain authority, quotas and feedback configuration remain acceptance
gates; provider choice is not proof they are provisioned. No sends or production
writes are authorized by this draft.
Sources below were checked on 2026-10-25. Repository inventory is a source snapshot
at 45fdcb32ca, not a claim about live provider configuration or deployed health.
No credentials, live catalog, production database or sandbox organization was read.
Workspace staff-test gate
The workspace staff-test send is closed unlessnewsletter_sending is on, the customer subdomain is a verified non-apex name outside tuturuuu.com, a platform admin has approved the domain and the sender local-part, and the workspace holds fewer than 10 reserved or accepted sends for the current UTC day. A send reserves its slot before the mailer is called, reservations are serialized per workspace, and only a definite mailer rejection releases a slot; a reservation that never finishes keeps its slot until the UTC day ends. Regression coverage: apps/database/supabase/tests/newsletter-delivery-cap-reservation.sql and the concurrent race in apps/database/scripts/newsletter-cap-concurrency.mjs. The only recipient is the signed-in actor. Subscriber rows are stored and are not recipients of this send.
Existing inventory and reuse boundaries
No general-purpose workspace add-on/entitlement model was identified in the
examined billing/schema paths. Confirm schema drift before authoring migrations.
The existing Polar client uses the installed SDK’s
Polar constructor and
server option (packages/payment/src/polar/server.ts); current upstream examples
use versioned APIs. Pin the installed API contract and test compatibility before
adopting new SDK examples or upgrading dependencies.
Runtime and ownership
Mail and Infrastructure use their authenticated satellite sessions. Resolve actors throughgetSatelliteAppSessionUser or the applicable satellite request actor;
never use raw Supabase user helpers in satellites. Workspace aliases are normalized
before all membership, preview and mutation checks. Browser requests use typed
packages/internal-api helpers and TanStack Query; no raw app API fetching or
useEffect fetching.
New/substantially reworked Web handlers belong in apps/web/src/app/api/**.
Existing app-owned Pay/Mail/Infrastructure adapters retain explicit ownership;
choose their route placement with the owning platform maintainer before coding.
Shared newsletter policy, entitlement and state machines have framework-free
entrypoints with injected identity, storage, clock, locale and transport. Prefer
@tuturuuu/utils/effect for orchestration with typed errors and bounded concurrency.
No resumed Rust/TanStack runtime or broad framework migration is needed.
Request flow: Mail authorizes a campaign and commits its immutable revision plus
an outbox entry. A Cloudflare processor claims outbox pages and enqueues recipient
IDs. Queue consumers reauthorize each recipient immediately before submission.
Supabase is the transaction boundary; the queue is a wake-up hint, not permission.
An outbox row survives publication failure; duplicate queue publication cannot
create a second recipient claim. Provider events arrive on a separate trusted queue.
Follow Cloudflare ownership and
cost/stop acceptance.
Use current cf/Vite+ conventions where parity is qualified; retain Wrangler for
unqualified operations. New Workers join the active service inventory and require
exact-commit emitted-artifact CI and isolated Worker runtime acceptance.
Domain and sender onboarding
Workspace owners submit business identity, intended content, audience provenance, expected volume, website, postal address and abuse contact. State isnot_requested → pending → approved | rejected; approved can become suspended.
Reapplication preserves prior decisions and reason history. Rejected or suspended
workspaces cannot send even on a paid plan.
A workspace sending-domain claim references the canonical domain row and tracks
independent DNS state (unverified, checking, verified, failed, expired)
and review state (pending, approved, rejected, suspended). Readiness requires
both current DNS verification and approval. Store the exact account, zone,
provider domain identifier, normalized IDNA domain, expected DNS records, revision
and verified time. A domain cannot be concurrently claimed by unrelated workspaces;
transfer requires revoke, ownership re-verification and a new approval. No automatic
inheritance from parent-domain approval or a wildcard sender.
The setup screen presents provider-returned records with host/type/value and
observed status. Use SES verified domain identities,
DKIM DNS records and a custom MAIL FROM
subdomain with SES-issued SPF/MX; verify customer DMARC alignment. Customer DNS
need not move to Cloudflare. Prove ownership in the platform SES account/region,
or use explicit SES sending authorization
for a customer-owned SES identity; pin account, region and identity ARN.
Use provider-issued DKIM selectors; verify aligned visible From, DKIM signing domain
and envelope sender. Preserve existing root MX and DMARC policy; never create two
SPF records or weaken an existing DMARC policy. Prefer a dedicated sending subdomain.
The customer confirms DNS changes; do not request their account-wide API token.
The selected SES identity model must use narrowly scoped server credentials.
Cron Control owns verification, default off. Proposed bounds: 25 due domains/tick,
one provider-status lookup/domain/attempt, 12 total attempts over 48 hours, capped
backoff with jitter, lease expiry and a durable cursor. A terminal/failing exhausted
row stops polling. Manual Retry creates an audited new revision with a capped
operator budget; it cannot reset a global spending limit. Recheck active domains
under a renewable, budgeted verification lease, and fail closed on expired proof.
Missing records or provider disablement suspend future sends, with clear recovery.
Sender identity is an exact canonical address linked to the approved domain claim.
Verify mailbox control with an expiring, single-use challenge where supported, then
require platform-admin approval. Sending-subdomain control alone does not approve
every local part. State includes pending_verification, pending_review, approved,
rejected, suspended, revoked. Changing address/domain invalidates verification
and approval; changing display name or reply-to is audited and re-reviewed if it
changes represented identity. Reply-to must be verified or constrained by policy.
Never create inbound mailboxes merely to approve newsletter senders.
Approvers must have a fresh verified exact @tuturuuu.com identity and the
explicit platform newsletter-management permission in the root workspace. Tenant
admins cannot grant this permission. Decisions record actor, reason, evidence,
resource revision and timestamp; stale concurrent decisions return conflict.
Suspension increments the sending fence immediately. Approval never enables a
provider action by itself when another gate remains closed.
Sending, idempotency and bounded cost
Chosen transport: Amazon SES, using the existing provider adapter and qualifying its Worker-safe authenticated boundary. SES v2 SendEmail supports simple/raw/templated email. Preserve custom unsubscribe headers and explicit configuration-set/identity binding. SES quotas are regional, including a rolling 24-hour sending quota and per-second rate. Sandbox accounts allow 200 messages/24 hours and one/second, with verified recipients; live account capacity and production access remain unverified. Use exactly one recipient per send, no CC/BCC; proposed newsletter content cap is 256 KiB with hosted images and no attachments for the initial release. A frozen campaign revision stores sender, content hash, audience snapshot cutoff, consent policy, schedule and maximum recipients. Key each recipient delivery by(workspace_id, campaign_revision_id, subscriber_id) with a unique constraint and
payload hash. Claim, quota reservation and spending reservation occur atomically.
Queue duplicates read the existing row. Changed payload requires a new campaign
revision, never a reused key. Subscriber status and suppression are checked again
at send time, even when the audience snapshot contains the address.
States: pending → reserved → submitting → accepted | rejected | unknown, followed
by monotonic delivery outcomes. A provider message ID is not inbox delivery proof.
No SES idempotency guarantee is established for the selected send contract. Therefore
exactly-once external delivery is not promised: timeout, process crash after
submission, or receipt-write failure becomes unknown, retains quota/spend, and
never auto-resubmits. Reconcile against provider message/event evidence; absent
proof stays unknown. A known pre-submission failure or explicit API rejection may
release reservation. Do not treat a later rejection as proof an earlier unknown
attempt did not send.
Proposed finite consumer limits: 25 recipient IDs/wake, concurrency 2, three durable
attempts only for proven unsent failures, 24-hour retry age, bounded backoff and a
DLQ. Configure Queue retries consistently with that budget; redrive preserves
identity, attempts and deadlines. Provider delivery retries after acceptance are
provider-owned and do not trigger a second application send. Campaigns reserve their full audience against the applicable quota before
scheduling. An audience that does not fit is rejected or paused, with a choice
to reduce it; it never silently spills into later days or sends a quota-sized subset.
Durable stop fence and total-spend envelope
Store global, workspace, domain and campaign stop flags with monotonic generations, lease expiry and actor audit. Before each expensive operation, submission and reschedule, a fenced transaction checks all flags, approval, entitlement, quota, remaining operation credits and lease. Serialize final submission admission and stop on a per-workspace coordinator; one in-flight provider call may already have crossed the boundary. The stop UI reports that bounded uncertainty and waits for in-flight admission receipts. A generation invalidates queued stale work; stopped or terminal work is acknowledged without fan-out or self-rescheduling. A stop endpoint requires platform authority, persists before success and works independently of Mail UI/ingress. Also document an operator path to pause Queue consumers, disable the Cron Control job and revoke the sending credential/binding. Stop cannot recall accepted mail. Test stop racing claims, submissions, crashes, queue retries, lease renewal and rescheduling in the real isolated Worker runtime. The hard envelope is not just a dollar counter around sending. Atomically reserve conservative micro-dollar cost and finite operation credits before work: provider submissions, enqueue/read/delete/DLQ operations, Worker invocations, DB calls, R2 bytes/requests, verification polls and event ingestion. Account, workspace, campaign, workspace-local-day and billing-period budgets all apply; exhaustion fails closed. Do not discount included provider allowance when reserving. Concurrent leases reserve disjoint credits; no restart resets budgets. A bounded sweeper expires leases but never refunds unknown provider writes. Queue/event deliveries themselves can cost money before application code runs. Thus application counters alone cannot cap the entire Cloudflare invoice. Require finite admitted campaign volume, producer limits, finite Queue retention/retries, bounded provider-event amplification and a separate hosted control-plane stop procedure. Measure the worst-case residual cost of already admitted messages and in-flight work. Keep production default off until hosted pause/revocation receipts and that residual envelope are accepted; do not claim an absolute invoice cap against arbitrary hostile ingress. Reject unknown external ingress before expensive work and use provider/edge controls as additional defenses. SES pricing lists à la carte outbound at $0.10/1,000 and Essentials at $0.16/1,000 in its first volume band. The chosen AWS account plan remains unverified. Email-only cost for Tier 1 is $0.20/$0.32 and Tier 2 full 31-day use is $1.55/$2.48 respectively. These exclude data, optional features, Cloudflare, storage, database, payments and support. Reserve against the verified plan’s complete cost envelope; do not use the superseded Cloudflare $0.35/1,000 calculation for SES or claim net margins. Paid tiers remain exclusive. Queues pricing bills operations, with payload billing in 64 KiB chunks and retries adding reads. Pin current rates in the implementation cost worksheet; count normal and persistent failure paths, fan-out, DLQ, event volume and storage retention. CPU caps and billing alerts are detection/containment aids, not total-spend caps. Numeric platform dollar caps, aggregate provider capacity and warm-up limits require owner approval.Delivery feedback, consent and compliance
SES configuration-set event publishing provides delivery/bounce/complaint feedback, for example through SNS to a bounded Cloudflare ingestion Worker and trusted Queue. Verify SNS signatures/certificate source, allowlisted topic ARN, account/region, subscription and provider-message binding before admission; never blindly follow arbitrary confirmation URLs. Deduplicate event IDs; tolerate replay, out-of-order and late events. Do not accept an unauthenticated HTTP JSON event as provider evidence. Store compact normalized facts, not subject/body copies. A delivered event means remote server acceptance. Hard bounces and complaints suppress immediately before further sends. Temporary failures stay provider-owned; a proposed three soft failures in seven days triggers review/suppression, subject to provider semantics. Reconcile provider-managed SES suppressions with local decisions using bounded cursors. Provider account-wide policy suppression always wins. Workspace unsubscribe is tenant-scoped; platform abuse suppression is global and cannot reveal another tenant’s address history. Operators cannot remove provider read-only suppression by changing local state. No automatic resubscription on import, plan change, refund or successful delivery. Double opt-in is the product default: signed-up contacts remain pending until a single-use expiring confirmation token is redeemed. Store consent purpose, source, policy/version, timestamps and evidence reference. Imports require consent mapping and an attestation plus evidence; imported unconfirmed contacts do not receive a campaign. Purchased/scraped lists are forbidden. Historical proven consent can use an explicit reviewed migration exception; do not blast confirmation emails at an unverified imported list. Confirmation/test sends need their own abuse and cost budgets, cannot be an open relay, and must respect suppression. Every campaign includes visible unsubscribe, business identity, postal address and accurate subject/From. Implement HTTPSList-Unsubscribe plus
List-Unsubscribe-Post: List-Unsubscribe=One-Click under
RFC 8058, and verify DKIM covers the required
headers in received messages. The opaque high-entropy token is scoped to workspace,
subscriber and purpose; store a hash, redact it from logs and avoid third-party
assets/referrers. Unauthenticated POST unsubscribes idempotently without login or
confirmation. GET shows the preference page and does not mutate (link scanners).
Suppress immediately, including queued recipients. List-specific preferences may
narrow subscription choices but must offer workspace-wide newsletter opt-out.
The FTC CAN-SPAM guide
requires truthful headers/subjects, required commercial identification and postal
address, a working opt-out and honoring it within ten business days. This design
uses immediate suppression and does not charge for opting out. Keep suppression
available even while billing/access is suspended.
For GDPR, record the lawful basis,
withdrawal, access/export/erasure and retention process; double opt-in is a product
policy, not a claim of automatic legal compliance. Confirm local ePrivacy/direct
marketing requirements, processor agreements, transfer terms and controller roles
with the legal owner before launch. Minimize IP/user-agent retention; consent
evidence references must not become permanent raw tracking logs. Retain only the
minimum suppression tombstone needed to prevent reimport, under an approved lawful
basis and retention policy. Deletion fences prevent queued work resurrecting data.
Open/click tracking defaults off, needs explicit privacy policy and consent review,
and must be labeled approximate (proxies/scanners distort it). Initial analytics
are accepted/delivered/deferred/bounced/complained/unsubscribed counts. Warm up each
domain; proposed review triggers are any complaint among the first 100 accepted
messages, or at least 0.1% complaints / 2% hard bounces over a defined 1,000-message
window. These are conservative draft controls, not provider guarantees. Sparse
samples need review; stale feedback or event ingestion failures pause expansion.
Retention — user-approved 2026-10-25
This approved newsletter retention standard covers GDPR and Vietnam PDPD Decree 13/2023 requirements for legal review; they do not establish compliance by themselves. The legal owner must also check Vietnam’s currently effective successor legislation and shorter statutory response deadlines; a product 30-day SLA cannot override a shorter legal duty.
Erasure overrides routine three-year consent retention unless a documented lawful
exception applies. Workspace deletion overrides indefinite suppression retention;
recreating a workspace cannot silently restore consent. HMAC is pseudonymous data,
not anonymous: keep keys outside tenant-visible data, version them, isolate them
per workspace, and support deletion and bounded key rotation without storing raw
email. Existing provider account-wide suppressions are a separate safety boundary;
verify their plaintext retention/deletion capabilities and processor obligations
before claiming end-to-end no-plaintext suppression. Global local abuse suppression
must also avoid plaintext recipient storage; its scope is distinct from tenant
opt-outs. Retention jobs run on Cloudflare with bounded pages, durable deletion
fences, audit and no resurrection from queues or backups. Document backup expiry
and processor deletion in the acceptance plan.
Proposed data model and authorization
Names below are proposals, not migrations. Useprivate service-only tables with
RLS enabled and no anon/authenticated grants by default; member-facing APIs expose
minimal authorized projections. Every tenant row has ws_id, and composite foreign
keys (ws_id, resource_id) prevent cross-workspace parent/child references.
Member access requires live workspace membership plus granular permissions for
viewing newsletters, managing audiences, editing campaigns, sending campaigns,
managing domains and managing subscriptions. Reuse
manage_subscription for
billing where appropriate. Sending and subscriber export require explicit rights;
mailbox membership alone is insufficient. Test permission removal during a job.
Privileged Workers receive narrow RPC capability, not a general user-facing
service-role query proxy. Each RPC validates workspace, resource, claim lease and
generation. Prefer invoker functions. Necessary SECURITY DEFINER functions use
SET search_path = '', schema-qualified tables/functions, fixed SQL, explicit
actor checks and narrow EXECUTE grants; revoke PUBLIC/anon/authenticated unless
explicitly required. No caller-supplied actor ID substitutes for authentication.
Audit decisions and provider/billing mutations append-only with redacted fields.
A failed audit write aborts the associated approval or entitlement mutation.
Migration and rollout safety
Create additive private tables and indexes first, RLS/grants in the same migration. Avoid rewriting hot Mail/subscription tables or backfilling customer approval from legacy active flags. Add nullable references, backfill bounded keyset batches, add FK/check constraintsNOT VALID where supported, then validate separately under
short lock/statement timeouts. Use concurrent index creation for populated tables
only in a migration path verified to permit nontransactional DDL. Never place
CREATE INDEX CONCURRENTLY inside a transaction blindly. Retry only bounded known
lock failures; record unknown migration outcome before retrying.
Rehearse full reset and upgrade from a production-shaped anonymized fixture in an
isolated database, including lock contention, RLS negative controls, constraint
validation and rollback-by-disabling flags. Generate types from applied schema.
Keep schema and its consuming contracts in the same rollout unit when required.
CI builds the exact app commits; staging migration must pass before authorized
production promotion and the gated supabase-production.yaml result. No manual
sb:push/sb:linkpush. This design PR executes no migration.
Add-ons, Polar and daily quota
Recorded product decisions (2026-10-25)
The user approved SES for newsletter/bulk delivery and approved the retention and billing policies below as written. Free is 10/day only after workspace newsletter approval; every unapproved workspace receives 0 newsletter sends, regardless of payment. Domain and sender approvals remain independent prerequisites. Platform-wide GDPR/PDPD implementation is a separate lane; this document defines the newsletter retention standard that lane may cite, without expanding its scope. Scope: customer newsletter sending in Mail and platform administration in Infrastructure. Transactional email, connected accounts, workspace base tiers and AI credits retain their current policies. These decisions govern live and future migration paths; no older $5/500 or $2/2,000-per-day proposal may be seeded.
A workspace has exactly one newsletter tier. No stacking, additive free
allowance, simultaneous paid-tier grants or quota multiplication is permitted.
The generic workspace add-on catalog remains useful for attaching this newsletter
capability independently of base workspace billing, but its newsletter entries
belong to one exclusive tier group. Rename provisional tables if a narrower
newsletter-specific implementation is clearer. Tier selection must not replace
the workspace’s unrelated FREE/PLUS/PRO/ENTERPRISE base subscription.
The prices, caps and tier exclusivity are user decisions. Workspace timezone day
boundaries, billing-anniversary pool reset, exact corporate identity plus explicit
platform permission for approvers, conservative workspace daily/monthly spending
caps and a global kill switch are orchestrator-selected defaults the user can
override. Numeric spend caps remain a launch configuration gate.
A Polar discount changes price, not entitlement. Coupons remain supported as
product-restricted Polar discounts on either paid tier. Never infer quota from
paid amount or browser coupon text. Bind each catalog entry to merchant,
environment, product, price, currency and immutable entitlement version. Transition
an existing paid tier through one subscription change instead of buying a second
subscription; reconcile duplicate external subscriptions without granting twice.
Entitlement resolution is a pure versioned function over approval, provider
eligibility, the one effective tier and valid promotions. All grants remain
constrained by global/provider/domain/abuse/spending ceilings. Workspace secrets
may lower abuse limits but cannot create grants or bypass approval. Tier 1 permits
at most 200/day while its 2,000-period pool remains; exhaustion permits zero sends
until renewal, not a fallback extra 10/day. Tier 2 permits 500/day. Free permits
10/day only after newsletter approval; without approval every tier permits zero. Tier changes preserve prior usage and cannot reset the day’s consumed or
reserved capacity to zero.
Daily quota uses database time converted through the workspace’s persisted IANA
timezone and resets at local midnight. Store timezone version, period start/end
UTC instants and local date, not a bare date alone. DST days may be 23/25 hours.
New timezone settings take effect at a scheduled boundary without opening an extra
bucket; retain prior usage and enforce a transition interval that cannot grant
two allowances. The UI shows the actual next reset in the workspace timezone.
This product quota is separate from SES’s regional rolling 24-hour quota.
Monthly pool periods use authoritative subscription billing-period start/end
instants, anchored to the billing anniversary, not calendar months, quota-day
boundaries or a reset cron. Respect Polar’s returned interval for short months,
leap days and subscription changes; do not approximate it as 30 days. A UTC instant
at the boundary belongs to exactly one half-open interval. Webhook reconciliation
can reveal the new period late, but must never backdate duplicate grants. Period
renewal and subscription eligibility must be verified before creating new capacity.
In one transaction, freeze the full eligible audience and conditionally reserve the entire campaign
recipient count against its tier daily allowance, monthly pool when applicable,
and spending credits. The transaction either admits all recipients or none.
Store
quota_source, daily period ID, billing period ID, entitlement revision and
reservation state. Count accepted and unknown submissions, including accepted
hard bounces; release only proven unsent attempts to their original source and
period. A proven-unsent reservation crossing either boundary is reallocated
atomically against the new eligible periods before submission; accepted/unknown
remains charged to its submission periods. Release cannot revive expired capacity.
Upgrades do not reset existing use. No rollover or reset on retry, restart, coupon
change or duplicate webhook; no negative balances under concurrency. Tests and
confirmations have separate bounded budgets and cannot masquerade as campaigns.
Regression requirements for these product decisions: Free 10/day; Tier 1
200/day and 2,000/period; exhausted pool denying sends; Tier 2 500/day; exact
single-tier enforcement; pending/unapproved denial; full-count reservation and
quota rejection without a partial campaign; local-midnight/DST/timezone-edit transitions; billing
anniversary/short-month renewal; replay and concurrent reservation races. These
are required implementation coverage, not tests executed by this documentation PR.
Checkout and lifecycle
Use the platform merchant’s separate Tier 2 ($10) and Tier 1 ($2) recurring products, fixed USD minor-unit prices of 1000 and 200 and environment-specific allowlisted IDs. Preserve existing seat/base subscription handling and classifynewsletter_tier separately from tier and
credit-pack products. Polar subscriptions
and discounts support recurring offers
and once, fixed-month or forever discount durations. Restrict codes to the intended
product, dates and redemptions; record the advertised post-promotion price.
- A current member with billing rights requests an allowlisted plan. Server binds workspace/customer/environment and validates approval and coupon eligibility.
- Persist a unique checkout intent before calling Polar. Bind server-owned metadata and external customer identity to that intent; never trust workspace metadata submitted by the browser. A duplicate request reuses the intent.
- Create checkout through the installed SDK’s verified contract. Restrict success and return URLs to approved Mail/Pay routes. Unknown create outcome reconciles the same intent rather than blindly creating another subscription.
- Return from checkout shows payment pending until a verified webhook/readback confirms entitlement. Client success parameters never grant access.
Billing behavior — user-approved 2026-10-25
Upgrades apply immediately after the verified Polar transition and are prorated through Polar. Downgrades/cancellations take effect at period end, then select the lower tier or Free; no mid-cycle cut. Prior usage remains charged. Tier 1’s pool starts only at the verified paid billing-period boundary and never receives an unverified extra pool during upgrade/downgrade reconciliation. Onpast_due, retain the existing full tier limits for seven days from the
verified first past-due transition. Send bounded idempotent notices on days 0, 3
and 6 through Cloudflare-owned scheduling. Repeated events cannot restart grace.
At expiry use Free limits until paid. Canceled (effective ended cancellation) or
unpaid uses Free until resubscription; a future cancellation flag retains the
current tier until period end. Non-payment never deletes data, and domain/sender
approvals remain approved unless independently revoked for security or abuse.
Refunds/chargebacks need reconciled explicit revocation rules; they never reset
quota or silently delete content.
Reserve the full eligible recipient count at scheduling, including daily
quota, Tier 1 pool and spend. For future dates, reserve against the intended
workspace-local day and verified subscription period; do not reserve beyond a
known paid period or borrow unverified renewal capacity. If a later date’s tier
cannot be established, leave the campaign draft until it can be admitted.
A tier/grace/approval change revalidates all queued campaigns. If the remaining
audience no longer fits, pause with a notice; never select a smaller quota-sized
subset. Require explicit re-admission to resume. When several campaigns compete,
use deterministic schedule/creation order in one locked allocation transaction.
Full reservation prevents quota-driven partial sends; it cannot guarantee
atomic external delivery. Bounces, withdrawal, abuse suspension, provider failure
or Stop can still interrupt a campaign after some recipients were accepted. Show
those partial outcomes truthfully and retain unknown-send fences. Recheck consent
and suppression per recipient; never send to an unsubscribed person to preserve
an all-recipient promise. Test downgrade/grace expiry before dispatch and mid-run,
releasing only proven-unsent reservations and preserving accepted/unknown charges.
Sandbox acceptance plan
The design phase performs no provider writes. Provider feasibility uses a dedicated Polar sandbox, sandbox API/token/webhook secret and sandbox catalog IDs. The environment is separate from production; assert endpoint/organization before each setup action. Never fall back to production when credentials are absent. Current sandbox confirmation emails have recipient restrictions; lack of an email is not payment failure evidence. Create $10/month 500/day and $2/month 2,000-per-period (200/day) sandbox products, recurring prices and once/fixed/forever restricted discounts only in that sandbox. Exercise successful/failed checkout, invalid/expired/exhausted coupon, duplicate click, abandoned checkout, renewal, upgrade/proration, downgrade, scheduled and immediate cancellation, recovery, refund/chargeback where supported and portal return. Use supported test payment methods. Test forged/stale signatures, raw-body mutation, duplicate and reordered events, processing crash after receipt, wrong workspace/product/merchant/environment, subscription duplication and unknown provider writes. Freeze clocks for day/month boundaries. Unsupported lifecycle simulations use labeled fixtures and remain a hosted acceptance gap. Keep a redacted evidence matrix with product IDs privately; never put keys or customer data in PRs.UX specification
Infrastructure platform console
Add Newsletter approvals under platform administration: workspace, domain and sender review tabs, pending counts, age, risk filters and detail panels. Detail shows submitted identity/consent evidence, exact DNS results and timestamps, provider eligibility, previous decisions and associated workspace. Approve/reject needs a reason and current revision; suspend/revoke is always available with appropriate authority. No one-click bulk approval in the first release. Access requesters see actionable rejection reasons without internal risk notes. Sending health shows queue lag, oldest unknown send, feedback freshness, delivery/bounce/complaint rates with sample sizes, suppression sync state, provider capacity, budget reserved/spent/remaining and stop status. Scoped and global Stop controls show persisted generation and in-flight uncertainty; resume requires review and a fresh bounded lease. Domain setup displays DNS instructions and state even while approval is pending. Existing Infrastructure global templates, blacklist and transactional queue remain distinct destinations.Mail newsletter workspace
Add Newsletter as a first-class workspace destination. Any eligible workspace member can discover the request/status screen without creating an internal Mail mailbox. Approved users reach Campaigns, Audiences, Templates, Domains & senders, and Plan & usage. Build the access bootstrap separately from inbox-only corporate admission so customers can use newsletters without access to staff mailboxes.- Access request: business/contact, expected content/volume and audience consent inputs; submitted/pending/rejected/suspended states, timestamps and recovery. Billing stays unavailable until required eligibility is established.
- Audiences and lists: subscriber status/consent timeline, tags and segments, search and permission-gated export; bounded CSV import with preview, field map, duplicate/suppressed counts, consent evidence and resumable errors. Neutralize spreadsheet formulas in exports. Lists do not override workspace opt-out.
- Composer and templates: subject/preheader, approved sender, accessible rich text and plain-text version, desktop/mobile preview, safe merge-field allowlist, autosaved version history and test send. Mandatory identity/unsubscribe footer cannot be removed. Sanitize HTML; no scripts, arbitrary template execution or remote server-side URL fetches. Show missing fields before scheduling.
- Scheduling: explicit timezone plus resolved send date/offset; persist UTC instant and IANA zone, resolve DST ambiguity explicitly. Review audience count, exclusions, quota, estimated cost and readiness, then confirm immutable revision. Scheduling creates a durable Cloudflare-owned job, not a browser timer.
- Campaigns and analytics: draft/scheduled/sending/paused/completed/canceled, recipient-level authorized outcomes, unknown counts, progress and bounded retry recovery. Accepted and delivered are separate. Do not promise inbox placement.
- Domain and sender setup: step-by-step DNS rows, copy controls, last checked, next check/expiry, independent verification and approval badges, denial reason and bounded retry. Explain SES identity verification and account readiness before collecting payment.
- Plan and usage: daily accepted/unknown/reserved and remaining quota sources and monthly pool balance, workspace-local reset and subscription-period end, current price/discount duration/next price, payment state, upgrade/coupon entry and manage/cancel link. Show both plan and safety ceilings when the latter limits sends; avoid misleading unused-capacity claims.
bun i18n:sort. Update each app’s navigation.tsx aliases, children, icons and
permissions. Use existing shell hierarchy and accessible status text/focus handling,
not color-only states, native dialogs or hard-coded hue classes. Keep new files
under 700 LOC and split components near 200 LOC. Browser verification for this task
uses an admitted fleet host.
Security and threat model
No secrets in
workspace_secrets projections, client bundles, analytics or audit.
Store provider credentials in the established server secret mechanism; workspace
rows contain references/configuration only. Do not read or print existing secrets
to inventory them. Independent security review is required before integrating
identity, RLS, billing, webhook or Worker control changes. Open critical/high
findings retain the repository release hold.
Delivery plan and review boundaries
Each row is a small PR boundary; split a row further if its implementation exceeds a reviewable scope. Use native GitHub stacks only for real dependencies; independent UI scaffolding and provider research can be separate. The integration owner owns merge/promotion. This draft PR is never merged by the design child.
Local verification stays build-free; queue heavy tests/type checks through
ttr resources and use an admitted devbox where appropriate. CI must run applicable
lint/type/test and real app/Worker builds on the exact commit. Do not run
bun validate or app release builds on this machine. Required database reset tests
run only in an admitted isolated environment. Production cutover, Polar live
catalog writes and customer sending need separate release authorization and proof.
Remaining implementation gates
SES account/region, identity ownership/delegation, configuration set, verified feedback and actual pricing/quotas need read-only acceptance. Numerical spending caps need owner configuration. Refund/chargeback disposition remains explicit; no quota resets or silent content deletion. Retention and billing policies above are approved, not pending decisions. No live checks, sends or production writes are included in this documentation update; credentials must userequest_secret.