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
| Entity | What it represents |
|---|---|
| Social post | One published or scheduled post. Has title, body, media URLs, target platforms[], status (draft/scheduled/published/failed), publish_date, external_id (Ayrshare id). |
| Social provider profile | A connected platform account — provider='ayrshare', platform='twitter'/'linkedin'/..., status (active/disconnected). |
| Social engagement | Snapshot of likes / comments / shares / impressions for one post at one point in time. |
| Social comment | A comment captured from a platform via webhook or hourly poll. |
| Social campaign | Optional grouping for analytics roll-ups. |
Schema under social with public.* shims.
Publish flow
Two paths:
| Mode | What happens |
|---|---|
| Immediate | Post fires publishPost() synchronously; status flips to published; emits social.post.published with platform URLs in the payload. |
| Scheduled | Post 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:
- Calls
syncAllAnalytics(supabase, tenantId)— refreshessocial_engagementrows for every published post. - 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
- Ayrshare integration — OAuth + webhook setup.
- Content module — the broader publish-anywhere surface that overlaps with Social.