# 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:** ```python # 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) ```python 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) ```python 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) ```python 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` ```python 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/` ```python # 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` ```python 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` ```python @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` ```python 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): ```python # 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