Files
igny8/v2/V2-Execution-Docs/02H-socializer.md
IGNY8 VPS (Salman) 0570052fec 1
2026-03-23 17:20:51 +00:00

29 KiB
Raw Blame History

IGNY8 Phase 2: Socializer (02H)

Native Social Media Posting & Engagement Engine — Stage 8

Document Version: 1.0 Date: 2026-03-23 Phase: IGNY8 Phase 2 — Feature Expansion Status: Build Ready Source of Truth: Codebase at /data/app/igny8/ Audience: Claude Code, Backend Developers, Architects


1. CURRENT STATE

Social Media Today

There is no social media functionality in IGNY8. No OAuth connections to any social platform exist. No social post generation, scheduling, or analytics. The automation pipeline ends at Stage 7 (publish to WordPress).

What Exists

  • 7-stage automation pipeline (01E) terminates at publish — no post-publish social distribution
  • SiteIntegration model (integration app) — handles WordPress OAuth; pattern reusable for social OAuth
  • Content model — stores the content that feeds social post generation
  • Images model (writer app) — stores generated images that can be resized for social platforms
  • AutomationConfig model (automation app) — per-site automation settings; extendable for social toggles
  • Celery infrastructure with beat scheduler — ready for social scheduling tasks

What Does Not Exist

  • No social app or models
  • No OAuth connections for LinkedIn, Twitter/X, Facebook, Instagram, TikTok
  • No AI social post generation or platform adaptation
  • No scheduling/calendar system
  • No engagement tracking
  • No Stage 8 pipeline integration

2. WHAT TO BUILD

Overview

Build Stage 8 of the automation pipeline: a social media engine that connects to 5 platforms via OAuth, generates AI-adapted posts from published content, schedules posts with best-time optimization, and tracks engagement metrics.

2.1 Platform Support

Platform Max Length Key Format OAuth Flow API
LinkedIn 1,300 chars Professional, industry insights OAuth 2.0 (3-legged) Marketing API v2
Twitter/X 280 chars (thread option) Concise, hashtags, hooks OAuth 2.0 (PKCE) API v2
Facebook ~63,206 chars (500 optimal) Conversational, visual OAuth 2.0 (Facebook Login) Graph API v18+
Instagram 2,200 chars, 30 hashtags Visual-first, hashtag-heavy Via Facebook Business Graph API (IG)
TikTok varies Gen-Z tone, trending hooks OAuth 2.0 Content Posting API

2.2 OAuth Infrastructure

Reusable OAuth service structure:

Location: igny8_core/integration/oauth/

  • base_oauth.py — base class with token encrypt/decrypt, refresh logic
  • linkedin_oauth.py — LinkedIn 3-legged OAuth, scopes: w_member_social, r_organization_social, w_organization_social
  • twitter_oauth.py — Twitter OAuth 2.0 with PKCE
  • facebook_oauth.py — Facebook Login, page selection, scopes: pages_manage_posts, pages_read_engagement
  • instagram_oauth.py — via Facebook Business, Instagram Basic Display API
  • tiktok_oauth.py — TikTok OAuth 2.0

Token Security:

  • Access tokens and refresh tokens encrypted using the same encryption pattern as GSC tokens (02C)
  • Tokens stored in SocialAccount.access_token and SocialAccount.refresh_token (encrypted TextField)
  • Auto-refresh via Celery task (refresh_social_tokens) runs hourly

Platform-Specific Auth Notes:

  • Facebook: Requires App Review for pages_manage_posts permission. Flow: Login → Page Selection → Permission Grant → Store page_access_token. Webhook subscription for engagement updates.
  • LinkedIn: Requires Marketing API Partner Program access. Flow: Authorization → Organization Selection → Store access_token.
  • Instagram: No direct OAuth — connected via Facebook Business account. Requires Facebook Page linked to Instagram Professional account.
  • Multi-account support: Multiple SocialAccount records per platform per site.

2.3 AI Content Adaptation

Input: Content record (title, content_html, meta_description, cluster keywords from SAGCluster)

Per platform, AI generates:

  • Adapted text matching platform tone + length limits
  • Hashtag set (topic-aware, platform-appropriate count)
  • CTA appropriate to platform conventions
  • Image sizing recommendations

Platform-Specific Generation:

  • LinkedIn: Professional tone, industry framing, 3-5 hashtags, link in text
  • Twitter/X: Hook + key point + CTA in 280 chars. Thread generation option (2-10 tweets) for long content
  • Facebook: Conversational, 2-3 paragraphs, 3-5 hashtags, link at end
  • Instagram: Visual-first caption, 20-30 hashtags in first comment or caption, no clickable link (use "link in bio" CTA)
  • TikTok: Gen-Z/casual tone, trending hook format, 3-5 hashtags

2.4 Post Types

# Post Type Description Platforms
1 Announcement Link post with title + excerpt + URL All
2 Highlights Key takeaways from article + CTA All
3 Quote Card Branded insight/statistic as image post All
4 FAQ Snippet Single FAQ from content as post LinkedIn, Twitter, Facebook
5 Carousel Multi-image posts (future) Instagram, LinkedIn

2.5 Image Sizing per Platform

Platform Dimension Aspect Ratio
LinkedIn 1200×627px ~1.91:1
Twitter 1600×900px ~16:9
Facebook 1200×630px ~1.91:1
Instagram (square) 1080×1080px 1:1
Instagram (portrait) 1080×1350px 4:5
TikTok 1080×1920px 9:16

Image resizing uses the Images model records generated by pipeline Stages 5-6, resized to platform specs using Pillow.

2.6 Scheduling & Calendar

Best-Time Algorithm:

  • Configurable default best-time slots per platform
  • Per-account override via SocialAccount.settings.best_times[]
  • If engagement data available, learn optimal posting times from past performance

Queue System:

  • Posts with status='scheduled' and scheduled_at in the past → Celery task publishes
  • Celery task publish_scheduled_posts runs every minute
  • Frequency caps: max posts per day per platform (configurable, default: 2)
  • Cooldown: 4-6 hours between posts to same platform (configurable via SocialAccount.settings.cooldown_hours)

Calendar View:

  • API endpoint returns week/month layout of scheduled + published posts
  • Frontend renders visual calendar with drag-drop rescheduling (.tsx component)

Bulk Scheduling:

  • Select multiple content → generate social posts for all connected platforms
  • Auto-space across optimal times over days/weeks
  • Review before confirming schedule

2.7 Engagement Tracking

  • Celery task fetch_engagement runs every 6 hours
  • Fetches metrics from each platform API for recent posts (last 30 days)
  • Metrics: likes, comments, shares/retweets, impressions, clicks, engagement_rate
  • Aggregate dashboard: per-platform performance, best performing posts, optimal posting times
  • Attribution: UTM parameters appended to all shared URLs (utm_source={platform}&utm_medium=social&utm_campaign=igny8)

2.8 Stage 8 Pipeline Integration

After Stage 7 (publish to WordPress), if social accounts are connected for the site:

  1. Pipeline triggers Stage 8
  2. Load all connected SocialAccount records for the site
  3. For each connected account, AI generates platform-adapted post
  4. If AutomationConfig.auto_social_publish enabled: posts queue immediately at next best-time slot
  5. If manual review enabled: posts go to status='draft' for user review
  6. Published posts logged with platform_post_id for engagement tracking

AutomationConfig Extension:

# Add to AutomationConfig.settings JSONField:
{
    "social_enabled": True,           # Master toggle
    "auto_social_publish": False,     # Auto-queue or manual review
    "social_platforms": ["linkedin", "twitter"],  # Which platforms to auto-post
    "social_post_types": ["announcement", "highlights"],  # Which post types
}

3. DATA MODELS & APIS

3.1 New Models

All models in a new social app.

SocialAccount (social app)

class SocialAccount(SiteSectorBaseModel):
    """
    Connected social media account for a site.
    Stores OAuth tokens (encrypted) and per-account settings.
    Multi-account support: multiple accounts per platform per site.
    """
    platform = models.CharField(
        max_length=15,
        choices=[
            ('linkedin', 'LinkedIn'),
            ('twitter', 'Twitter/X'),
            ('facebook', 'Facebook'),
            ('instagram', 'Instagram'),
            ('tiktok', 'TikTok'),
        ]
    )
    platform_account_id = models.CharField(
        max_length=255,
        help_text='External platform account/page ID'
    )
    account_name = models.CharField(max_length=255, help_text='Display name')
    account_type = models.CharField(
        max_length=20,
        choices=[
            ('personal', 'Personal'),
            ('page', 'Page'),
            ('organization', 'Organization'),
        ],
        default='personal'
    )
    access_token = models.TextField(
        help_text='Encrypted OAuth access token'
    )
    refresh_token = models.TextField(
        blank=True,
        default='',
        help_text='Encrypted OAuth refresh token (nullable for platforms without refresh)'
    )
    token_expiry = models.DateTimeField(null=True, blank=True)
    permissions = models.JSONField(
        default=list,
        help_text='Granted OAuth scopes'
    )
    status = models.CharField(
        max_length=10,
        choices=[
            ('active', 'Active'),
            ('expired', 'Expired'),
            ('revoked', 'Revoked'),
            ('error', 'Error'),
        ],
        default='active'
    )
    settings = models.JSONField(
        default=dict,
        help_text='{auto_publish, max_per_day, best_times[], cooldown_hours}'
    )

    class Meta:
        app_label = 'social'
        db_table = 'igny8_social_accounts'

PK: BigAutoField (integer) — inherits from SiteSectorBaseModel

SocialPost (social app)

class SocialPost(SiteSectorBaseModel):
    """
    A social media post — generated from content or standalone.
    Tracks full lifecycle from draft to published with engagement.
    """
    content = models.ForeignKey(
        'writer.Content',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='social_posts',
        help_text='Source content (null for standalone posts)'
    )
    social_account = models.ForeignKey(
        'social.SocialAccount',
        on_delete=models.CASCADE,
        related_name='posts'
    )
    platform = models.CharField(
        max_length=15,
        help_text='Denormalized from social_account for filtering'
    )
    post_type = models.CharField(
        max_length=15,
        choices=[
            ('announcement', 'Announcement'),
            ('highlights', 'Highlights'),
            ('quote_card', 'Quote Card'),
            ('faq_snippet', 'FAQ Snippet'),
            ('carousel', 'Carousel'),
        ]
    )
    text = models.TextField()
    hashtags = models.JSONField(default=list, help_text='List of hashtag strings')
    media_urls = models.JSONField(default=list, help_text='List of image/video URLs')
    link_url = models.URLField(blank=True, default='')
    utm_params = models.JSONField(
        default=dict,
        blank=True,
        help_text='{utm_source, utm_medium, utm_campaign}'
    )
    thread_posts = models.JSONField(
        null=True,
        blank=True,
        help_text='For Twitter threads: [{text, media_url}]'
    )
    scheduled_at = models.DateTimeField(null=True, blank=True)
    published_at = models.DateTimeField(null=True, blank=True)
    platform_post_id = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text='External post ID after publishing'
    )
    platform_post_url = models.URLField(blank=True, default='')
    status = models.CharField(
        max_length=15,
        choices=[
            ('draft', 'Draft'),
            ('scheduled', 'Scheduled'),
            ('publishing', 'Publishing'),
            ('published', 'Published'),
            ('failed', 'Failed'),
            ('cancelled', 'Cancelled'),
        ],
        default='draft'
    )
    error_message = models.TextField(blank=True, default='')

    class Meta:
        app_label = 'social'
        db_table = 'igny8_social_posts'

PK: BigAutoField (integer) — inherits from SiteSectorBaseModel

SocialEngagement (social app)

class SocialEngagement(models.Model):
    """
    Engagement metrics for a published social post.
    Fetched periodically from platform APIs.
    """
    social_post = models.ForeignKey(
        'social.SocialPost',
        on_delete=models.CASCADE,
        related_name='engagement_records'
    )
    likes = models.IntegerField(default=0)
    comments = models.IntegerField(default=0)
    shares = models.IntegerField(default=0)
    impressions = models.IntegerField(default=0)
    clicks = models.IntegerField(default=0)
    engagement_rate = models.FloatField(default=0.0)
    raw_data = models.JSONField(default=dict, help_text='Full platform API response')
    fetched_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        app_label = 'social'
        db_table = 'igny8_social_engagement'

PK: BigAutoField (integer) — standard Django Model (not AccountBaseModel since engagement is tied to post)

3.2 New App Registration

Create social app:

  • App config: igny8_core/modules/social/apps.py with app_label = 'social'
  • Add to INSTALLED_APPS in igny8_core/settings.py

3.3 Migration

igny8_core/migrations/XXXX_add_social_models.py

Operations:

  1. CreateModel('SocialAccount', ...) — with index on platform, status
  2. CreateModel('SocialPost', ...) — with indexes on social_account, platform, status, scheduled_at
  3. CreateModel('SocialEngagement', ...) — with index on social_post

3.4 API Endpoints

All endpoints under /api/v1/social/:

Account Management

Method Path Description
POST /api/v1/social/accounts/connect/{platform}/ Initiate OAuth flow for platform. Returns redirect URL.
GET /api/v1/social/accounts/callback/{platform}/ OAuth callback handler. Exchanges code for tokens, creates SocialAccount.
GET /api/v1/social/accounts/?site_id=X List connected accounts for site.
DELETE /api/v1/social/accounts/{id}/ Disconnect account (revoke tokens, soft-delete).
PUT /api/v1/social/accounts/{id}/settings/ Update account settings (max_per_day, best_times, cooldown).

Post Management

Method Path Description
POST /api/v1/social/posts/generate/ AI-generate posts for content across all connected platforms. Body: {content_id, post_types: []}.
POST /api/v1/social/posts/ Create manual post. Body: {social_account_id, text, ...}.
GET /api/v1/social/posts/?site_id=X List posts with filters (platform, status, date range).
PUT /api/v1/social/posts/{id}/ Edit draft/scheduled post.
POST /api/v1/social/posts/{id}/publish/ Publish immediately.
POST /api/v1/social/posts/{id}/schedule/ Schedule for later. Body: {scheduled_at}.
DELETE /api/v1/social/posts/{id}/ Cancel/delete post.
POST /api/v1/social/posts/bulk-generate/ Generate for multiple content. Body: {content_ids: [int]}.
POST /api/v1/social/posts/bulk-schedule/ Schedule multiple posts. Body: {post_ids: [int], auto_space: true}.

Calendar & Analytics

Method Path Description
GET /api/v1/social/calendar/?site_id=X&month=YYYY-MM Calendar view — scheduled + published posts for month.
GET /api/v1/social/analytics/?site_id=X Aggregate analytics: per-platform performance, top posts.
GET /api/v1/social/analytics/posts/?site_id=X Per-post analytics with engagement breakdown.

Permissions: All endpoints use SiteSectorModelViewSet permission patterns.

3.5 AI Function — GenerateSocialPostsFunction

Registry key: generate_social_posts Location: igny8_core/ai/functions/generate_social_posts.py

class GenerateSocialPostsFunction(BaseAIFunction):
    """
    Generates platform-adapted social media posts from content.
    One call produces posts for all requested platforms.
    """
    function_name = 'generate_social_posts'

    def validate(self, content_id, platforms=None, post_types=None, **kwargs):
        # Verify content exists, has content_html
        # Verify requested platforms have connected accounts
        pass

    def prepare(self, content_id, platforms=None, post_types=None, **kwargs):
        # Load Content record
        # Load cluster keywords for hashtag generation
        # Load connected SocialAccount records for the site
        # Determine applicable post_types per platform
        pass

    def build_prompt(self):
        # Per platform, build adaptation instructions:
        # - Platform tone + length limits
        # - Content title, meta_description, key points from content_html
        # - Hashtag generation instructions
        # - CTA format
        # - Thread instructions (Twitter if content > 280 chars summary)
        pass

    def parse_response(self, response):
        # Parse per-platform posts:
        # {platform: {text, hashtags[], cta, thread_posts?}}
        pass

    def save_output(self, parsed):
        # Create SocialPost records per platform per post_type
        # Attach UTM parameters
        # Set status='draft' (default) or 'scheduled' if auto-publish
        pass

3.6 OAuth Service

Location: igny8_core/integration/oauth/

# base_oauth.py
class BaseOAuthService:
    """Base class for OAuth integrations. Handles token encryption/decryption."""

    def encrypt_token(self, token):
        """Encrypt token using Django's Fernet key (same pattern as 02C GSC tokens)."""
        pass

    def decrypt_token(self, encrypted_token):
        """Decrypt stored token."""
        pass

    def get_authorization_url(self, site_id, account_id=None):
        """Generate OAuth authorization URL with state parameter."""
        pass

    def handle_callback(self, code, state):
        """Exchange authorization code for tokens, create/update SocialAccount."""
        pass

    def refresh_tokens(self, social_account):
        """Refresh expired access token using refresh_token."""
        pass

# linkedin_oauth.py
class LinkedInOAuthService(BaseOAuthService):
    """LinkedIn Marketing API OAuth 2.0 (3-legged)."""
    SCOPES = ['w_member_social', 'r_organization_social', 'w_organization_social']
    # ...

# twitter_oauth.py
class TwitterOAuthService(BaseOAuthService):
    """Twitter/X OAuth 2.0 with PKCE."""
    SCOPES = ['tweet.read', 'tweet.write', 'users.read']
    # ...

# facebook_oauth.py
class FacebookOAuthService(BaseOAuthService):
    """Facebook Login with page selection."""
    SCOPES = ['pages_manage_posts', 'pages_read_engagement']
    # ...

# tiktok_oauth.py
class TikTokOAuthService(BaseOAuthService):
    """TikTok Content Posting API OAuth."""
    # ...

3.7 Social Publisher Service

Location: igny8_core/business/social_publisher.py

class SocialPublisherService:
    """
    Handles actual posting to platform APIs.
    Routes to platform-specific publishers.
    """

    PUBLISHERS = {
        'linkedin': LinkedInPublisher,
        'twitter': TwitterPublisher,
        'facebook': FacebookPublisher,
        'instagram': InstagramPublisher,
        'tiktok': TikTokPublisher,
    }

    def publish(self, social_post_id):
        """
        Publish a SocialPost to its target platform.
        1. Load SocialPost + SocialAccount
        2. Decrypt access token
        3. Route to platform-specific publisher
        4. Update SocialPost with platform_post_id, platform_post_url, published_at
        5. Set status='published' or 'failed'
        """
        pass

3.8 Celery Tasks

Location: igny8_core/tasks/social_tasks.py

@shared_task(name='publish_scheduled_posts')
def publish_scheduled_posts():
    """
    Runs every minute. Finds SocialPost records with
    status='scheduled' and scheduled_at <= now(). Publishes each.
    """
    pass

@shared_task(name='refresh_social_tokens')
def refresh_social_tokens():
    """
    Runs hourly. Refreshes tokens expiring within next 2 hours.
    Updates SocialAccount.access_token, token_expiry.
    Sets status='expired' if refresh fails.
    """
    pass

@shared_task(name='fetch_engagement')
def fetch_engagement():
    """
    Runs every 6 hours. Fetches engagement metrics from platform APIs
    for all published posts in last 30 days.
    Creates SocialEngagement records.
    """
    pass

@shared_task(name='generate_social_posts_stage8')
def generate_social_posts_stage8(content_id):
    """
    Triggered by pipeline after Stage 7 (publish).
    Generates social posts for all connected platforms for the site.
    """
    pass

Beat Schedule Additions:

Task Schedule Notes
publish_scheduled_posts Every minute Publishes due scheduled posts
refresh_social_tokens Hourly Refreshes expiring OAuth tokens
fetch_engagement Every 6 hours Fetches engagement metrics for recent posts

3.9 Image Resizing Service

Location: igny8_core/business/social_image_resize.py

class SocialImageResizeService:
    """
    Resizes images from the Images model to platform-specific dimensions.
    Uses Pillow for image processing.
    """

    PLATFORM_SIZES = {
        'linkedin': (1200, 627),
        'twitter': (1600, 900),
        'facebook': (1200, 630),
        'instagram_square': (1080, 1080),
        'instagram_portrait': (1080, 1350),
        'tiktok': (1080, 1920),
    }

    def resize(self, image_path, platform, variant='default'):
        """Resize image, return new file path."""
        pass

4. IMPLEMENTATION STEPS

Step 1: Create Social App

  1. Create igny8_core/modules/social/ directory with __init__.py and apps.py
  2. Add social to INSTALLED_APPS in settings.py
  3. Create models: SocialAccount, SocialPost, SocialEngagement

Step 2: Migration

  1. Create migration for 3 new models
  2. Run migration

Step 3: OAuth Infrastructure

  1. Create igny8_core/integration/oauth/ directory
  2. Implement BaseOAuthService with token encryption/decryption
  3. Implement platform-specific OAuth handlers (LinkedIn, Twitter, Facebook, TikTok)
  4. Instagram OAuth routes through Facebook Business

Step 4: AI Function

  1. Implement GenerateSocialPostsFunction in igny8_core/ai/functions/generate_social_posts.py
  2. Register generate_social_posts in igny8_core/ai/registry.py

Step 5: Services

  1. Implement SocialPublisherService in igny8_core/business/social_publisher.py
  2. Implement platform-specific publishers (LinkedIn, Twitter, Facebook, Instagram, TikTok)
  3. Implement SocialImageResizeService in igny8_core/business/social_image_resize.py

Step 6: Pipeline Integration

Add Stage 8 trigger after Stage 7 (publish):

# In pipeline after publish completes:
def post_publish(content_id):
    site = content.site
    # Check if social is enabled for this site
    config = AutomationConfig.objects.get(site=site)
    if config.settings.get('social_enabled'):
        generate_social_posts_stage8.delay(content_id)

Step 7: API Endpoints

  1. Create igny8_core/urls/social.py with account, post, calendar, and analytics endpoints
  2. Create views: AccountConnectView, AccountCallbackView, AccountListView
  3. Create PostGenerateView, PostViewSet, CalendarView, AnalyticsView
  4. Register URL patterns under /api/v1/social/

Step 8: Celery Tasks

  1. Implement 4 tasks in igny8_core/tasks/social_tasks.py
  2. Add publish_scheduled_posts, refresh_social_tokens, fetch_engagement to beat schedule

Step 9: Serializers & Admin

  1. Create DRF serializers for SocialAccount (exclude encrypted tokens from response), SocialPost, SocialEngagement
  2. Register models in Django admin

Step 10: Credit Cost Configuration

Add to CreditCostConfig (billing app):

operation_type default_cost description
social_adaptation 1 AI-generate post for one platform
social_hashtag 0.5 Hashtag generation for one post
social_thread 2 Twitter thread generation (2-10 tweets)
social_carousel 5 Carousel post generation
social_image_resize 3-10 Image resizing/generation per platform
social_suite 15-25 Full suite for all 5 platforms

5. ACCEPTANCE CRITERIA

OAuth Connections

  • LinkedIn OAuth 2.0 connects and stores encrypted tokens
  • Twitter/X OAuth 2.0 with PKCE connects successfully
  • Facebook Login with page selection works, stores page_access_token
  • Instagram connects via Facebook Business account
  • TikTok OAuth connects and stores tokens
  • Token refresh runs hourly, updates expired tokens
  • Multi-account support: multiple accounts per platform per site

Post Generation

  • AI generates platform-adapted text for each connected platform
  • LinkedIn posts use professional tone, 1,300 char limit
  • Twitter posts respect 280 char limit, thread option for long content
  • Facebook posts use conversational tone, optimal 500 char length
  • Instagram captions include 20-30 hashtags, "link in bio" CTA
  • TikTok posts use casual/Gen-Z tone, trending hook format
  • UTM parameters appended to all shared URLs

Post Types

  • Announcement, Highlights, Quote Card, FAQ Snippet post types generated
  • Post type selection respects platform compatibility

Scheduling

  • Posts can be scheduled for future time
  • publish_scheduled_posts task runs every minute, publishes due posts
  • Frequency caps enforced (max per day per platform)
  • Cooldown period enforced between posts to same platform
  • Calendar endpoint returns month view of scheduled/published posts
  • Bulk scheduling auto-spaces posts across optimal times

Engagement

  • Engagement metrics fetched every 6 hours for recent posts
  • SocialEngagement records created with likes, comments, shares, impressions, clicks
  • Aggregate analytics endpoint returns per-platform performance + top posts
  • Per-post analytics available with engagement breakdown

Pipeline Integration

  • Stage 8 triggers automatically after Stage 7 (publish)
  • Social posts generated for all connected platforms
  • auto_social_publish toggle controls immediate vs manual review
  • Platform selection configurable via AutomationConfig.settings

Images

  • Images from pipeline resized to platform-specific dimensions
  • media_urls populated on SocialPost records

6. CLAUDE CODE INSTRUCTIONS

File Locations

igny8_core/
├── modules/
│   └── social/
│       ├── __init__.py
│       ├── apps.py                    # app_label = 'social'
│       └── models.py                  # SocialAccount, SocialPost, SocialEngagement
├── ai/
│   └── functions/
│       └── generate_social_posts.py   # GenerateSocialPostsFunction
├── integration/
│   └── oauth/
│       ├── __init__.py
│       ├── base_oauth.py              # BaseOAuthService
│       ├── linkedin_oauth.py
│       ├── twitter_oauth.py
│       ├── facebook_oauth.py
│       ├── instagram_oauth.py         # Routes through Facebook
│       └── tiktok_oauth.py
├── business/
│   ├── social_publisher.py            # SocialPublisherService + platform publishers
│   └── social_image_resize.py         # SocialImageResizeService
├── tasks/
│   └── social_tasks.py                # Celery tasks
├── urls/
│   └── social.py                      # Social endpoints
└── migrations/
    └── XXXX_add_social_models.py

Conventions

  • PKs: BigAutoField (integer) — do NOT use UUIDs
  • Table prefix: igny8_ on all new tables
  • App label: social (new app)
  • Celery app name: igny8_core
  • URL pattern: /api/v1/social/...
  • Permissions: Use SiteSectorModelViewSet permission pattern
  • Token encryption: Same Fernet pattern as 02C GSC tokens — NEVER expose raw tokens in API responses
  • AI functions: Extend BaseAIFunction; register as generate_social_posts
  • Frontend: .tsx files with Zustand stores

Cross-References

Doc Relationship
01E Pipeline Stage 8 integration — hooks after Stage 7 publish
02I Video creator shares social posting for video content; reuses SocialAccount OAuth for YouTube/TikTok
02C GSC token encryption pattern reused for social OAuth tokens
03A WP plugin standalone has share buttons — different from this (posting FROM IGNY8)
04A Managed services include social media management as a service tier

Key Decisions

  1. New social app — Separate from integration because social media is a distinct domain with its own models and business logic
  2. SocialEngagement extends models.Model, not SiteSectorBaseModel — Engagement records are tied to posts, not directly to sites/sectors
  3. Denormalized platform on SocialPost — Avoids join to SocialAccount for platform-based queries and filtering
  4. OAuth tokens encrypted at rest — Same Fernet encryption as 02C; tokens never returned in API responses
  5. AutomationConfig.settings extension — Social pipeline toggles added to existing settings JSONField rather than new model fields