|
@@ -1,16 +1,23 @@
|
|
|
# SocialManager — Personal Social Media Manager
|
|
# SocialManager — Personal Social Media Manager
|
|
|
|
|
|
|
|
-A self-hosted, local-first social media management platform. Aggregate feeds from all your platforms, compose and cross-post content, schedule posts, and get AI-powered suggestions — all from one dashboard.
|
|
|
|
|
|
|
+A self-hosted, local-first social media management platform. Aggregate feeds from all your platforms, compose and cross-post content, schedule posts with per-account timezone support, and get AI-powered suggestions via a local Ollama instance — all from one privacy-first dashboard.
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
## Features
|
|
## Features
|
|
|
|
|
|
|
|
-- **Unified Feed** — Pull feeds from Twitter/X, Mastodon, Bluesky, LinkedIn, Instagram, Reddit and YouTube into a single dashboard
|
|
|
|
|
-- **Filter & Tag** — Filter your feed by platform or custom tags
|
|
|
|
|
-- **Cross-post** — Write once, publish to multiple platforms simultaneously
|
|
|
|
|
-- **Scheduler** — Schedule posts for a specific date/time with BullMQ job queue
|
|
|
|
|
-- **AI Assistance** — Grammar correction and platform-specific content adaptation (T5 model, runs locally)
|
|
|
|
|
|
|
+- **Unified Feed** — Pull feeds from Twitter/X, Mastodon, Bluesky, LinkedIn, Instagram, Facebook, Reddit and YouTube into a single TweetDeck-style dashboard
|
|
|
|
|
+- **Cross-post** — Write once, publish to multiple platforms simultaneously with per-account targeting
|
|
|
|
|
+- **Scheduler** — Schedule posts for a specific date/time; BullMQ handles retries with idempotent delivery (no duplicate posts)
|
|
|
|
|
+- **Per-account Timezone** — Each account stores its own timezone; the compose view converts scheduled times correctly
|
|
|
|
|
+- **Media Library** — Upload images and videos from your device; pick from the library in Compose
|
|
|
|
|
+- **Draft Saving** — Save posts and return to them later from the Drafts tab
|
|
|
|
|
+- **Content Calendar** — Month/week calendar view of scheduled posts in the Scheduler
|
|
|
|
|
+- **Account Profiles** — Store business context (name, industry, audience, tone, hashtags) per account for AI context injection
|
|
|
|
|
+- **AI Assistance** — Powered by local [Ollama](https://ollama.ai): draft generation, hashtag suggestions, image captions (via vision models); streams directly into the editor
|
|
|
|
|
+- **Token Expiry Warnings** — Dashboard banner when Meta tokens are within 7 days of expiry
|
|
|
|
|
+- **Token Encryption** — OAuth tokens stored AES-256-GCM encrypted at rest
|
|
|
|
|
+- **Structured Logging** — Pino JSON logging across all services with consistent fields
|
|
|
- **Multi-language UI** — English and Turkish built-in; adding a new language is a single file
|
|
- **Multi-language UI** — English and Turkish built-in; adding a new language is a single file
|
|
|
- **Microservices** — Each platform is an independent service, easy to add or remove
|
|
- **Microservices** — Each platform is an independent service, easy to add or remove
|
|
|
- **Fully local** — No SaaS, no subscriptions. Runs entirely on your machine via Docker
|
|
- **Fully local** — No SaaS, no subscriptions. Runs entirely on your machine via Docker
|
|
@@ -22,12 +29,12 @@ A self-hosted, local-first social media management platform. Aggregate feeds fro
|
|
|
| Layer | Technology |
|
|
| Layer | Technology |
|
|
|
|-------|-----------|
|
|
|-------|-----------|
|
|
|
| Frontend | Vue 3, TypeScript, Vite, Tailwind CSS, Pinia, Vue Router, vue-i18n |
|
|
| Frontend | Vue 3, TypeScript, Vite, Tailwind CSS, Pinia, Vue Router, vue-i18n |
|
|
|
-| API Gateway | Node.js / Fastify |
|
|
|
|
|
-| Message Broker | RabbitMQ |
|
|
|
|
|
-| Database | MongoDB |
|
|
|
|
|
|
|
+| API Gateway | Node.js / Fastify 4 |
|
|
|
|
|
+| Platform Services | Node.js / Fastify (one per platform) |
|
|
|
|
|
+| Database | MongoDB 6 |
|
|
|
| Job Queue | Redis + BullMQ |
|
|
| Job Queue | Redis + BullMQ |
|
|
|
-| AI Service | Python / HappyTransformer (T5) |
|
|
|
|
|
-| Platform SDKs | twitter-api-v2, masto, @atproto/api |
|
|
|
|
|
|
|
+| AI | [Ollama](https://ollama.ai) (local LLM — llama3.2, llava, etc.) |
|
|
|
|
|
+| Logging | Pino (structured JSON) |
|
|
|
| Reverse Proxy | Nginx |
|
|
| Reverse Proxy | Nginx |
|
|
|
| Containerization | Docker Compose |
|
|
| Containerization | Docker Compose |
|
|
|
|
|
|
|
@@ -41,17 +48,17 @@ A self-hosted, local-first social media management platform. Aggregate feeds fro
|
|
|
| `ui` | — | Vue 3 frontend (Vite dev server) |
|
|
| `ui` | — | Vue 3 frontend (Vite dev server) |
|
|
|
| `gateway` | 8084 | REST API gateway |
|
|
| `gateway` | 8084 | REST API gateway |
|
|
|
| `socket` | 8085 | WebSocket server (real-time feed updates) |
|
|
| `socket` | 8085 | WebSocket server (real-time feed updates) |
|
|
|
-| `formatter` | — | Platform-specific content formatter |
|
|
|
|
|
-| `ai-grammar-correction` | — | AI grammar correction (T5) |
|
|
|
|
|
-| `feed-aggregator` | 3010 | Pulls feeds from all platforms periodically |
|
|
|
|
|
|
|
+| `feed-aggregator` | 3010 | Polls feeds from all platforms periodically |
|
|
|
| `scheduler` | 3011 | Scheduled post management (BullMQ) |
|
|
| `scheduler` | 3011 | Scheduled post management (BullMQ) |
|
|
|
| `twitter` | 3001 | Twitter/X integration |
|
|
| `twitter` | 3001 | Twitter/X integration |
|
|
|
| `linkedin` | 3002 | LinkedIn integration |
|
|
| `linkedin` | 3002 | LinkedIn integration |
|
|
|
| `mastodon` | 3003 | Mastodon integration |
|
|
| `mastodon` | 3003 | Mastodon integration |
|
|
|
| `bluesky` | 3004 | Bluesky (AT Protocol) integration |
|
|
| `bluesky` | 3004 | Bluesky (AT Protocol) integration |
|
|
|
|
|
+| `instagram` | 3005 | Instagram Graph API |
|
|
|
|
|
+| `facebook` | 3006 | Facebook Pages Graph API |
|
|
|
| `mongodb` | 27018 | Database |
|
|
| `mongodb` | 27018 | Database |
|
|
|
| `redis` | 6379 | Cache & job queue |
|
|
| `redis` | 6379 | Cache & job queue |
|
|
|
-| `messageBroker` | 5672 / 15672 | RabbitMQ (+ management UI) |
|
|
|
|
|
|
|
+| `messageBroker` | 5672 / 15672 | RabbitMQ (legacy, largely unused) |
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
@@ -70,9 +77,14 @@ cd social-media-manager
|
|
|
cp .env.example .env
|
|
cp .env.example .env
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Edit `.env` and fill in your API credentials for the platforms you want to use. You can start with just Mastodon or Bluesky — both have free, open APIs.
|
|
|
|
|
|
|
+Edit `.env` and fill in your API credentials. Minimum required fields:
|
|
|
|
|
|
|
|
```env
|
|
```env
|
|
|
|
|
+APP_BASE_URL=http://localhost:8081
|
|
|
|
|
+
|
|
|
|
|
+# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
|
|
|
+ENCRYPTION_KEY=your_64_hex_char_key_here
|
|
|
|
|
+
|
|
|
# Mastodon (easiest — get token from instance Settings > Development)
|
|
# Mastodon (easiest — get token from instance Settings > Development)
|
|
|
MASTODON_INSTANCE_URL=https://mastodon.social
|
|
MASTODON_INSTANCE_URL=https://mastodon.social
|
|
|
MASTODON_ACCESS_TOKEN=your_token_here
|
|
MASTODON_ACCESS_TOKEN=your_token_here
|
|
@@ -90,6 +102,17 @@ docker compose up -d
|
|
|
|
|
|
|
|
Open **http://localhost:8081** in your browser.
|
|
Open **http://localhost:8081** in your browser.
|
|
|
|
|
|
|
|
|
|
+### 4. (Optional) Connect AI via Ollama
|
|
|
|
|
+
|
|
|
|
|
+Run Ollama on your host machine and pull a model:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+ollama pull llama3.2 # text generation
|
|
|
|
|
+ollama pull llava # image captioning (vision)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Then go to **Settings → AI Integration**, set the endpoint to `http://host.docker.internal:11434`, test the connection, and save.
|
|
|
|
|
+
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
## Platform Connection Guide
|
|
## Platform Connection Guide
|
|
@@ -109,7 +132,7 @@ Open **http://localhost:8081** in your browser.
|
|
|
|
|
|
|
|
## Instagram & Facebook Setup (Facebook Developer App)
|
|
## Instagram & Facebook Setup (Facebook Developer App)
|
|
|
|
|
|
|
|
-Both Instagram and Facebook share **one Facebook Developer App**. You set it up once, then connect everything from the Settings UI — no token copying required.
|
|
|
|
|
|
|
+Both Instagram and Facebook share **one Facebook Developer App**. You set it up once, then connect everything from the Settings UI — no token copying required. Tokens are stored encrypted (AES-256-GCM) in MongoDB.
|
|
|
|
|
|
|
|
### Prerequisites
|
|
### Prerequisites
|
|
|
|
|
|
|
@@ -117,38 +140,23 @@ Both Instagram and Facebook share **one Facebook Developer App**. You set it up
|
|
|
- A **Facebook Page** (personal timelines are not supported by the Graph API)
|
|
- A **Facebook Page** (personal timelines are not supported by the Graph API)
|
|
|
- For Instagram: a **Business or Creator Instagram account** linked to that Facebook Page
|
|
- For Instagram: a **Business or Creator Instagram account** linked to that Facebook Page
|
|
|
|
|
|
|
|
----
|
|
|
|
|
-
|
|
|
|
|
### Step 1 — Create a Facebook App
|
|
### Step 1 — Create a Facebook App
|
|
|
|
|
|
|
|
1. Go to [developers.facebook.com/apps](https://developers.facebook.com/apps/) and click **Create App**
|
|
1. Go to [developers.facebook.com/apps](https://developers.facebook.com/apps/) and click **Create App**
|
|
|
-2. Choose **Business** as the app type and give it a name (e.g. `SocialManager Local`)
|
|
|
|
|
|
|
+2. Choose **Business** as the app type
|
|
|
3. In **Settings > Basic**, note down your **App ID** and **App Secret**
|
|
3. In **Settings > Basic**, note down your **App ID** and **App Secret**
|
|
|
|
|
|
|
|
----
|
|
|
|
|
-
|
|
|
|
|
### Step 2 — Add Products & Permissions
|
|
### Step 2 — Add Products & Permissions
|
|
|
|
|
|
|
|
-In your app dashboard:
|
|
|
|
|
-
|
|
|
|
|
-#### Facebook Login for Business
|
|
|
|
|
|
|
+**Facebook Login for Business:**
|
|
|
|
|
|
|
|
-- Products > **Facebook Login for Business** > Set Up
|
|
|
|
|
- Under **Client OAuth Settings**, add to **Valid OAuth Redirect URIs**:
|
|
- Under **Client OAuth Settings**, add to **Valid OAuth Redirect URIs**:
|
|
|
|
|
|
|
|
```text
|
|
```text
|
|
|
http://localhost:8081/api/auth/meta/callback
|
|
http://localhost:8081/api/auth/meta/callback
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
- (If hosting remotely, replace `http://localhost:8081` with your `APP_BASE_URL`)
|
|
|
|
|
-
|
|
|
|
|
-#### Instagram Graph API
|
|
|
|
|
-
|
|
|
|
|
-- Products > **Instagram Graph API** > Set Up
|
|
|
|
|
-
|
|
|
|
|
-#### Required Permissions
|
|
|
|
|
-
|
|
|
|
|
-Enable in Development mode — no App Review needed for your own accounts:
|
|
|
|
|
|
|
+**Required permissions** (Development mode — no App Review needed for your own accounts):
|
|
|
|
|
|
|
|
| Permission | Used for |
|
|
| Permission | Used for |
|
|
|
|------------|----------|
|
|
|------------|----------|
|
|
@@ -158,30 +166,27 @@ Enable in Development mode — no App Review needed for your own accounts:
|
|
|
| `instagram_content_publish` | Publish Instagram posts |
|
|
| `instagram_content_publish` | Publish Instagram posts |
|
|
|
| `instagram_manage_insights` | Required alongside content_publish |
|
|
| `instagram_manage_insights` | Required alongside content_publish |
|
|
|
|
|
|
|
|
----
|
|
|
|
|
-
|
|
|
|
|
### Step 3 — Connect from the Settings UI
|
|
### Step 3 — Connect from the Settings UI
|
|
|
|
|
|
|
|
1. Open <http://localhost:8081/settings>
|
|
1. Open <http://localhost:8081/settings>
|
|
|
-2. In the **Facebook & Instagram** card, enter your App ID and App Secret → **Save**
|
|
|
|
|
-3. Click **Connect with Facebook & Instagram** — this redirects you to Facebook's OAuth page
|
|
|
|
|
-4. Authorise the app
|
|
|
|
|
-5. You are returned to Settings with a **page picker** listing all your Facebook Pages and linked Instagram accounts
|
|
|
|
|
-6. Check the ones you want to manage → **Connect Selected**
|
|
|
|
|
|
|
+2. Enter your App ID and App Secret → **Save**
|
|
|
|
|
+3. Click **Connect with Facebook & Instagram**
|
|
|
|
|
+4. Authorise the app on Facebook's OAuth page
|
|
|
|
|
+5. Select which Pages and Instagram accounts to manage → **Connect Selected**
|
|
|
|
|
|
|
|
-That's it. Tokens are stored in MongoDB — no `.env` editing required. You can connect multiple Pages and Instagram accounts simultaneously.
|
|
|
|
|
-
|
|
|
|
|
----
|
|
|
|
|
|
|
+Tokens are stored encrypted in MongoDB — no `.env` editing required.
|
|
|
|
|
|
|
|
### Token Notes
|
|
### Token Notes
|
|
|
|
|
|
|
|
| Token | Expiry | How it is handled |
|
|
| Token | Expiry | How it is handled |
|
|
|
-| --- | --- | --- |
|
|
|
|
|
|
|
+|-------|--------|-------------------|
|
|
|
| Short-lived user token | 1–2 hours | Exchanged automatically during OAuth |
|
|
| Short-lived user token | 1–2 hours | Exchanged automatically during OAuth |
|
|
|
-| Long-lived user token | ~60 days | Stored in MongoDB; reconnect via Settings when it expires |
|
|
|
|
|
-| Page access token | Never expires | Fetched during OAuth and stored; does not need refreshing |
|
|
|
|
|
|
|
+| Long-lived user token | ~60 days | Stored encrypted; reconnect via Settings when it expires |
|
|
|
|
|
+| Page access token | Never expires | Fetched during OAuth and stored encrypted |
|
|
|
|
|
|
|
|
-> **Instagram publishing:** Instagram does not support text-only posts via the Graph API. Every post requires at least one image URL (`imageUrl`) or video URL (`videoUrl`) in addition to the caption. The compose view will need these fields when targeting Instagram.
|
|
|
|
|
|
|
+> A banner appears in the Dashboard and Settings when any Meta token expires within 7 days.
|
|
|
|
|
+>
|
|
|
|
|
+> **Instagram publishing:** Every post requires at least one `imageUrl` or `videoUrl`. Text-only posts are not supported by the Instagram Graph API.
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
@@ -194,7 +199,7 @@ That's it. Tokens are stored in MongoDB — no `.env` editing required. You can
|
|
|
// Add to messages: { en, tr, xx }
|
|
// Add to messages: { en, tr, xx }
|
|
|
// Add to SUPPORTED_LOCALES: { code: 'xx', label: '...', flag: '🇽🇽' }
|
|
// Add to SUPPORTED_LOCALES: { code: 'xx', label: '...', flag: '🇽🇽' }
|
|
|
```
|
|
```
|
|
|
-3. Done — language will appear in the NavBar dropdown automatically
|
|
|
|
|
|
|
+3. Done — the language appears in the NavBar dropdown automatically
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
@@ -203,8 +208,10 @@ That's it. Tokens are stored in MongoDB — no `.env` editing required. You can
|
|
|
1. Create `services/{platform}/` with `index.js`, `package.json`, `Dockerfile`
|
|
1. Create `services/{platform}/` with `index.js`, `package.json`, `Dockerfile`
|
|
|
2. Extend `BasePlatformService` and implement `fetchFeed()`, `publishPost()`, `getStatus()`
|
|
2. Extend `BasePlatformService` and implement `fetchFeed()`, `publishPost()`, `getStatus()`
|
|
|
3. Add the service to `docker-compose.yml`
|
|
3. Add the service to `docker-compose.yml`
|
|
|
-4. Add the service URL to `feed-aggregator` and `scheduler` environment variables
|
|
|
|
|
-5. Add platform metadata to `ui/src/stores/platforms.ts`
|
|
|
|
|
|
|
+4. Add the service URL to `feed-aggregator` and `scheduler` environment variables and `PLATFORM_SERVICES` maps
|
|
|
|
|
+5. Add platform metadata to `PLATFORM_META` in `ui/src/stores/platforms.ts`
|
|
|
|
|
+6. Add platform name to the `activePlatforms` default set in `ui/src/stores/feed.ts`
|
|
|
|
|
+7. Add `platforms.{key}` to both locale files (`en.ts`, `tr.ts`)
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
@@ -213,28 +220,36 @@ That's it. Tokens are stored in MongoDB — no `.env` editing required. You can
|
|
|
```
|
|
```
|
|
|
.
|
|
.
|
|
|
├── services/
|
|
├── services/
|
|
|
-│ ├── utils/ # Shared: RabbitMQ, MongoDB, BasePlatformService
|
|
|
|
|
-│ ├── gateway/ # API gateway
|
|
|
|
|
|
|
+│ ├── utils/ # Shared: BasePlatformService, MongoDB, RabbitMQ, logger, crypto
|
|
|
|
|
+│ │ ├── BasePlatformService.js
|
|
|
|
|
+│ │ ├── MongoDBConnector.js
|
|
|
|
|
+│ │ ├── RabbitMQConnector.js
|
|
|
|
|
+│ │ ├── RabbitMQListener.js
|
|
|
|
|
+│ │ ├── RabbitMQProducer.js
|
|
|
|
|
+│ │ ├── logger.js # Pino createLogger(service) factory
|
|
|
|
|
+│ │ └── crypto.js # AES-256-GCM encryptToken / decryptToken
|
|
|
|
|
+│ ├── gateway/ # API gateway (credentials, OAuth, post dispatch, AI, media, drafts)
|
|
|
│ ├── socket/ # WebSocket server
|
|
│ ├── socket/ # WebSocket server
|
|
|
-│ ├── formatter/ # Content formatter
|
|
|
|
|
-│ ├── ai_grammar_correction/
|
|
|
|
|
-│ ├── feed-aggregator/
|
|
|
|
|
-│ ├── scheduler/
|
|
|
|
|
|
|
+│ ├── feed-aggregator/ # Periodic feed polling
|
|
|
|
|
+│ ├── scheduler/ # BullMQ scheduled post worker
|
|
|
│ ├── twitter/
|
|
│ ├── twitter/
|
|
|
│ ├── linkedin/
|
|
│ ├── linkedin/
|
|
|
│ ├── mastodon/
|
|
│ ├── mastodon/
|
|
|
-│ └── bluesky/
|
|
|
|
|
|
|
+│ ├── bluesky/
|
|
|
|
|
+│ ├── instagram/
|
|
|
|
|
+│ └── facebook/
|
|
|
├── ui/
|
|
├── ui/
|
|
|
│ └── src/
|
|
│ └── src/
|
|
|
-│ ├── views/ # Dashboard, Compose, Scheduler, Settings
|
|
|
|
|
|
|
+│ ├── views/ # Dashboard, Compose, Scheduler (+ calendar/drafts), Settings, Media
|
|
|
│ ├── components/
|
|
│ ├── components/
|
|
|
-│ ├── stores/ # Pinia: feed, compose, platforms
|
|
|
|
|
|
|
+│ ├── stores/ # Pinia: feed, compose, platforms, ai
|
|
|
|
|
+│ ├── utils/ # timezone.ts (IANA list + UTC conversion)
|
|
|
│ ├── locales/ # i18n: en, tr
|
|
│ ├── locales/ # i18n: en, tr
|
|
|
│ └── router/
|
|
│ └── router/
|
|
|
-├── docs/ # Architecture, roadmap, platform guides (gitignored)
|
|
|
|
|
├── docker-compose.yml
|
|
├── docker-compose.yml
|
|
|
├── nginx.conf
|
|
├── nginx.conf
|
|
|
-└── .env.example
|
|
|
|
|
|
|
+├── .env.example
|
|
|
|
|
+└── CLAUDE.md # Developer context for AI coding sessions
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
---
|
|
---
|