Integration Spec

Facebook Publishing Module

Technical deep-dive into the Facebook Graph API integration, OAuth flows for Pages, webhook handling, and queue-based publishing engine for the SMS platform.

🤖 Graph API v18.0 📱 Pages API ⚡ OAuth 2.0 📊 Webhook Listeners

Functional Requirements

📋
Acceptance Criteria Format

Each requirement includes Given/When/Then acceptance criteria, priority, and owner. These form the basis for QA test cases and developer task breakdown.

Authentication

FR-001
User RegistrationRegister with email and password. Email must be unique. Password min 8 chars. Send verification email after registration.
Acceptance Criteria
  • Given a new user submits the registration form with a unique email and 8+ char password, When they click Register, Then account is created, verification email is sent, and they are redirected to the verify-email screen.
  • Given a duplicate email is submitted, When registration is attempted, Then a validation error "Email already registered" is shown.
P0   Owner: Backend   Status: MVP
FR-002
User LoginLogin with email/password. Return JWT access token + refresh token. Rate limit to 5 attempts per 15 min per IP.
FR-003
Password ResetSend password reset link to registered email. Link expires in 60 minutes. Single-use token.
FR-004
Session ManagementJWT access token (15 min TTL). Refresh token (30 day TTL). Logout invalidates refresh token.

Facebook Pages

FR-005
OAuth ConnectionConnect Facebook Pages via Facebook Graph API OAuth. Store access token encrypted.
Acceptance Criteria
  • Given user clicks "Connect Facebook", When they complete the Meta OAuth flow and grant permissions, Then their Facebook Pages are saved, access token is encrypted at rest, and they see it in the accounts list.
  • Given the user denies permissions, When redirected back, Then an error message "Permission denied. Please allow all required permissions." is shown.
P0   Owner: Backend   Status: MVP
FR-006
Multiple PagesUser can connect unlimited Facebook Pages. Each has independent timezone, status, and settings.
FR-007
Token RefreshAutomatically refresh long-lived access tokens. Notify user 7 days before expiry. Suspend publishing if token expires.
FR-008
Account TimezoneEach account has a configurable timezone (IANA format). All displayed times use account timezone. UTC stored internally.

Media Library

FR-009
Media UploadSupport JPG, PNG, WEBP (max 8MB), MP4 (max 100MB). Auto-generate thumbnail. Store metadata in DB. File in local storage.
Acceptance Criteria
  • Given user uploads a JPG under 8MB, When the upload completes, Then thumbnail is generated, record is saved to DB, and the file appears in the media grid immediately.
  • Given user uploads a file over size limit, When file is selected, Then the upload is rejected client-side with message "File too large. Max 8MB for images, 100MB for video."
P0   Owner: Backend + Frontend   Status: MVP
FR-010
Media SearchSearch by filename, tag, MIME type. Filter by date range. Paginated results (20 per page).
FR-011
Media DeleteSoft delete from DB. Hard delete file from storage. Prevent delete if media is used in scheduled posts.

Caption Library

FR-012
Rich Caption EditorSupports emoji, mentions, hashtags. Max 2200 characters. Real-time character counter. Auto-save every 3 seconds.
FR-013
Caption TemplatesSave captions as reusable templates. Mark favorites. Search templates by keyword.

AI Assistant

FR-014
Caption GenerationGenerate caption from user prompt via OpenAI. Support: Generate, Rewrite, Improve, Expand, Shorten, Translate.
FR-015
Hashtag GenerationGenerate relevant hashtags from caption context. Append to caption or show separately. Max 30 hashtags.

Scheduler

FR-016
Create PostSelect account, media, caption. Set date/time in account timezone. Save as draft or schedule.
FR-017
Edit PostEdit scheduled post before publishing window (up to 5 min before scheduled time).
FR-018
Duplicate PostClone post with all settings. New post created in Draft status. User sets new schedule time.
FR-019
Cancel PostCancel a scheduled post. Sets status to Cancelled. Removes from queue. Notifies user.

Calendar

FR-020
Day Calendar ViewShow all scheduled posts on a 24-hour timeline. Color-coded by status. Current time indicator line.
FR-021
Drag & Drop RescheduleDrag post card to new time slot. System recalculates UTC. Confirm modal before saving.

Publishing Engine

FR-022
Automatic PublishingWorker picks up jobs at scheduled UTC time. Validates token, media, caption. Publishes via Facebook Graph API.
FR-023
Retry Failed JobsFailed jobs retry with exponential backoff: 1 min, 5 min, 15 min. Max 3 retries. Permanent failure after limit.
FR-024
Publish HistoryLog every attempt with status, timestamp, error message, API response. Accessible in post detail view.

Notifications & Analytics

FR-025
Failure NotificationNotify user in-app + email when publish permanently fails. Include reason and manual retry option.
FR-026
Token Expiry AlertNotify user 7 days, 3 days, and 1 day before Facebook token expiry. Prompt reconnection.
FR-027
Analytics DashboardDisplay: Likes, Comments, Shares, Reach, Impressions, Engagement Rate. Per-post and account-level views.

Non-Functional Requirements

Category Requirement Target
Performance Page Load Time < 2 seconds (LCP)
Performance API Response Time < 300ms (p95)
Performance Calendar Render < 1 second
Performance Queue Processing < 60 seconds per job
Availability System Uptime 99.9% (SLA)
Scalability Concurrent Users 10,000 active users
Scalability Scheduled Posts Millions of records
Reliability Duplicate Job Prevention Idempotent job IDs
Security Password Hashing bcrypt, cost factor 12
Security Token Storage Encrypted at rest (AES-256)
Security HTTPS TLS 1.2+ required
Security Rate Limiting 100 req/min per user
Accessibility Standard WCAG 2.1 AA
Browser Support Target Browsers Chrome, Firefox, Edge, Safari (last 2 versions)
Compliance Data Privacy No third-party tracking, local storage only

User Stories

Epic: Authentication
As a creator, I want to register an account with my email so that I can access the SMS platform.
Acceptance Criteria:
  • Email must be unique and verified before login is allowed
  • Password must be minimum 8 characters
  • Verification email sent within 60 seconds
Epic: Facebook Pages
As a creator, I want to connect my Facebook Page via OAuth so that I can schedule posts to it.
Acceptance Criteria:
  • OAuth flow completes within Facebook's popup
  • Account appears in account list within 5 seconds
  • Token stored securely and encrypted
Epic: AI Assistant
As a creator, I want AI to generate a caption for my post so that I save time writing engaging content.
Acceptance Criteria:
  • AI generates caption within 5 seconds
  • Caption respects Facebook 63,206 char limit
  • User can edit before saving
  • AI error shows fallback to manual editor
Epic: Scheduler
As a creator, I want to schedule a post so that it publishes automatically without manual action.
Acceptance Criteria:
  • Cannot schedule in past time
  • Post enters queue and shows Scheduled status
  • Confirmation screen shows exact publish time in account timezone
Epic: Calendar
As a creator, I want to drag a post to a new time slot so that rescheduling is fast and visual.
Acceptance Criteria:
  • Cannot drag to past time
  • Confirm modal appears before saving
  • Post status updated instantly on calendar
Epic: Publishing
As a creator, I want failed posts to retry automatically so that temporary API errors don't require manual intervention.
Acceptance Criteria:
  • System retries 3 times with exponential backoff
  • User notified after final failure
  • Retry count visible in post detail
Epic: Analytics
As a creator, I want to view post performance metrics so that I can improve future content strategy.
Acceptance Criteria:
  • Shows likes, comments, shares, reach, impressions
  • Data synced from Facebook within 24 hours of publishing
  • Engagement rate calculated automatically

Business Rules

Timezone Rules

Rule Behavior
Storage All publish timestamps stored in UTC in publish_at_utc column
Display All times displayed to user in account's configured IANA timezone
Drag & Drop Rescheduling recalculates UTC automatically from new time + account timezone
DST System uses IANA timezone library — DST transitions handled automatically
Timezone Change If account timezone is changed after scheduling, display times update but UTC preserved

Scheduling Rules

  • Cannot schedule post in the past (validation at form and API level)
  • Cannot schedule post if Facebook token is expired or account is disconnected
  • Cannot edit a post within 5 minutes of its scheduled publish time
  • Duplicate posts (same account, same time) trigger a warning — user must confirm
  • Carousel posts require minimum 2 and maximum 10 images
  • Video posts support only MP4 format, max 100MB, max 60 seconds duration

Publishing Rules

  • Publishing worker runs every 60 seconds to check for due jobs
  • Job is locked before processing to prevent duplicate publishing (idempotency key)
  • Maximum 3 retry attempts with exponential backoff (1m, 5m, 15m)
  • After max retries, job moves to Permanently Failed status and user is notified
  • Published posts cannot be deleted — only archived for audit history
  • Analytics sync runs 1 hour after successful publish

Media Rules

  • Supported image formats: JPG, PNG, WEBP — max 8MB per file
  • Supported video format: MP4 — max 100MB, max 60 seconds
  • Media cannot be deleted if referenced by a scheduled or processing post
  • Thumbnails generated automatically for all uploaded media
  • File names sanitized and stored with UUID-based names (original name preserved in metadata)

Caption Rules

  • Maximum caption length: 63,206 characters (Facebook limit)
  • Maximum hashtags: 30 per post (Recommended)
  • Caption is optional for image and video posts
  • AI-generated captions are logged in ai_requests table (prompt, response, token usage)

Validation Rules

User Registration Form

Field Rule Error Message
name Required, 2–100 chars, alpha + spaces only "Name must be 2–100 characters"
email Required, valid email format, unique in DB "Email is already registered" / "Invalid email"
password Required, min 8 chars, 1 uppercase, 1 number "Password must be 8+ chars with uppercase and number"
password_confirm Must match password field "Passwords do not match"

Create Post Form

Field Rule Error Message
facebook_page_id Required, must belong to current user, token must be valid "Please select a valid Facebook Page"
media_id Required, must belong to current user, file must exist on disk "Selected media not found or deleted"
caption Optional, max 2200 chars "Caption cannot exceed 2200 characters"
publish_date Required, must be today or future date "Publish date cannot be in the past"
publish_time Required, if today — must be at least 5 min in future "Publish time must be at least 5 minutes from now"
timezone Required, valid IANA timezone string "Invalid timezone"

Media Upload Validation

Check Rule
File Type Whitelist: image/jpeg, image/png, image/webp, video/mp4
Image Size Max 8MB (8,388,608 bytes)
Video Size Max 100MB (104,857,600 bytes)
Video Duration Max 60 seconds (validated server-side via FFprobe)
Image Dimensions Min 320x320px for Facebook compatibility
Virus Scan ClamAV scan before storing (production only)

API Request Validation

All API endpoints validate: Authorization header (Bearer JWT), Content-Type: application/json, and required fields presence before processing. Invalid requests return HTTP 422 with field-level error details.

Edge Cases

Scenario Trigger Expected Behavior Severity
Expired OAuth Token Facebook token expires during publish Cancel job, mark Failed, notify user, prompt reconnect Critical
Account Revoked Externally User removes app from Facebook settings Mark account disconnected, suspend all scheduled posts, log event Critical
Schedule in Past User submits form with past date/time Reject with validation error — "Publish time cannot be in the past" High
Duplicate Schedule Same account + same time + same media Show warning modal — user confirms or cancels High
Media Deleted Before Publish User deletes media linked to scheduled post Block deletion with error — "Media is used in X scheduled posts" High
Instagram API Timeout API does not respond within 30s Retry with backoff, log timeout event High
Instagram API Rate Limit 429 response from Instagram Delay job by rate limit reset window, retry automatically High
Queue Worker Crash Redis worker process dies mid-job Job remains in processing state — watchdog detects and requeues after 5 min Critical
AI Service Unavailable OpenAI API returns 503 Show friendly error, allow manual caption editing, log failure Medium
Empty AI Response OpenAI returns empty content Inform user, offer retry option Medium
Timezone Changed Post-Schedule User changes account timezone Recalculate display time — UTC publish_at_utc preserved unchanged Medium
Drag to Invalid Slot User drags post to past time or invalid slot Snap back to original position, show brief error toast Medium
Storage Full Disk capacity exceeded Reject uploads, alert admin, show user-friendly error Critical
Race Condition on Publish Two workers pick same job simultaneously Idempotency lock prevents duplicate publishing — second worker skips Critical
Session Expired Mid-Form JWT expires while user is filling form Preserve form data in localStorage, redirect to login, restore after re-auth Medium
DST Clock Change Daylight Saving Time transition IANA timezone library handles automatically — no manual intervention needed Medium

Error Handling

Code HTTP Reason User Message Resolution
E001 401 Invalid credentials "Email or password is incorrect." User retries login; lockout after 5 attempts
E002 401 Session expired "Your session has expired. Please log in again." Auto-redirect to login with return URL
E003 403 Instagram token expired "Instagram connection expired. Please reconnect your account." Show reconnect button → OAuth flow
E004 404 Media not found "Selected media could not be found." Prompt user to reselect media
E005 422 Caption too long "Caption exceeds 2200 character limit." Real-time counter prevents submission
E006 422 Past schedule time "Publish time must be in the future." Datepicker validation; API secondary check
E007 503 AI service unavailable "AI assistant is temporarily unavailable. Please write caption manually." Retry after 30 seconds; fallback to manual
E008 500 Queue failure "Publishing system error. Our team has been notified." Auto-retry; engineering alert via monitoring
E009 502 Publishing failed "Post could not be published. Retrying automatically." Exponential backoff retry; user notified after final failure
E010 429 Rate limit exceeded "Too many requests. Please wait and try again." Return Retry-After header; client respects backoff
E011 413 File too large "File size exceeds the limit (8MB for images, 100MB for videos)." Client-side validation before upload
E012 415 Unsupported media type "Unsupported file format. Supported: JPG, PNG, WEBP, MP4." File type check before upload; server rejects invalid types

API Error Response Format

{ "success": false, "error": { "code": "E006", "message": "Publish time must be in the future", "field": "publish_time", // null for non-field errors "details": {}, // additional context "request_id": "req_abc123xyz" // for support/debug } }

API Design

Base URL: /api/v1/ — All endpoints require Authorization: Bearer {jwt_token} header. Content-Type: application/json. Rate limit: 100 requests/minute per user.

Authentication Endpoints

Method Endpoint Description Auth
POST /auth/register Register new user account ❌ Public
POST /auth/login Login, returns JWT + refresh token ❌ Public
POST /auth/logout Invalidate refresh token ✅ JWT
POST /auth/refresh Get new access token via refresh token ✅ Refresh
POST /auth/password/reset Send password reset email ❌ Public

Scheduler Endpoints

Method Endpoint Description
POST /scheduler/posts Create scheduled post
GET /scheduler/posts List posts (params: account_id, status, date, search, page, limit)
GET /scheduler/posts/{id} Get post details with media, caption, queue status
PUT /scheduler/posts/{id} Update post (before publish window)
POST /scheduler/posts/{id}/duplicate Clone post as new draft
POST /scheduler/posts/{id}/reschedule Change publish date/time
POST /scheduler/posts/{id}/cancel Cancel scheduled post
DELETE /scheduler/posts/{id} Delete draft post
GET /scheduler/calendar Get calendar events (params: date, account_id)

Create Post — Request & Response Example

// POST /api/v1/scheduler/posts // Request Body: { "instagram_account_id": "uuid-account", "media_id": "uuid-media", "caption_id": "uuid-caption", // optional "title": "Morning post", "publish_date": "2026-07-10", "publish_time": "09:00", "timezone": "Asia/Kolkata" } // Response 201: { "success": true, "data": { "id": "uuid-post", "status": "scheduled", "publish_at_utc": "2026-07-10T03:30:00Z", "publish_at_local": "2026-07-10 09:00:00 IST", "queue_job_id": "job_abc123" } }

Media Endpoints

Method Endpoint Description
POST /media/upload Upload media file (multipart/form-data)
GET /media List media (params: search, folder_id, type, page)
GET /media/{id} Get media details
DELETE /media/{id} Delete media (soft delete)

AI & Analytics Endpoints

Method Endpoint Description
POST /ai/caption/generate Generate caption from prompt via OpenAI
POST /ai/caption/rewrite Rewrite existing caption
POST /ai/hashtags/generate Generate hashtag suggestions
GET /analytics Analytics dashboard data
GET /analytics/posts/{id} Per-post analytics metrics
GET /notifications List user notifications
PUT /notifications/{id}/read Mark notification as read

Database Design

Database: MySQL 8.0. All tables use UUID primary keys, UTC timestamps, and soft deletes where applicable. Foreign key constraints enforced at DB level.

👥
users
Column Type Properties Description
🔑 id BIGINT UNSIGNED PKAUTO_INC Primary Key
uuid CHAR(36) NOT NULLUNIQUE External Reference ID
name VARCHAR(100) NOT NULL Full Name
email VARCHAR(255) NOT NULLUNIQUE Login Email
password VARCHAR(255) NOT NULL bcrypt hash
avatar VARCHAR(500) NULL Profile Image URL
status ENUM DEFAULT 'active' 'active','inactive','banned'
last_login_at TIMESTAMP NULL
email_verified_at TIMESTAMP NULL
created_at TIMESTAMP DEFAULT NOW()
updated_at TIMESTAMP ON UPDATE NOW()
deleted_at TIMESTAMP NULL soft delete
📱
instagram_accounts
Column Type Properties Description
🔑 id BIGINT UNSIGNED PKAUTO_INC
uuid CHAR(36) NOT NULLUNIQUE
🔗 user_id BIGINT UNSIGNED NOT NULLFK REFERENCES users(id) ON DELETE CASCADE
instagram_user_id VARCHAR(100) NOT NULL Meta Graph ID
username VARCHAR(100) NOT NULL Instagram Handle
display_name VARCHAR(255) NULL
profile_picture VARCHAR(500) NULL
access_token TEXT NOT NULL AES-256 encrypted
token_expires_at TIMESTAMP NULL
timezone VARCHAR(100) DEFAULT 'UTC' Account scheduling timezone
status ENUM DEFAULT 'active' 'active','expired','disconnected'
publishing_enabled TINYINT(1) DEFAULT 1
created_at TIMESTAMP DEFAULT NOW()
updated_at TIMESTAMP ON UPDATE NOW()
📅
scheduled_posts
Column Type Properties Description
🔑 id BIGINT UNSIGNED PKAUTO_INC
uuid CHAR(36) NOT NULLUNIQUE
🔗 user_id BIGINT UNSIGNED NOT NULLFK REFERENCES users(id)
🔗 instagram_account_id BIGINT UNSIGNED NOT NULLFK REFERENCES instagram_accounts(id)
media_id BIGINT UNSIGNED NULL Foreign key to media table
caption_id BIGINT UNSIGNED NULL Foreign key to captions table
title VARCHAR(255) NULL Internal note/title
status ENUM DEFAULT 'draft' 'draft','scheduled','queued','processing','published','failed','retrying','cancelled'
publish_date DATE NOT NULL Local user date
publish_time TIME NOT NULL Local user time
publish_at_utc TIMESTAMP NOT NULL Converted absolute UTC datetime
published_at TIMESTAMP NULL Actual publish time
retry_count TINYINT DEFAULT 0
error_message TEXT NULL
created_at TIMESTAMP DEFAULT NOW()
updated_at TIMESTAMP ON UPDATE NOW()
deleted_at TIMESTAMP NULL
⚙️
publish_jobs
Column Type Properties Description
🔑 id BIGINT UNSIGNED PKAUTO_INC
uuid CHAR(36) NOT NULLUNIQUE
🔗 scheduled_post_id BIGINT UNSIGNED NOT NULLFK REFERENCES scheduled_posts(id)
idempotency_key CHAR(64) NOT NULLUNIQUE Prevents duplicate execution
queue_name VARCHAR(100) DEFAULT 'publishing'
status ENUM DEFAULT 'pending' 'pending','processing','published','failed'
priority TINYINT DEFAULT 5
retry_count TINYINT DEFAULT 0
error_message TEXT NULL
api_response JSON NULL Raw payload from Meta API
scheduled_at TIMESTAMP NOT NULL
started_at TIMESTAMP NULL
finished_at TIMESTAMP NULL
created_at TIMESTAMP DEFAULT NOW()
updated_at TIMESTAMP ON UPDATE NOW()

Other Tables Summary

🖼️
media
Uploaded media metadata
uuid, user_id, file_name, mime_type, size, storage_path, thumbnail_path
✍️
captions
Reusable caption templates
uuid, user_id, title, content, hashtags, is_favorite
🔔
notifications
User notification inbox
uuid, user_id, type, title, message, severity, status, read_at
📈
analytics
Instagram post metrics
scheduled_post_id, likes, comments, shares, saves, reach, impressions, engagement_rate, synced_at
🤖
ai_requests
AI request audit log
user_id, prompt, response, model, tokens_used, request_type, status
👣
activity_logs
User activity audit trail
user_id, action, resource_type, resource_id, ip_address, user_agent

Architecture

Architecture Style: Modular Monolith (MVP) — Service-oriented ready. API-first. Queue-based processing. Event-driven background jobs. Designed to split into microservices in Phase 3.

System Architecture Diagram

SMS System Architecture Diagram showing 5 layers: Client Layer (React/TypeScript), API Gateway (Laravel REST API), Queue Layer (Redis + Laravel Horizon), Data Layer (MySQL), and External Services (Instagram Graph API, OpenAI, Email, Cloud Storage)

High-Level Architecture Flow

USER BROWSER
React + TypeScript + Tailwind
HTTPS REST API
LARAVEL API LAYER
Auth | Scheduler | Media | Caption | AI | Analytics
JWT Middleware + Rate Limiter
MySQL DB
(All Data)
Redis
(Queue)
Queue Workers
(PHP Artisan queue:work)
Local File Storage
(Images, Videos, Thumbs)
EXTERNAL SERVICES
Instagram Graph API | OpenAI

Publishing Sequence

1
User schedules post via API
  • Validate all fields
  • Convert timezone to UTC (publish_at_utc)
  • Store in scheduled_posts (status: scheduled)
  • Create publish_jobs entry (status: pending)
2
Queue Worker (runs every 60s)
  • SELECT jobs WHERE scheduled_at <= NOW() AND status = 'pending'
  • Lock job with idempotency_key (UPDATE ... WHERE status = 'pending')
  • Validate: token valid, media exists, account active
3
Instagram Graph API Call
  • Upload media container
  • Publish container to feed
  • Store API response
4
On Success
  • Update scheduled_posts status = 'published'
  • Update publish_jobs status = 'published'
  • Schedule analytics sync (1hr delay)
  • Send success notification
5
On Failure
  • Log error_message + api_response
  • If retry_count < 3: requeue with exponential backoff
  • If retry_count >= 3: status = 'failed', notify user

Technology Stack

Layer Technology Purpose
Frontend React + TypeScript + Tailwind CSS SPA, Calendar, Dashboard, Forms
Backend PHP 8.2 + Laravel 11 REST API, Business Logic, Queue Management
Database MySQL 8.0 All persistent data storage
Queue Redis + Laravel Horizon Background job processing, retry management
AI OpenAI GPT-4o API Caption generation, hashtag suggestions
Storage Local FileSystem (Laravel Storage) Media files, thumbnails
Auth JWT (tymon/jwt-auth) Stateless API authentication
Instagram Instagram Graph API v19+ OAuth, media publishing, analytics sync
Infrastructure Docker + Docker Compose Containerized deployment

Security

Category Implementation Standard
Password Hashing bcrypt, cost factor 12 OWASP
JWT Tokens HS256, 15-min access TTL, 30-day refresh TTL RFC 7519
Instagram Tokens AES-256-CBC encrypted at rest FIPS 140-2
HTTPS TLS 1.2+ mandatory, HSTS enabled OWASP A02
CSRF Protection Laravel SanctumCSRF cookie + Referer check for web routes OWASP A01
SQL Injection Eloquent ORM prepared statements — no raw queries OWASP A03
XSS Prevention React JSX auto-escaping; API responses Content-Type: application/json OWASP A03
Rate Limiting 100 req/min per user; 5 login attempts per 15 min per IP OWASP A04
File Upload Security MIME type whitelist, file extension check, ClamAV scan OWASP A08
RBAC Policy-based authorization — user can only access their own resources Least Privilege
Audit Logging All create/update/delete operations logged in activity_logs SOC 2
Environment Secrets .env file, never committed to VCS. Production uses secret manager. 12-Factor App

OAuth Security Flow

1. User clicks "Connect Instagram" 2. Redirect to Instagram OAuth with: - client_id: APP_ID - redirect_uri: https://app.sms.com/instagram/callback - scope: instagram_basic, instagram_content_publish, instagram_manage_insights - state: CSRF_TOKEN (random 32-byte hex stored in session) 3. Instagram redirects back with: code, state 4. Server validates state === session CSRF_TOKEN 5. Exchange code for short-lived access token 6. Exchange for long-lived access token (60-day TTL) 7. Encrypt token with AES-256 before storing in DB 8. Schedule auto-refresh 7 days before expiry

Performance

Metric Target Strategy
API Response Time < 300ms (p95) DB indexes, eager loading, response caching
Page Load (LCP) < 2 seconds React code splitting, lazy loading, CDN for static assets
Calendar Render < 1 second Virtualized list, date-scoped queries, client-side cache
Media Upload < 5 seconds for 8MB Async upload, progress streaming, background thumbnail generation
Queue Processing < 60 seconds Parallel workers (Horizon), priority queues, job timeout settings
AI Response < 5 seconds OpenAI streaming, client-side loading state, timeout 30s
Database Queries < 50ms Proper indexes, avoid N+1 (eager load), query result caching

Caching Strategy

Data Cache Layer TTL
User session data Redis 15 minutes
Dashboard stats Redis 5 minutes
Calendar events (day) Client localStorage 1 minute
Analytics data Redis 1 hour
Instagram account list Redis 5 minutes

Database Optimization

  • Composite index on scheduled_posts(status, publish_at_utc) for queue worker query
  • Composite index on scheduled_posts(user_id, status) for user dashboard
  • Eager load instagram_account when listing scheduled_posts
  • Paginate all list endpoints — max 50 records per page
  • Soft-deleted records excluded from all queries via global scope
  • Analytics table partitioned by month for large-scale data

Testing

Test Level Tool / Framework Coverage Target Responsibility
Unit Tests PHPUnit (Backend), Jest (Frontend) > 80% (Core Logic) Developers
Integration Tests PHPUnit API Endpoints, Queue Workers Developers
UI/E2E Tests Cypress Critical Paths (Login, Schedule Post) QA Automation
Security Tests OWASP ZAP Vulnerability Scanning Security Team
Performance Tests k6 API Load (1k req/sec) DevOps

Critical Test Scenarios

  • Schedule a post across daylight saving time boundary
  • Simulate Instagram API failure and verify exponential backoff retry
  • Test duplicate idempotency key submission (should reject second request)
  • Upload 100MB MP4 file and verify processing time
  • Verify session termination across all devices on password reset

QA Checklist

Frontend (React)

  • Responsive design (Mobile/Tablet/Desktop)
  • Form validation (Empty fields, invalid data)
  • Timezone rendering matches OS local vs selected
  • Drag & Drop works smoothly on touch devices

Backend (API)

  • Rate limiter blocks > 100 req/min
  • Invalid JWT returns 401 Unauthorized
  • Past date scheduling returns 422
  • Pagination works (page=2, limit=50)

Worker (Publishing)

  • Job picks up at exact scheduled_at UTC time
  • Failed job increments retry_count
  • Max retry limit marks job as failed
  • Idempotency prevents double publish

Developer Checklist

  • Ensure all new API endpoints are documented in Swagger/OpenAPI
  • Verify no N+1 query issues using Laravel Telescope
  • Write database migrations with both up() and down() methods
  • Add appropriate indexes for any new foreign keys
  • Use strict types (declare(strict_types=1);) in all new PHP files
  • Ensure all frontend components use TypeScript interfaces for props
  • Remove all console.log and dd() before creating PR
  • Run PHP CodeSniffer and ESLint locally

DevOps Checklist

  • Configure Redis maxmemory policy to noeviction for Queue data safety
  • Set up Supervisor to manage Laravel Horizon worker processes
  • Configure Nginx client_max_body_size to 120M for video uploads
  • Set up Datadog/NewRelic APM for API response monitoring
  • Ensure S3 / Local storage directories have correct RWX permissions
  • Configure automated daily backups for MySQL database
  • Set up Slack alerts for Queue worker crashes
  • Configure SSL/TLS certificates and force HTTPS redirection

Risks

Risk Impact Probability Mitigation Strategy
Instagram API changes rate limits High Medium Implement dynamic rate limit detection and job backoff.
Queue Worker Memory Leaks Medium Medium Configure supervisor to restart workers every 1000 jobs.
OpenAI API Downtime Medium Low Graceful UI degradation; allow manual caption entry.
User Timezone Confusion High Medium Clear UI indicators of which timezone is currently selected.

Assumptions

  • Users have valid Instagram Professional/Creator accounts linked to Facebook Pages.
  • Average video size will be under 50MB (max allowed is 100MB).
  • Most users will schedule posts 1-7 days in advance.
  • Users understand that AI content may require manual review before publishing.