Skip to content

robertguss/social_post

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SocialPost

A self-hosted social media scheduling application for scheduling and publishing content to X/Twitter and LinkedIn. Built with Next.js, Convex, and Better Auth as a single-user productivity tool to replace expensive subscription services.

License Next.js Convex TypeScript

Features

  • Multi-Platform Publishing - Schedule posts to X/Twitter and LinkedIn with platform-specific content
  • Twitter Thread Support - Create and schedule multi-tweet threads (up to 25 tweets) with drag-and-drop reordering
  • AI Content Assistant - Google Gemini-powered features for content creation:
    • Tone adjustment (professional, casual, engaging, formal)
    • Twitter-to-LinkedIn expansion (auto-expand short tweets to LinkedIn posts)
    • Smart hashtag generation (platform-specific, relevant hashtags)
  • Intelligent Posting Time Recommendations - Research-based optimal posting times with custom preference overrides
  • Staggered Scheduling - Set different publish times for each platform
  • Template System - Create and reuse content templates with tags
  • URL Auto-Posting - Automatically post URLs as replies/comments after main content
  • Smart Retry Logic - Automatic retry with exponential backoff for failed posts
  • Failure Notifications - Telegram notifications when posts fail after all retries
  • Token Management - Automatic LinkedIn and Twitter token refresh
  • Encrypted Storage - AES-256-GCM encryption for OAuth tokens
  • Real-Time Updates - Reactive UI updates with Convex subscriptions
  • Mobile Responsive - Optimized for scheduling on the go
  • Analytics Dashboard - Track published, scheduled, and failed posts
  • Usage Tracking & Cost Management - AI request rate limiting and cost estimation

📬 Join the Refactoring AI Newsletter

Subscribe

Refactoring AI Newsletter

I teach developers how to ship their ideas in days with AI

Master modern full-stack development with AI-powered tools and techniques

✨ What You'll Learn:

🚀 I've taught over 50,000 developers to date.
🎯 Top 1% TypeScript engineers globally on GitHub.
🤖 Learn how to use AI coding agents like Claude Code effectively

→ Subscribe Now (It's Free!)


🚀 Built with the AI Starter Kit

GitHub

SocialPost was built using the AI Starter Kit - a production-ready foundation for building full-stack applications with modern tools.

What the Starter Kit Provides:

⚡ Next.js 16 with App Router and React 19
🔄 Convex real-time database with zero infrastructure
🔐 Better Auth authentication (email/password + OAuth ready)
🎨 20+ pre-installed shadcn/ui components
✅ Complete testing setup with Vitest
📚 Comprehensive documentation and examples
🤖 Optimized for AI coding agents like Claude Code

Perfect for rapidly building: SaaS apps, dashboards, real-time tools, and production applications

→ Get the FREE AI Starter Kit


Table of Contents

Quick Start

# Clone the repository
git clone https://github.com/yourusername/social_post.git
cd social_post

# Install dependencies
pnpm install

# Set up environment variables (see Configuration section)
cp .env.example .env.local

# Start development servers
pnpm run dev

Visit http://localhost:3000 to see your app.

Prerequisites

Installation

1. Clone and Install Dependencies

git clone https://github.com/yourusername/social_post.git
cd social_post
pnpm install

2. Set Up Convex

# Initialize Convex development deployment
pnpm dlx convex dev

# Follow the prompts to:
# - Log in to your Convex account
# - Create a new project or select existing one
# - Link your local code to the deployment

3. Set Up Better Auth

  1. Better Auth is already configured with Convex in this project

  2. Configure Better Auth environment variables in your Convex deployment:

    # Follow the Better Auth + Convex setup guide:
    # https://www.better-auth.com/docs
  3. Add required environment variables (see Configuration section below)

4. Configure OAuth Applications

X/Twitter OAuth 2.0:

  1. Create an app at developer.twitter.com
  2. Enable OAuth 2.0 with these scopes:
    • tweet.read
    • tweet.write
    • users.read
    • offline.access
  3. Add callback URL: http://localhost:3000/api/auth/twitter/callback

LinkedIn OAuth 2.0:

  1. Create an app at linkedin.com/developers
  2. Request these permissions:
    • openid
    • profile
    • w_member_social
  3. Add callback URL: http://localhost:3000/api/auth/linkedin/callback

Configuration

Environment Variables

Create .env.local for Next.js:

# Better Auth
BETTER_AUTH_SECRET=your_secret_key
BETTER_AUTH_URL=http://localhost:3000

# Convex
NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud

# OAuth Callback Base URL
NEXT_PUBLIC_BASE_URL=http://localhost:3000

# Single-User Mode (optional - set to "true" to disable new signups)
DISABLE_SIGNUPS=false
NEXT_PUBLIC_DISABLE_SIGNUPS=false

Add to Convex Dashboard (Settings → Environment Variables):

# Better Auth Configuration
BETTER_AUTH_SECRET=your_secret_key
BETTER_AUTH_URL=http://localhost:3000

# X/Twitter OAuth
TWITTER_CLIENT_ID=your_twitter_client_id
TWITTER_CLIENT_SECRET=your_twitter_client_secret

# LinkedIn OAuth
LINKEDIN_CLIENT_ID=your_linkedin_client_id
LINKEDIN_CLIENT_SECRET=your_linkedin_client_secret

# Encryption (generate with: openssl rand -base64 32)
ENCRYPTION_KEY=your_base64_encoded_32_byte_key

# Telegram Notifications (optional)
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_CHAT_ID=your_chat_id

# Google Gemini AI (optional - for AI content features)
GEMINI_API_KEY=your_gemini_api_key

# AI Rate Limiting (optional - defaults shown)
AI_DAILY_RATE_LIMIT=1000              # Daily AI request limit
AI_MONTHLY_RATE_LIMIT=20000           # Monthly AI request limit
AI_WARNING_THRESHOLD_PCT=90           # Warning at 90% of limit

# Performance Tracking (optional - for posting time recommendations)
PERFORMANCE_TRACKING_ENABLED=true     # Enable historical performance tracking

# Single-User Mode (optional - set to "true" to disable new signups)
DISABLE_SIGNUPS=false

Generate Encryption Key

# Generate a secure 32-byte key and encode as base64
openssl rand -base64 32

Copy the output to ENCRYPTION_KEY in Convex environment variables.

Single-User Mode

By default, the application allows multiple users to sign up. If you want to restrict your deployment to a single user (yourself), you can enable single-user mode:

How it works:

  • Set DISABLE_SIGNUPS=true and NEXT_PUBLIC_DISABLE_SIGNUPS=true in your environment variables
  • The signup API endpoint will reject new registration attempts
  • The signup page will display a "Signups Closed" message
  • The "Sign up" link on the login page will be hidden
  • Existing users can continue to log in normally

To enable:

  1. For production deployments, add to your .env.production or Vercel environment variables:

    DISABLE_SIGNUPS=true
    NEXT_PUBLIC_DISABLE_SIGNUPS=true
  2. For Convex production, add to Convex Dashboard → Production → Settings → Environment Variables:

    DISABLE_SIGNUPS=true
  3. Create your account first, then enable single-user mode to lock it down

Use case: This is perfect if you're deploying SocialPost as a personal productivity tool and want to ensure no one else can create an account on your instance.

Development

Available Scripts

# Start both frontend and backend in parallel
pnpm run dev

# Start frontend only (Next.js dev server)
pnpm run dev:frontend

# Start backend only (Convex dev server)
pnpm run dev:backend

# Open Convex dashboard
pnpm dlx convex dashboard

# Build for production
pnpm run build

# Start production server
pnpm run start

# Run linter
pnpm run lint

# Run tests
pnpm run test

# Run tests in watch mode
pnpm run test:watch

# Generate test coverage
pnpm run test:coverage

Project Structure

social_post/
├── app/                      # Next.js App Router pages
│   ├── layout.tsx            # Root layout with providers
│   ├── page.tsx              # Home page
│   ├── dashboard/            # Dashboard page
│   ├── schedule/             # Post scheduling page
│   ├── history/              # Post history page
│   ├── settings/             # Settings page (OAuth + posting preferences)
│   ├── templates/            # Template library page
│   └── api/                  # API routes for OAuth callbacks
├── components/               # React components
│   ├── ui/                   # shadcn/ui components
│   └── features/             # Feature-specific components
│       ├── TwitterThreadComposer.tsx    # Thread creation UI
│       ├── TwitterThreadPreview.tsx     # Thread preview
│       ├── AIAssistantButton.tsx        # AI feature access
│       ├── AISuggestionPanel.tsx        # AI content suggestions
│       ├── HashtagSuggestionPanel.tsx   # Hashtag insertion UI
│       └── RecommendedTimes.tsx         # Posting time suggestions
├── convex/                   # Convex backend
│   ├── schema.ts             # Database schema
│   ├── posts.ts              # Post mutations & queries (thread support)
│   ├── publishing.ts         # Publishing actions (thread publishing)
│   ├── connections.ts        # OAuth connections
│   ├── templates.ts          # Template CRUD
│   ├── dashboard.ts          # Dashboard queries
│   ├── encryption.ts         # Token encryption
│   ├── tokenRefresh.ts       # Twitter & LinkedIn token refresh
│   ├── notifications.ts      # Telegram notifications
│   ├── aiAssistant.ts        # AI feature actions
│   ├── gemini.ts             # Gemini API integration utilities
│   ├── aiUsageTracking.ts    # AI usage tracking & rate limiting
│   ├── aiFeedback.ts         # User feedback collection
│   ├── postingRecommendations.ts  # Posting time recommendations
│   └── postingPreferences.ts      # User preference overrides
├── docs/                     # Documentation
│   ├── setup/                # Setup guides (Gemini, OAuth, etc.)
│   └── archive/              # Completed user stories
├── hooks/                    # Custom React hooks
├── lib/                      # Utility functions
│   └── utils/
│       └── characterCount.ts # Twitter/LinkedIn character counting
└── middleware.ts             # Better Auth route protection

Architecture

Technology Stack

  • Frontend: Next.js 15.5.4 (App Router), React 19, Tailwind CSS 4
  • Backend: Convex (database, queries, mutations, actions)
  • Authentication: Better Auth (single-user auth)
  • UI Components: shadcn/ui
  • Language: TypeScript throughout

Core Concepts

Convex Backend Philosophy: All backend logic lives in convex/. Convex provides:

  • Queries - Read data reactively (realtime updates)
  • Mutations - Write data transactionally
  • Actions - Call external APIs (X, LinkedIn, Telegram) with Node.js runtime
  • Scheduled Functions - Critical for timed post publishing

Scheduled Publishing Architecture:

User creates post → Convex mutation → ctx.scheduler.runAt(scheduledTime)
  → Convex Action publishes to X/LinkedIn → Update post status
  → On failure: Retry logic → Telegram notification

Security:

  • OAuth tokens encrypted with AES-256-GCM before database storage
  • All Convex functions verify user authentication
  • Data scoped to userId for single-user isolation

Data Models

posts - Stores scheduled and published content

  • Fields: status, twitterContent, twitterThread, linkedInContent, scheduledTimes, url, twitterPostIds, errorMessage, retryCount
  • Supports both single tweets (twitterContent) and threads (twitterThread array)
  • Index: by_user on [userId]

user_connections - Stores encrypted OAuth tokens

  • Fields: platform, accessToken, refreshToken, expiresAt
  • Index: by_user_platform on [userId, platform]

templates - Stores reusable content templates

  • Fields: name, content, tags, lastUsedAt, usageCount
  • Index: by_user on [userId]

ai_usage_logs - Tracks AI API usage and costs

  • Fields: userId, timestamp, feature, tokensUsed, cost, modelUsed, requestId, duration, success
  • Indexes: by_user, by_timestamp, by_user_timestamp, by_feature

ai_feedback - User feedback on AI-generated content

  • Fields: userId, feature, requestId, originalContent, aiResponse, feedbackType, feedbackText, timestamp
  • Indexes: by_user, by_feature, by_timestamp

posting_time_recommendations - Research-based optimal posting times

  • Fields: platform, dayOfWeek, hourStart, hourEnd, engagementScore, timeZone (stored in UTC)
  • Index: by_platform_day on [platform, dayOfWeek]

posting_preferences - User custom posting time preferences

  • Fields: userId, platform, dayOfWeek, hourStart, hourEnd, engagementScore, timeZone (stored in local timezone)
  • Index: by_user_platform_day on [userId, platform, dayOfWeek]

post_performance - Historical engagement metrics (feature-gated)

  • Fields: postId, userId, platform, likes, shares, comments, impressions, timestamp
  • Index: by_post on [postId]

Documentation

Comprehensive documentation is available in the docs/ directory:

AI Content Features

SocialPost includes AI-powered content creation features using Google Gemini 1.5 Flash:

Available Features

1. Tone Adjustment

  • Rewrite content in different tones: professional, casual, engaging, or formal
  • Preserves meaning while adjusting voice and style
  • Respects platform character limits (280 for Twitter, 3,000 for LinkedIn)

2. Twitter-to-LinkedIn Expansion

  • Automatically expand short Twitter content into longer LinkedIn posts
  • Targets 500-1,000 characters for LinkedIn
  • Preserves URLs, hashtags, and @mentions from original
  • Only available when Twitter has content and LinkedIn is empty/shorter

3. Smart Hashtag Generation

  • Generate 3-5 relevant hashtags based on post content
  • Platform-aware: short/casual for Twitter, professional/descriptive for LinkedIn
  • Click individual hashtags to insert at cursor position or "Insert All"
  • Character limit validation prevents over-limit insertion

Rate Limiting & Cost Tracking

Rate Limits:

  • Daily: 1,000 requests (configurable via AI_DAILY_RATE_LIMIT)
  • Monthly: 20,000 requests (configurable via AI_MONTHLY_RATE_LIMIT)
  • Warning displayed at 90% of limit (configurable via AI_WARNING_THRESHOLD_PCT)

Cost Estimation:

  • Uses Gemini 1.5 Flash model
  • Pricing (paid tier): $0.075/1M input tokens, $0.30/1M output tokens
  • Typical cost per request: $0.000023 - $0.000065
  • All requests tracked in ai_usage_logs table with token counts and costs

User Feedback:

  • Report issues with AI-generated content via "Report Issue" button
  • Feedback categories: inappropriate, low-quality, other
  • Helps improve AI feature quality over time

Usage

  1. Click the AI Assistant button (sparkles icon) in the post composer
  2. Select a feature from the menu
  3. Review the AI-generated suggestion in a side-by-side panel
  4. Accept, Reject, or Edit the suggestion before applying

Twitter Threads

Create and schedule multi-tweet threads with advanced composition tools:

Thread Creation

Composer Features:

  • Toggle "Thread Mode" to switch from single tweet to thread composition
  • Add up to 25 tweets (Twitter API limit)
  • Drag-and-drop reordering of tweets in the thread
  • Alternative move up/down buttons for reordering
  • Individual character counters per tweet (280 char limit each)
  • Numbered badges showing tweet position in thread
  • Visual warnings for empty tweets (auto-removed on scheduling)
  • Red borders for tweets exceeding character limit

Thread Preview:

  • Live preview showing how thread will appear on Twitter
  • Visual thread connector lines between tweets
  • Character count display per tweet with color-coded warnings
  • Simulated Twitter UI with avatar, handle, timestamp
  • Thread info showing URL will be posted as final reply
  • Empty tweets filtered from preview

Thread Publishing

Publishing Flow:

  1. First tweet published to your timeline
  2. Subsequent tweets posted as replies, creating thread continuity
  3. Optional URL posted as final reply (if provided)
  4. All tweet IDs stored in twitterPostIds array for tracking

Character Counting:

  • Each tweet: 280 character maximum (strict validation)
  • URLs automatically counted as 23 characters (Twitter's t.co shortening)
  • Emoji counted properly (most count as 2 characters)
  • Real-time character counter with warnings at 260 chars

Error Handling:

  • Automatic retry with exponential backoff for transient errors
  • Token refresh before publishing if expiring soon
  • Individual tweet failures don't fail entire thread
  • Detailed error messages for troubleshooting

Thread vs Single Tweet

Backward Compatibility:

  • Existing single tweets stored in twitterContent field
  • New threads stored in twitterThread array field
  • Publishing logic checks for thread first, falls back to single tweet
  • Edit existing posts to convert between single tweet and thread

Intelligent Posting Time Recommendations

Get data-driven suggestions for optimal posting times based on research and your preferences:

How It Works

Research-Based Recommendations:

  • Pre-loaded with best practices from social media research
  • Twitter: Tuesday-Thursday 9-11am EST recommended
  • LinkedIn: Wednesday 10am-12pm EST for maximum engagement
  • All times stored in UTC, displayed in your local timezone
  • Top 3 time suggestions shown with engagement level indicators

Custom Preferences:

  • Override research-based times with your own preferred posting windows
  • Set custom time ranges per platform and day of week
  • Custom preferences prioritized (95 engagement score) over research data
  • Manage preferences at /settings/preferences
  • Side-by-side comparison of custom vs default recommendations

Conflict Detection:

  • Shows when suggested times overlap with already-scheduled posts
  • Helps avoid posting multiple times in short succession
  • Visual indicators for conflicting time slots

Historical Performance Integration (Feature-Gated):

  • Track engagement metrics (likes, shares, comments) from published posts
  • Algorithm blends research data (60%) with your historical performance (40%)
  • Requires Twitter/LinkedIn analytics API access
  • Enable via PERFORMANCE_TRACKING_ENABLED environment variable

Usage

  1. Open post scheduler and select a date
  2. View "Recommended Times" section below date picker
  3. See top 3 suggestions with engagement levels (High/Good/Moderate/Low)
  4. Click a suggestion to auto-fill the posting time
  5. Customize preferences in Settings to override defaults

Testing

Running Tests

# Run all tests
pnpm run test

# Watch mode
pnpm run test:watch

# With coverage
pnpm run test:coverage

Test Coverage

  • Unit Tests: Character counting, validation logic, timestamp conversion
  • Integration Tests: Convex queries/mutations with auth, post creation flow
  • Component Tests: React components with Convex hooks
  • Action Tests: Mock external APIs, test retry logic

Deployment

Deploy to Vercel (Frontend)

# Install Vercel CLI
pnpm i -g vercel

# Deploy to production
vercel --prod

Environment Variables: Add all .env.local variables to Vercel project settings.

Deploy Convex (Backend)

# Create production deployment
pnpm dlx convex deploy

# Set production environment variables
# Via Convex Dashboard → Production → Settings → Environment Variables

Post-Deployment:

  1. Update OAuth callback URLs to production domain
  2. Test OAuth flows in production
  3. Verify scheduled posts are publishing
  4. Set up monitoring and alerting

Production Checklist

  • Environment variables set in Vercel and Convex
  • OAuth apps configured with production callback URLs
  • Encryption key generated and set
  • Telegram bot configured (optional)
  • Better Auth production instance configured
  • DNS records pointed to Vercel
  • SSL certificate active
  • Error tracking configured
  • Backup strategy implemented

Troubleshooting

Common Issues

Posts Not Publishing:

  1. Check Convex logs in dashboard
  2. Verify OAuth tokens are not expired (check Settings page)
  3. Check scheduled function status in Convex dashboard
  4. Review error messages in Post History

OAuth Connection Fails:

  1. Verify callback URLs match exactly
  2. Check client ID and secret in Convex environment variables
  3. Ensure scopes are correctly configured
  4. Check browser console for errors

Encryption Errors:

  1. Verify ENCRYPTION_KEY is set in Convex environment variables

  2. Ensure key is exactly 32 bytes (base64-encoded)

  3. Run migration if upgrading from plain-text tokens:

    // In Convex dashboard console
    await ctx.runAction(internal.encryption.migrateTokensToEncrypted, {
      dryRun: true, // Test first
    });

Rate Limiting:

  • X/Twitter: Space out posts, retry logic handles 429 errors
  • LinkedIn: Built-in retry with exponential backoff

Debug Mode

Enable verbose logging:

# In convex function code
console.log('[Debug]', { postId, status, error });

View logs in Convex Dashboard → Logs.

Contributing

Contributions are welcome! This is a personal productivity tool, but improvements benefit everyone.

Development Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Run tests: pnpm run test
  5. Run linter: pnpm run lint
  6. Commit changes: git commit -m 'Add amazing feature'
  7. Push to branch: git push origin feature/amazing-feature
  8. Open a Pull Request

Coding Standards

  • Use TypeScript for type safety
  • Follow existing code style
  • Add tests for new features
  • Update documentation
  • Use conventional commits

Code Review Process

  • All PRs require review
  • Tests must pass
  • No linting errors
  • Documentation updated

Roadmap

Completed ✅

  • Twitter thread support (up to 25 tweets)
  • AI content assistant (tone adjustment, expansion, hashtag generation)
  • Intelligent posting time recommendations
  • Historical performance tracking foundation
  • Custom posting preference overrides
  • AI usage tracking and cost management
  • Twitter token auto-refresh

Planned

  • Support for additional platforms (Mastodon, Bluesky)
  • Image/media attachment support
  • Full post analytics integration (Twitter/LinkedIn APIs)
  • Bulk scheduling from CSV
  • Multi-user support (future)
  • Browser extension for quick scheduling
  • AI content improvement based on historical performance

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Support

Author

Built with ❤️ as a replacement for expensive social media scheduling tools.


Star this repo if you find it useful!

About

Schedule posts to both X/Twitter & LinkedIn for FREE!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages