TikTok channel factoryProvision multiple TikTok channels in one batch. Each channel gets its own stable alias and waits for one human Login Kit authorization.0/1 channels connected. TikTok review approval is still required before production publishing.
multi-channel readyTikTok Maintiktok-2ptpsjelx7r8gxxp17n6-bc5cfe20@auto-mmo.com · awaiting TikTok authorization
alias-readyAuthorize TikTok
ChannelsChoose the brand/theme identity whose social accounts you are managing.
4 channelsTikTok MainPrimary TikTok affiliate channel · 0 connected account records
ManageSmoke Test UIUI creation smoke test only; no live publishing. · 0 connected account records
ManageAuto MMO 2Facebook Page Auto MMO 2 · 1 connected account records
SelectedSmoke Test — Multi-channel V1Temporary routing verification; no live platform token. · 1 connected account records
ManageFacebook · Auto MMO 2account_facebook_1169175069621527 · 1169175069621527
connectedAdd a channelEach channel can own one Facebook Page, Instagram account, and TikTok account — or multiple accounts later.
collection: channelsAutomated email aliasesCatch-all now routes aliases to the Worker. Reusing the same channel, platform, and purpose keeps the address stable across retries.
registry readyFacebook connectUse the in-app OAuth flow so the dashboard stores Page credentials directly.
active page connectedCurrent active PageAuto MMO 2 (1169175069621527)
connectedOAuth sourceThe app will request Page scopes directly and save the selected Page into platform_accounts plus platform_secrets.
direct app loginConnect FacebookStarts the real Facebook login flow, lists manageable Pages, then lets you choose the active Page here.
Instagram publish pathInstagram now has a separate Instagram Login path, so it no longer depends on the broken Facebook Page mapping.
awaiting accountCurrent active accountNo Instagram professional account is saved yet.
not connectedLast verificationNo Instagram verification attempt has been recorded yet.
not verifiedFastest setup pathThe old Facebook Login path is blocked by Meta asset provisioning. Use Connect Instagram below; the manual form remains only as a legacy fallback.
use instagram loginConnect InstagramOpens Instagram Login, requests instagram_business_basic and instagram_business_content_publish, then saves the Instagram user token here.
TikTok publish pathTikTok now has an in-app config form so the platform account can be seeded without editing Firestore by hand.
awaiting tokenCurrent active accountNo TikTok creator account is saved yet.
not connectedLast verificationNo TikTok verification attempt has been recorded yet.
not verifiedMedia restrictionTikTok video and photo posts now use public media URLs through PULL_FROM_URL. The URL domain or prefix must be verified in TikTok Developer Portal.
importantOAuth sourceThe app can now start a real TikTok Login Kit redirect, exchange the code for access and refresh tokens, and save the creator account automatically.
direct app loginConnect TikTokStarts the real TikTok Login Kit flow, saves the returned access and refresh tokens, then immediately runs the creator-info verification check. The callback URL must live on HTTPS.
Instagram first live testUse this path after the token has already passed the save-and-verify check.
verify account first1. Keep the job simpleCreate one fresh post on /posts with only Instagram selected, one caption, and exactly one public media URL.
one media item2. Use the supported media shapeThe live adapter accepts either one image or one video. For the fastest first pass, use one image on the owned asset domain.
image fastest3. Trigger one publish attemptOpen the matching job on /jobs and run Publish now so the first adapter response is captured immediately.
manual first4. Record the resultCheck worker note, dispatch history, and externalRef on the job detail screen. The expected success path is a created container id followed by a published remote media id.
capture first responseTikTok first live testKeep the first direct-post attempt narrow so the result is easy to diagnose.
verify account first1. Start with one videoThe first smoke test uses TikTok direct PULL_FROM_URL with one managed video asset, so the media domain must be verified first.
video path preferred2. Start with one assetThe UI path on /posts currently creates the cleanest first test with exactly one video and only TikTok selected. Photo posts use the same verified-URL path.
one asset fastest3. Let the adapter choose a valid privacy levelKeep a default privacy saved here on /settings, but expect the live call to fall back to the creator-info options if needed.
privacy checked live4. Read back the publish idOpen the matching job detail after Publish now and record the first TikTok API message plus the returned async publish_id.
capture publish_idProduction scheduler readinessThis is the last local checklist before a Vercel cron run can own due-job publishing without the Mac cron fallback.
ready for first live runAPP_BASE_URLPresent. The Facebook callback can generate its deployed redirect origin.
setCRON_SECRETPresent. Vercel cron can authenticate directly against the same scheduler route.
setServer FirebaseReady. The deployed route can read platform secrets and write dispatch records.
live writes readyManaged media domainReady. Scheduled publishes can keep using owned public asset URLs instead of third-party source links.
owned-media readyActive Facebook PageAuto MMO 2 is connected and ready for the first production due-job test.
connectedFirst remote cron smoke testUse this exact sequence to prove the deployed Vercel scheduler can publish one due Facebook job without the local Mac cron fallback.
ready to execute1. Mirror the deployed envSet APP_BASE_URL, CRON_SECRET, FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY, and the full managed asset bucket env set in the Vercel production project.
mirrored locally too2. Create one fresh due Facebook jobUse a brand-new post with exactly one managed public media item, schedule it for now or slightly in the past, and leave the matching job in pending before triggering the sweep.
new jobs only3. Trigger the deployed route with the Vercel secret pathPrefer Bearer auth for this smoke test so the helper exercises the same CRON_SECRET contract used by Vercel Cron.
bearer auth4. Verify the first production outcomeExpect ok: true in the response, at least one processed job, a new dispatch record, and a real Facebook adapter success or failure message recorded on the job detail.
record resultRemote CLI smoke test
Run this from the repo root after the due Facebook job exists.
CRON_SECRET=your-vercel-cron-secret \ SCHEDULER_BASE_URL=https://auto-mmo-publisher.vercel.app \ npm run scheduler:run -- --auth bearer --limit 1
Raw curl fallback
Use this if you want to test the deployed route without the repo helper.
curl -X POST "https://auto-mmo-publisher.vercel.app/api/scheduler/run?limit=1" \ -H "Authorization: Bearer $CRON_SECRET"
Auth shell planRecommended first setup before you start using the app across devices
preparedProviderGoogle sign-in first, because it is the fastest personal setup
recommendedAccess controlAllowlist your main email first, then expand later if needed
nextSession modelFrontend signs in, backend keeps privileged writes on admin path
alignedFirestore collections stagedThese are the collections the app is already shaped around
ready to seedchannelsA brand, theme, or content identity that owns one or more platform accounts.
10 fieldspostsOne content item that can be published to multiple platforms at different times.
12 fieldsassetsCanonical media records that let the publish pipeline track one public asset across posts, retries, and future bucket imports.
9 fieldsplatform_accountsPer-platform connection records so tokens and readiness live outside the content model.
13 fieldsplatform_secretsOptional per-platform secret documents referenced by platform_accounts.tokenRef.
7 fieldspublish_jobsPlatform-specific execution units that the Cloud Run worker will claim and process.
9 fieldspublish_job_dispatchesQueued handoff records created by manual dashboard triggers before a worker claims the job.
7 fieldsplatform_connect_sessionsShort-lived server-side OAuth sessions used while a user logs in and chooses which Facebook Page to activate.
6 fieldsemail_aliasesStable catch-all email aliases allocated per channel, platform, account, and workflow purpose.
8 fieldsinbound_emailsIdempotent, normalized verification emails received from the Cloudflare Email Worker.
12 fieldsEnvironment placeholdersThese are the first values to prepare for the next build slice
file: .env.exampleNEXT_PUBLIC_FIREBASE_API_KEYPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
NEXT_PUBLIC_FIREBASE_AUTH_DOMAINPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
NEXT_PUBLIC_FIREBASE_PROJECT_IDPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
NEXT_PUBLIC_FIREBASE_APP_IDPlaceholder added in the repo for later wiring.
Layerfrontend
Sensitivityconfig
Statuspresent
FIREBASE_PROJECT_IDPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
FIREBASE_CLIENT_EMAILPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
FIREBASE_PRIVATE_KEYPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
FACEBOOK_APP_IDPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
FACEBOOK_APP_SECRETPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
TIKTOK_CLIENT_KEYPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
TIKTOK_CLIENT_SECRETPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
TIKTOK_OAUTH_SCOPESPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
INSTAGRAM_APP_IDPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
INSTAGRAM_APP_SECRETPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
INSTAGRAM_OAUTH_SCOPESPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
PUBLISH_RUNNER_SECRETPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
APP_BASE_URLPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
CRON_SECRETPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
R2_ACCOUNT_IDPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
R2_ACCESS_KEY_IDPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
R2_SECRET_ACCESS_KEYPlaceholder added in the repo for later wiring.
Layerserver
Sensitivitysecret
Statuspresent
R2_BUCKET_NAMEPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
R2_PUBLIC_BASE_URLPlaceholder added in the repo for later wiring.
Layerserver
Sensitivityconfig
Statuspresent
Scheduled runner hookUse this endpoint from cron, Cloud Scheduler, or another secure trigger
ready to wireGET /api/scheduler/run?limit=10Also accepts POST. The route scans due jobs, creates dispatches, and reuses the live worker path.
internal routeScheduler authUse x-publish-runner-secret with PUBLISH_RUNNER_SECRET, or send a Bearer token with either PUBLISH_RUNNER_SECRET or CRON_SECRET.
requiredLegacy jobsAuto-run is reliable for new posts because the composer now stores ISO time plus timezone metadata.
new posts firstRuns one server-side due-job sweep immediately without exposing the runner secret to the browser.