Social module

The Social module manages multi-platform social posting, scheduling, and engagement tracking. Backed by Ayrshare as the publish provider; engagement metrics + comments sync hourly so the dashboard reflects platform truth without manual refresh.

Entities

EntityWhat it represents
Social postOne published or scheduled post. Has title, body, media URLs, target platforms[], status (draft/scheduled/published/failed), publish_date, external_id (Ayrshare id).
Social provider profileA connected platform account — provider='ayrshare', platform='twitter'/'linkedin'/..., status (active/disconnected).
Social engagementSnapshot of likes / comments / shares / impressions for one post at one point in time.
Social commentA comment captured from a platform via webhook or hourly poll.
Social campaignOptional grouping for analytics roll-ups.

Schema under social with public.* shims.

Publish flow

Two paths:

ModeWhat happens
ImmediatePost fires publishPost() synchronously; status flips to published; emits social.post.published with platform URLs in the payload.
ScheduledPost status set to scheduled + scheduled_at; emits social.post.scheduled. Ayrshare runs the publish at the scheduled time; their webhook callback marks the post published when delivery confirms.

Webhook dedup: when Ayrshare confirms an immediate publish that already emitted, the webhook handler gates on the prior status being scheduled to avoid double-firing the published event.

Engagement sync

Hourly cron social-analytics-sync walks tenants with an active Ayrshare profile and:

  1. Calls syncAllAnalytics(supabase, tenantId) — refreshes social_engagement rows for every published post.
  2. Calls syncAllComments(supabase, tenantId) — pulls new comments since the last sync.

Per-tenant errors are collected and returned in the response so a single failing tenant doesn't poison the whole cron run.

Composer

The compose surface supports:

  • Per-platform message variants (Twitter 280-char vs LinkedIn long-form vs Instagram caption).
  • Media upload to the tenant-scoped storage bucket with thumbnail generation in the worker.
  • Schedule picker; UTC-anchored so cross-team scheduling stays predictable.

Cross-module insights

  • Social × Content: a Content item published via Content's publishing-integration layer can land as a Social post if the platform is marked social. Lifecycle event dedup at the bus prevents double-emission.
  • Social × Analytics: scheduled "engagement by post / campaign" exports through the analytics-reports system.
  • Social × CRM: comments are projected into contact activities when the commenter's social handle matches a known contact (handle → email mapping required).

Permissions

social.posts.read|create|update|delete + social.providers.connect (gated to admin/owner because connecting an Ayrshare profile costs API quota).

Read next