Add warmup content generation and admin review surfaces, plus mailbox warmup appeal/status APIs.
Track warmup engagement and tampering signals so unsafe mailboxes can be handled by the warmup flow.
Adds a dedicated admin path for sending platform email — distinct from
the campaign emailsend service (which sends through customer mailboxes)
so the two abuse surfaces never share code paths.
Schema (000047) adds admin_outreach_messages: every send is recorded
with sent_by, the resolved to_email, the optional reply_to, subject,
body, and a queued → sent/failed status. Failed sends keep their error
column populated for the audit log.
Extends notify.EmailNotificationService with SendOutreach so both
backends (SES + SMTP) support custom Reply-To: SES via the native
ReplyToAddresses field, SMTP via a forged Reply-To header. The
existing transactional Send() remains unchanged so no other caller is
affected.
Service (internal/app/adminoutreach) resolves recipients three ways:
to_email (raw address), to_user_id (sends to the user's account email),
or to_org_id (sends to the workspace owner). Persist-then-send-then-
mark ensures the audit row exists even if the mailer hangs, and
mark-failed captures the error string verbatim.
Routes:
POST /admin/outreach manage_organizations
GET /admin/outreach view_organizations
Admin UI: composer with recipient mode picker (email / user_id / org_id),
configurable Reply-To (defaults to support@warmbly.com so customers can
actually reply), subject + HTML body editor, and an outreach log below
showing the last 50 sends with status badges and error details. Sidebar
entry under Accounts (Send icon).
Three surfaces close the loop on the limit-increase workflow:
- admin/dashboard/LimitRequestsPage.tsx queues every pending request
with full context (org → users → field → current vs requested →
+delta) and one-click approve/reject. Both actions open a review
dialog; approve notes are optional, reject notes are required and
surface to the customer.
- web/settings/limits/page.tsx is the customer-facing form. Resource
selector, requested value, reason textarea, plus a list of every
past request with its status (pending/approved/rejected/cancelled)
and the reviewer's notes when present. Pending rows expose a
cancel link. Footer links to the ToS limits clause.
- site/terms.astro grows a new section 07 ("Usage limits and
increase requests"). Explicit: "unlimited" means no plan-tier cap
but a product-wide hard ceiling still applies, increases are at
Warmbly's sole discretion, and previously granted increases can be
revoked when reputation signals deteriorate. Bumps every existing
section heading and id from 07 onward.
Admin sidebar grows a "Limit requests" entry under Accounts (Gauge
icon). Web settings layout grows a "Limits" section under owner-only
sections.
Add /enterprise page wired to /admin/enterprise/inquiries. Sales-style
pipeline: pending → contacted → converted | declined, with an inline
<select> on each row so triage is one click per inquiry rather than a
detail-page round-trip.
Each row shows company, contact, estimated volume, team size, and the
free-form notes from the marketing-site form. Pending is the default
filter so the queue surfaces first; "All" reveals historical decisions.
Added a sidebar entry under Accounts (Briefcase icon) so the inquiry
queue is one click away from the rest of the customer-facing admin.
Shorter, cleaner path. The 'web-' prefix was redundant given the dir
sits at the repo root next to web/ and is unambiguously the admin web
app. Git tracked the rename so blame + history follow through to the
new location.
Updated README.md and docs/VENDOR_LOCKIN.md references plus the package
README header. No code changes.