Social publishing
Social publishing connects a project to its own Facebook Page, Instagram Business account, and LinkedIn Company Page, then auto-publishes scheduled content items at the right time — with per-platform status, post URLs, and clear error reporting.
Setup is one-time per project. After that, scheduling and publishing is a 30-second flow from the content planner.
Step-by-step
- 1Check your plan
Social publishing is gated by `Plan.allowSocialPublishing`. If your account isn't on a qualifying plan, you'll see an upgrade prompt on the Project Social tab and the schedule modal.
- 2Connect a social account
Open the project → Social tab. For each platform, click Connect and complete the OAuth popup. The card flips to Active with the account name and avatar once connected. Reconnect anytime to swap accounts.
- 3Pick a content item to publish
Open the content planner → board view. Find the item, click the Schedule icon (calendar-clock) on its card. Items without a project don't get the Schedule icon — assign a project first.
- 4Configure the schedule
Pick a date and time in the future. Tick the accounts you want to post to. For each account, choose Publish (post automatically) or Save as draft (FB creates an unpublished post; IG/LinkedIn mark ready for manual posting since they have no drafts API).
- 5Override per platform (optional)
Expand 'Override caption / media' under any account to give it a different message or media list — useful when LinkedIn needs a more formal version than Instagram.
- 6Watch it publish
Within a minute of the scheduled time, the cron picks up the row, calls the provider, and updates the colored status dot on the card: 🟢 published, 🟣 drafted, 🔴 failed. Click the History icon to see per-attempt details, retry failures, or cancel scheduled posts.
- 7Reconnect if tokens expire
Every 6 hours a token-health check runs on Instagram and LinkedIn connections. If a token's been revoked, the card flips to Expired and shows a Reconnect CTA. Facebook page tokens never expire.
Tips
Failed posts don't auto-retry — open the History modal and click Retry once you've fixed the cause (e.g., reconnected, edited the media). Instagram videos can take more than 30 seconds to finish encoding — the system defers them to the next cron tick rather than failing. The same brand on two different projects must OAuth twice — connections are scoped per-project for safety. See [`docs/social-publishing.md`](https://github.com/) and the integration to-do for deployment-side setup (env vars, provider apps, cron worker).
Admin configuration
Plan → `allowSocialPublishing` defaults to false on every plan. Enable it per plan in `/admin/plans` for tiers that should have access. Env vars (deploy-time): `SOCIAL_TOKEN_KEY`, `META_APP_ID`/`SECRET`, `LINKEDIN_CLIENT_ID`/`SECRET`, `SOCIAL_OAUTH_REDIRECT_BASE`, `CRON_SECRET`. Provider apps (deploy-time): a verified Meta app with Pages + Instagram Graph products, and a LinkedIn app with Marketing Developer Platform access. `wms-be` cron worker runs the publishing engine every minute and the token-health check every 6 hours.