Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LMendoza70/SSA/llms.txt

Use this file to discover all available pages before exploring further.

The Social Media module bridges the gap between the institutional CMS and the channels the population actually uses. Rather than requiring staff to manually copy-paste content into each social platform, the module lets editors publish or schedule a post to multiple networks in a single action — ensuring authoritative health information reaches people on Facebook, Instagram, X, TikTok, and YouTube without duplication of effort or risk of transcription errors. The adapter architecture means adding a new platform in the future never touches existing publishing logic.

Architecture: Adapter Pattern

All social platforms are accessed through a shared SocialPublisher interface. The CMS and scheduling layers interact exclusively with this interface; they have no knowledge of any specific platform’s API.
interface SocialPublisher {
  publish(content: SocialPost): Promise<SocialPublishResult>;
  schedule(content: SocialPost, publishAt: Date): Promise<SocialScheduleResult>;
  republish(postId: string): Promise<SocialPublishResult>;
  getStatus(postId: string): Promise<SocialPostStatus>;
}
Each supported platform has a concrete adapter injected by NestJS’s dependency injection container:
  • FacebookAdapter
  • InstagramAdapter
  • XAdapter (formerly Twitter)
  • TikTokAdapter
  • YouTubeAdapter
Adding a new social platform never requires changes to the CMS module or scheduling logic. Each adapter is an isolated @Injectable() class. This is Clean Architecture’s Open/Closed Principle in action — the system is open for extension but closed for modification.

How the Adapter Is Selected

At runtime the SocialService resolves the correct adapter for each platform in the platforms array of a SocialPost. This lookup is performed through a SocialAdapterRegistry — a map keyed by Platform enum value — so adding a new adapter is a matter of registering it in one place.
// src/social/social-adapter.registry.ts
@Injectable()
export class SocialAdapterRegistry {
  private readonly adapters: Map<Platform, SocialPublisher>;

  constructor(
    private readonly facebookAdapter: FacebookAdapter,
    private readonly instagramAdapter: InstagramAdapter,
    private readonly xAdapter: XAdapter,
    private readonly tiktokAdapter: TikTokAdapter,
    private readonly youtubeAdapter: YouTubeAdapter,
  ) {
    this.adapters = new Map([
      [Platform.FACEBOOK, this.facebookAdapter],
      [Platform.INSTAGRAM, this.instagramAdapter],
      [Platform.X, this.xAdapter],
      [Platform.TIKTOK, this.tiktokAdapter],
      [Platform.YOUTUBE, this.youtubeAdapter],
    ]);
  }

  resolve(platform: Platform): SocialPublisher {
    const adapter = this.adapters.get(platform);
    if (!adapter) throw new Error(`No adapter registered for platform: ${platform}`);
    return adapter;
  }
}

SocialPost Shape

A SocialPost carries everything an adapter needs to produce a platform-specific publication. Media assets are resolved from the Multimedia Module before the post object is constructed.
interface SocialPost {
  contentId: string;      // CMS content UUID
  text: string;           // Post caption (may be truncated per-platform by the adapter)
  mediaUrls: string[];    // Resolved asset URLs from the Multimedia Module
  platforms: Platform[];  // Target platforms for this publication
  publishAt?: Date;       // If set, the post is scheduled rather than immediate
}

Supported Platforms

PlatformAdapterSupported TypesCharacter Limit
FacebookFacebookAdapterText, Image, Video63,206 chars
InstagramInstagramAdapterImage, Video (carousel)2,200 chars
X (Twitter)XAdapterText, Image280 chars
TikTokTikTokAdapterVideo2,200 chars
YouTubeYouTubeAdapterVideo
Each adapter is responsible for enforcing its platform’s character limit. If the text field exceeds the platform maximum, the adapter truncates it and appends an ellipsis before calling the platform API. The original text is preserved in the database record.

API Reference

All endpoints require authentication. Scheduling and republishing are privileged operations restricted to users with the social:write permission scope.
POST /social/publish
POST /social/schedule
POST /social/republish/:postId
GET  /social/posts
GET  /social/posts/:postId/status

Publish Immediately

POST /social/publish
Content-Type: application/json
Authorization: Bearer <token>
{
  "contentId": "uuid-of-cms-content",
  "text": "Nueva campaña de vacunación disponible en todos los centros de salud de la Jurisdicción. Infórmate aquí.",
  "mediaUrls": ["https://storage.example.com/uploads/campana-vacunacion.jpg"],
  "platforms": ["facebook", "instagram"]
}
A successful response returns 201 Created with per-platform publish results:
{
  "results": [
    {
      "platform": "facebook",
      "status": "published",
      "externalPostId": "fb_1234567890",
      "publishedAt": "2025-06-15T14:30:00.000Z"
    },
    {
      "platform": "instagram",
      "status": "published",
      "externalPostId": "ig_0987654321",
      "publishedAt": "2025-06-15T14:30:02.000Z"
    }
  ]
}

Schedule a Post

POST /social/schedule
Content-Type: application/json
Authorization: Bearer <token>
{
  "contentId": "uuid-of-cms-content",
  "text": "Recuerda: esta semana inicia la campaña de desparasitación. ¡No faltes!",
  "mediaUrls": [],
  "platforms": ["facebook", "x"],
  "publishAt": "2025-06-20T09:00:00.000Z"
}
Returns 201 Created with a scheduledPostId that can be used to cancel or check status.

Republish a Post

POST /social/republish/:postId
Authorization: Bearer <token>
Republishes a previously published or failed post using the same content and platforms as the original. Useful for retrying after a platform API outage.

List Posts

GET /social/posts?platform=facebook&status=published&page=1&limit=20
Authorization: Bearer <token>
ParameterTypeDescription
platformstringFilter by platform slug (e.g. facebook, instagram)
statusstringpublished, scheduled, failed, or pending
pagenumberPage number (default 1)
limitnumberResults per page (default 20)

Check Post Status

GET /social/posts/:postId/status
Authorization: Bearer <token>
Returns the current status of a post as reported by the platform adapter. If the post was scheduled, this endpoint reflects whether it has been published or is still pending.

Environment Configuration

Platform credentials are read from environment variables at startup. No credentials are ever stored in the database or committed to source control.
# Facebook
FACEBOOK_PAGE_ID=...
FACEBOOK_ACCESS_TOKEN=...

# Instagram
INSTAGRAM_ACCOUNT_ID=...
INSTAGRAM_ACCESS_TOKEN=...

# X (Twitter)
X_API_KEY=...
X_API_SECRET=...
X_ACCESS_TOKEN=...
X_ACCESS_SECRET=...

# TikTok
TIKTOK_ACCESS_TOKEN=...

# YouTube
YOUTUBE_CLIENT_ID=...
YOUTUBE_CLIENT_SECRET=...
YOUTUBE_REFRESH_TOKEN=...
Access tokens for Facebook and Instagram expire periodically. Implement a token-refresh job or use a long-lived page token where the platform allows it. Expired tokens will cause publish operations to fail silently if not monitored.

Adding a New Platform

Extending the Social module to support a new platform requires only three steps — no changes to existing adapters, services, or the CMS module.
1

Implement the SocialPublisher interface

Create a new file under src/social/adapters/ and implement all four methods.
// src/social/adapters/new-platform.adapter.ts
@Injectable()
export class NewPlatformAdapter implements SocialPublisher {
  async publish(content: SocialPost): Promise<SocialPublishResult> {
    // Platform-specific API call
  }

  async schedule(content: SocialPost, publishAt: Date): Promise<SocialScheduleResult> {
    // Platform-specific scheduling
  }

  async republish(postId: string): Promise<SocialPublishResult> {
    // Fetch original post and re-publish
  }

  async getStatus(postId: string): Promise<SocialPostStatus> {
    // Query platform API for post status
  }
}
2

Register the adapter in SocialAdapterRegistry

Add the new platform to the Platform enum and register the adapter in SocialAdapterRegistry.
// Add to Platform enum
export enum Platform {
  FACEBOOK = 'facebook',
  INSTAGRAM = 'instagram',
  X = 'x',
  TIKTOK = 'tiktok',
  YOUTUBE = 'youtube',
  NEW_PLATFORM = 'new-platform', // ← new entry
}
3

Add environment variables

Document the required credentials in .env.example and your deployment environment. The adapter should read all secrets from ConfigService — never from process.env directly.

CMS Overview

Content published to social media originates from CMS entities.

Multimedia

Media assets referenced in posts are managed by the Multimedia Module.

Content Types

Learn which content types are suitable for social distribution.

Build docs developers (and LLMs) love