| name | content-calendar |
| description | Plan, schedule, and publish social media posts across Twitter/X, LinkedIn, and Instagram from a single self-hosted calendar interface. Use when asked to schedule social posts, manage a content pipeline, preview platform-specific formatting, or bulk-import a posting schedule from CSV. Triggers include "schedule post", "social media calendar", "publish to Twitter", "content pipeline", "bulk schedule", or "content calendar". |
content-calendar
Self-hosted social media content planner. Schedule posts across platforms, preview formatting, and manage a team content pipeline.
When to use
- Planning and scheduling social media posts across multiple platforms
- Previewing how content will appear on Twitter/X, LinkedIn, and Instagram before publishing
- Managing a content pipeline with a small team (drafts, review, schedule)
- Bulk scheduling posts from a CSV file
- Tracking post performance analytics
Prerequisites
- content-calendar server running (self-hosted or Docker)
- Login credentials (email + password)
- At least one platform connected in Settings
Quick Start
docker compose up -d
open http://localhost:3000
Default admin credentials are set during first run via the seed script.
Core Workflows
Create and schedule a post
- Open the calendar or Posts view.
- Click "New Post".
- Enter a title (internal reference), body text, and select platforms.
- Upload or pick media from the library.
- Click "Schedule Post" and pick a date and time.
- Review the platform preview and confirm.
Bulk schedule from CSV
- Go to Posts, then Bulk Import.
- Upload a CSV with columns:
title, body, platforms, scheduled_at.
- Review the parsed rows for validation errors.
- Click "Schedule N Posts" to confirm.
CSV format:
title,body,platforms,scheduled_at
Spring sale,Check out our sale!,twitter;linkedin,2026-03-24T09:00:00Z
Publish immediately
On any scheduled post, click the three-dot menu and select "Publish Now". The scheduler will attempt to publish within seconds.
API Reference
All API calls require a valid session cookie (POST /api/auth/login to authenticate).
| Method | Path | Description |
|---|
| POST | /api/auth/login | Log in (body: email, password) |
| GET | /api/posts | List posts (filter: status, platform) |
| POST | /api/posts | Create post |
| PUT | /api/posts/:id | Update post |
| DELETE | /api/posts/:id | Delete post |
| POST | /api/posts/:id/publish | Publish immediately |
| GET | /api/calendar | Posts for month (?year=2026&month=3) |
| POST | /api/media | Upload media file (multipart) |
| GET | /api/analytics | Aggregate stats |
Environment Variables
| Variable | Description | Default |
|---|
| PORT | Server port | 3000 |
| DATA_DIR | SQLite + media storage path | ./data |
| SESSION_SECRET | Session signing secret (required) | - |
| MEDIA_MAX_SIZE_MB | Max upload size in MB | 50 |
| SCHEDULER_ENABLED | Enable auto-publishing: 0 or 1 | 1 |
| LOG_LEVEL | debug, info, warn, error | info |
Post Status Lifecycle
draft -> scheduled -> published
-> failed (retry up to 3 times)
A post with no scheduled_at is a draft. Setting a date and saving moves it to scheduled. The cron job publishes due posts every minute.
Platform Rules Summary
| Platform | Body limit | Images | Links |
|---|
| Twitter / X | 280 chars | 4 images or 1 video | Auto-card |
| LinkedIn | 3000 chars | 9 images or 1 video | Auto-preview |
| Instagram | 2200 chars | 10 images or 1 video | Link in bio only |
Troubleshooting
Post shows "Failed"
The platform API returned an error. Check Settings to confirm the access token is still valid. LinkedIn tokens expire frequently and must be reconnected. Click "Retry" on the failed post after reconnecting.
Scheduled post not published
Confirm SCHEDULER_ENABLED=1 in your environment. The scheduler runs every minute; posts may publish up to 60 seconds after their scheduled time.
Platform connection not working
OAuth tokens expire. Go to Settings > Platform Connections and click "Reconnect" for the affected platform.
Media upload rejected
Check that the file is under MEDIA_MAX_SIZE_MB and is one of the allowed types: PNG, JPG, GIF, WebP, MP4, MOV.