Open-Source Cold Email & Warmup Platform
Warmbly 是开源的冷邮件平台:温暖您的邮箱、发送活动、并对每条回复进行分流。可在我们的云端运行,也可自行托管整套系统。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Everything goes live.
FullSend is an autonomous marketing/content engine for applications. Connect a GitHub repository and FullSend builds verified product intelligence, a marketing plan, Instagram content, creative, scheduling, publishing, and analytics.
Major operations are persisted as jobs. Closing the browser does not stop work. Refreshing the application does not restart completed stages. Retries resume the failed operation rather than restarting the whole pipeline.查看完整 README ↗Everything goes live.
FullSend is an autonomous marketing/content engine for applications. Connect a GitHub repository and FullSend builds verified product intelligence, a marketing plan, Instagram content, creative, scheduling, publishing, and analytics.
GitHub repository
↓
Product Intelligence (durable)
↓
Marketing Plan (durable)
↓
Instagram Content (durable jobs)
↓
Creative / Media (durable public URLs)
↓
Review / Approval
↓
Schedule
↓
Background Worker
↓
Instagram Publishing
↓
Analytics
↓
Optimization
Major operations are persisted as jobs. Closing the browser does not stop work. Refreshing the application does not restart completed stages. Retries resume the failed operation rather than restarting the whole pipeline.
An HTTP request creates durable jobs and returns. A worker pass runs separately and is bounded three ways, each closing a different route back to a request that outlives its own invocation:
Publishing is durable in the same sense. Instagram publishes in two calls — create a media container, then publish it — and the container id is written down before the publish call, the submission timestamp immediately before it goes out. If the response is lost, the next attempt asks Instagram what actually happened rather than publishing again. A unique index on the receipt is the backstop.
Instagram is the only active production social destination. TikTok exists in the codebase but is gated off by default (FULLSEND_TIKTOK_ENABLED; see OPERATOR_ACTIONS.md). The production content, scheduling, media, and publishing flow is Instagram-focused.
Plans live in src/lib/billing/plans.ts: Free / Send ($29) / Full Send ($79) / Agency ($249).
STRIPE_SECRET_KEY → billing is off; every account gets the full product with no limits.active or trialing subscription. Checkout and the Customer Portal handle cards — FullSend never sees card numbers.FULLSEND_ADMIN_EMAILS (or users.is_admin) get unlimited plan limits while still using the app normally — they are not free-plan capped when Live billing is on. Set [email protected] on Vercel for the creator account./api/billing/webhook keep the subscriptions row in sync. In-app UI: /app/billing.Owner setup (Dashboard + Vercel env) is documented in the Stripe billing pull request checklist.
Requires Node.js 22.x.
npm ci
npm run dev
Useful commands:
npm run typecheck
npm run lint
npm test
npm run build
npm run e2e
npm run worker
Linting is the ESLint CLI against eslint.config.mjs. Next 16 removed next lint, and next build no longer lints.
FullSend uses Next.js/Vercel for the application and Supabase for persistence, authentication, and media storage.
Run the database migrations in supabase/migrations/ in order:
| Migration | What it adds |
|---|---|
0001_fullsend_init.sql | Every table, and the RLS policies that keep tenants apart. |
0002_creative_storage.sql | The public fullsend-creative bucket Instagram fetches media from. |
0003_durable_publishing.sql | The columns that make a publish recoverable, and the unique index that makes publishing the same post twice impossible. |
0004_analysis_commit.sql | The commit an analysis was derived from, so the same commit is never analysed twice. |
0005_project_brand_identity.sql | Each project's own colours, type and marks, so no product is marketed in FullSend's identity. |
0006_generation_state.sql | Whether a post actually finished being made, and the vault column for a Facebook Page token. |
A migration file in the repository is not a migration in the database. GET /api/health checks each one against the live schema — including whether the storage bucket exists and is public — and names the file to run for anything missing.
Required production configuration includes:
NEXT_PUBLIC_APP_URL
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
FULLSEND_ENCRYPTION_KEY
CRON_SECRET
ANTHROPIC_API_KEY or OPENAI_API_KEY
GitHub Actions drives the background queue/heartbeat. The worker claims jobs with a lease, persists results, retries bounded failures, and recovers stale work.
.github/workflows/heartbeat.yml asks for */5 * * * *. GitHub does not honour it. Scheduled workflows are throttled hard on quiet repositories, and in practice this one fires anywhere from 45 minutes to four hours apart.
Nothing in the schedule can fix that, so the run compensates for it: the queue job stays up and sweeps continuously — polling every 15 seconds while there is work and every 60 seconds when idle — until the next firing cancels and replaces it. Coverage comes from runs being long rather than from the schedule being punctual.
On a public repository this is free: Actions minutes are unmetered. On a private repository it is not — a continuous sweep will consume your monthly Actions allowance. There, either shorten the deadline in the workflow or use an external pinger instead.
For a genuinely punctual worker, point any scheduler at the queue endpoint:
POST https://<your-app>/api/cron/queue
Authorization: Bearer <CRON_SECRET>
Every five minutes is a sensible interval; each call is a bounded worker pass and returns as soon as it has done its allowance. Free services that do this include cron-job.org, Cronitor and UptimeRobot. On Vercel Pro you can use native crons in vercel.json instead — disable the Actions workflow if you do, so the jobs are not driven twice.
Whatever drives it, treat anything other than HTTP 200 as a failure — a redirect especially. Vercel answers 308 for any origin that is not the canonical one: http:// rather than https, a www/apex mismatch, a deployment alias pointing at the production domain. Most HTTP clients neither follow a redirect by default nor call it an error, so a wrong URL returns a success with a body of Redirecting... and the queue silently never runs. This is not hypothetical: it stalled this deployment for days, wearing the exact costume of a healthy system. Point the scheduler at the origin the deployment reports as appUrl on /api/health, and alert on the status code rather than on the request failing.
FullSend does not invent product capabilities. Marketing claims must be supported by repository evidence or explicit product information. Failed jobs remain visible with their error and retry state instead of being presented as successful.