[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-74217":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":40,"readmeContent":41,"aiSummary":42,"trendingCount":15,"starSnapshotCount":15,"syncStatus":43,"lastSyncTime":44,"discoverSource":45},74217,"brightbean-studio","brightbeanxyz\u002Fbrightbean-studio","brightbeanxyz","Open-source, self-hostable social media management platform. Schedule, publish, and manage content across 10+ platforms from a single dashboard. Free alternative to Buffer, Sendible, and SocialPilot.","https:\u002F\u002Fbrightbean.xyz\u002F",null,"Python",1802,363,11,0,60,72,148,180,20.68,"GNU Affero General Public License v3.0",false,"main",[25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"agpl","buffer-alternative","content-management","django","docker","htmx","multi-platform","open-source","python","scheduling","self-hosted","social-media","social-media-management","social-media-scheduler","tailwindcss","2026-06-12 02:03:24","\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio\">\n    \u003Cimg src=\".github\u002Fassets\u002Fbrightbean-studio-logo.webp\" alt=\"BrightBean Studio\" width=\"280\">\n  \u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cstrong>Open-source social media management for creators, agencies, and SMBs.\u003C\u002Fstrong>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio\u002Factions\u002Fworkflows\u002Fci.yml\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg\" alt=\"CI\">\u003C\u002Fa>\n  \u003Ca href=\"LICENSE\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-AGPL--3.0-blue.svg\" alt=\"License: AGPL-3.0\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.python.org\u002F\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FPython-3.12%2B-blue.svg\" alt=\"Python 3.12+\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.djangoproject.com\u002F\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDjango-5.x-green.svg\" alt=\"Django 5.x\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n---\n\n## About BrightBean Studio\n\nBrightBean Studio is an open-source, self-hostable social media management platform built for creators, agencies and SMBs. It does what Sendible, SocialPilot, or ContentStudio do, but free and without per-seat, per-channel, or per-workspace limits. Plan, compose, schedule, approve, publish, and monitor content across Facebook, Instagram, LinkedIn, TikTok, YouTube, Pinterest, Threads, Bluesky, Google Business Profile, and Mastodon from a single multi-workspace dashboard.\n\nIt's for people managing many client accounts under one roof who'd rather own their social stack than pay $100–300\u002Fmonth to a SaaS vendor. Every feature is available to every user. No paid tier, no feature gate, no upsell.\n\nYou can deploy it with a one-click button on Heroku, Render, or Railway, run it on your own VPS via Docker, or run it locally. All platform integrations talk directly to the official first-party APIs using your own developer credentials, so there's no aggregator middleman, no vendor lock-in, and no third party sitting between you and your data.\n\n## Features\n\n| | |\n|---|---|\n| **Multi-workspace & teams** | Unlimited orgs → workspaces → members. Granular RBAC with custom roles, invitations, and a separate Client role for external collaborators. |\n| **Content composer** | Rich editor with per-platform caption\u002Fmedia overrides, version history, reusable templates, content categories & tags, a Kanban idea board. |\n| **Calendar & scheduling** | Visual calendar with recurring weekly posting slots per account and named queues that auto-assign posts to the next available slot. |\n| **Publishing engine** | Direct first-party API integrations (no aggregator), automatic retries, per-account rate-limit tracking, and a 90-day publish audit log. |\n| **Approval workflows** | Configurable stages (none \u002F optional \u002F internal \u002F internal + client), threaded internal & external comments, reminders, and a full audit trail. |\n| **Unified social inbox** | Comments, mentions, DMs, and reviews from every connected platform in one place, with sentiment analysis, assignments, threaded replies, and historical backfill. |\n| **Media library** | Org- and workspace-scoped libraries with nested folders, auto-generated platform-optimized variants, and alt text. |\n| **Client portal** | Passwordless 30-day magic-link access so clients can approve or reject posts without creating an account. |\n| **Notifications** | In-app, email, and webhook delivery with per-user preferences for every event type. |\n| **Security & ops** | Encrypted token & credential storage, Google SSO, Sentry support, and a 14-day reversible org-deletion grace period. 2FA (TOTP) is on the roadmap. |\n| **White-label friendly** | Per-workspace branding (logo, colors) and workspace defaults for hashtags, first comments, and posting templates. |\n\n### A quick look\n\n\u003Ctable>\n  \u003Ctr>\n    \u003Ctd width=\"50%\">\u003Cimg src=\".github\u002Fassets\u002FBrightBean%20Studio%20Calendar.webp\" alt=\"Calendar view\">\u003Cbr>\u003Csub>\u003Cb>Visual calendar\u003C\u002Fb> - drag-and-drop scheduling with recurring slots and queues.\u003C\u002Fsub>\u003C\u002Ftd>\n    \u003Ctd width=\"50%\">\u003Cimg src=\".github\u002Fassets\u002FBrightBean%20Studio%20Post%20Editor.webp\" alt=\"Post editor\">\u003Cbr>\u003Csub>\u003Cb>Post editor\u003C\u002Fb> - composer with per-platform overrides and previews.\u003C\u002Fsub>\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd width=\"50%\">\u003Cimg src=\".github\u002Fassets\u002FBrightBean%20Studio%20Idea%20Kanban%20Board.webp\" alt=\"Idea kanban board\">\u003Cbr>\u003Csub>\u003Cb>Idea board\u003C\u002Fb> - Kanban workflow to keep track of all your post ideas.\u003C\u002Fsub>\u003C\u002Ftd>\n    \u003Ctd width=\"50%\">\u003Cimg src=\".github\u002Fassets\u002FBrightBean%20Social%20Media%20Platforms.webp\" alt=\"Connected platforms\">\u003Cbr>\u003Csub>\u003Cb>Connect anything\u003C\u002Fb> - 10+ first-party integrations, no aggregator.\u003C\u002Fsub>\u003C\u002Ftd>\n  \u003C\u002Ftr>\n\u003C\u002Ftable>\n\n## Supported Platforms\n\n| Platform | Publish | Comments | DMs | Insights |\n|---|:---:|:---:|:---:|:---:|\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Ffacebook\" width=\"16\" height=\"16\"> Facebook | ✓ | ✓ | ✓ | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Finstagram\" width=\"16\" height=\"16\"> Instagram | ✓ | ✓ | ✓ | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Finstagram\" width=\"16\" height=\"16\"> Instagram (Direct) | ✓ | ✓ | ✓ | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fapi.iconify.design\u002Flogos\u002Flinkedin-icon.svg\" width=\"16\" height=\"16\"> LinkedIn (Personal) | ✓ | ✓ | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fapi.iconify.design\u002Flogos\u002Flinkedin-icon.svg\" width=\"16\" height=\"16\"> LinkedIn (Company) | ✓ | ✓ | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Ftiktok\" width=\"16\" height=\"16\"> TikTok | ✓ | — | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Fyoutube\" width=\"16\" height=\"16\"> YouTube | ✓ | ✓ | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Fpinterest\" width=\"16\" height=\"16\"> Pinterest | ✓ | — | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Fthreads\" width=\"16\" height=\"16\"> Threads | ✓ | ✓ | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Fbluesky\" width=\"16\" height=\"16\"> Bluesky | ✓ | ✓ | — | — |\n| \u003Cimg src=\"https:\u002F\u002Fapi.iconify.design\u002Flogos\u002Fgoogle-icon.svg\" width=\"16\" height=\"16\"> Google Business Profile | ✓ | — | — | ✓ |\n| \u003Cimg src=\"https:\u002F\u002Fcdn.simpleicons.org\u002Fmastodon\" width=\"16\" height=\"16\"> Mastodon | ✓ | ✓ | — | — |\n\n---\n\n### One-Click Deploy\n\n| Heroku | Render | Railway |\n|:------:|:------:|:-------:|\n| [![Deploy to Heroku](https:\u002F\u002Fwww.herokucdn.com\u002Fdeploy\u002Fbutton.svg)](https:\u002F\u002Fheroku.com\u002Fdeploy?template=https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio) | [![Deploy to Render](https:\u002F\u002Frender.com\u002Fimages\u002Fdeploy-to-render-button.svg)](https:\u002F\u002Frender.com\u002Fdeploy?repo=https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio) | [![Deploy on Railway](https:\u002F\u002Frailway.com\u002Fbutton.svg)](https:\u002F\u002Frailway.com\u002Fdeploy\u002Fbrightbean-studio?referralCode=brightbean) |\n\nAfter deploying, set these environment variables in your platform's dashboard:\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `DJANGO_SETTINGS_MODULE` | Auto-set | `config.settings.production`. Set if deployment config has not placed it. |\n| `SECRET_KEY` | Auto-generated | Django secret key. Set automatically by the deploy button. |\n| `ENCRYPTION_KEY_SALT` | Auto-generated | Encryption salt. Set automatically by the deploy button. |\n| `DATABASE_URL` | Auto-provisioned | PostgreSQL connection string. Set automatically. |\n| `ALLOWED_HOSTS` | Yes | Your app's domain, e.g. `your-app.herokuapp.com` |\n| `APP_URL` | Yes | Full public URL, e.g. `https:\u002F\u002Fyour-app.herokuapp.com` |\n| `STORAGE_BACKEND` | No | Set to `s3` for S3\u002FR2 storage. Default: `local`. Heroku, Render, and Railway have ephemeral filesystems, so uploaded files are lost on redeploy without S3. |\n| `S3_ENDPOINT_URL` | If using S3 | S3-compatible endpoint URL |\n| `S3_ACCESS_KEY_ID` | If using S3 | S3 access key |\n| `S3_SECRET_ACCESS_KEY` | If using S3 | S3 secret key |\n| `S3_BUCKET_NAME` | If using S3 | S3 bucket name |\n| `EMAIL_HOST` | No | SMTP server for sending invitations and password resets |\n| `EMAIL_PORT` | No | SMTP port (default: `587`) |\n| `EMAIL_HOST_USER` | No | SMTP username |\n| `EMAIL_HOST_PASSWORD` | No | SMTP password |\n| `GOOGLE_AUTH_CLIENT_ID` | No | For Google OAuth login. Get from [Google Cloud Console](https:\u002F\u002Fconsole.cloud.google.com\u002F) → Credentials. |\n| `GOOGLE_AUTH_CLIENT_SECRET` | No | Google OAuth secret |\n\nFor social media API keys, see [Platform Credentials](#platform-credentials). Full variable reference: `.env.example`.\n\n## Quick Start (Docker)\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio.git\ncd brightbean-studio\ncp .env.example .env\n```\n\nEdit `.env` - change `DATABASE_URL` to point to the Docker service name:\n\n```\nDATABASE_URL=postgres:\u002F\u002Fpostgres:postgres@postgres:5432\u002Fbrightbean\n```\n\nThen start everything:\n\n```bash\ndocker compose up -d --build\ndocker compose exec app python manage.py migrate\ndocker compose exec app python manage.py createsuperuser\n```\n\nTailwind compiles automatically via the `tailwind` Compose service. First build\ntakes ~60–90 seconds (running `npm install` in a fresh container); subsequent\nstarts are instant. Watch progress with `docker compose logs -f tailwind`.\n\nOpen http:\u002F\u002Flocalhost:8000 - you're running.\n\n\n## Fully Local Development (without Docker)\n\nRun everything natively - no Docker, no PostgreSQL install. Uses SQLite for the database.\n\n### Prerequisites\n\n- Python 3.12+\n- Node.js 20+\n\n### Setup\n\n**1. Clone and configure**\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio.git\ncd brightbean-studio\ncp .env.example .env\n```\n\n**2. Switch to SQLite**\n\nOpen `.env` and replace the `DATABASE_URL` line:\n\n```\nDATABASE_URL=sqlite:\u002F\u002F\u002Fdb.sqlite3\n```\n\nThat's it - no database server to install or manage.\n\n**3. Set up Python**\n\n```bash\npython3 -m venv .venv\nsource .venv\u002Fbin\u002Factivate\npip install -r requirements.txt\n```\n\n**4. Set up Tailwind CSS**\n\n```bash\ncd theme\u002Fstatic_src\nnpm install\ncd ..\u002F..\n```\n\n**5. Run database migrations**\n\n```bash\npython manage.py migrate\n```\n\n**6. Create your admin account**\n\n```bash\npython manage.py createsuperuser\n```\n\n**7. Start the app (3 terminal tabs)**\n\nTab 1 - Tailwind watcher:\n```bash\ncd theme\u002Fstatic_src && npm run start\n```\n\nTab 2 - Django dev server:\n```bash\nsource .venv\u002Fbin\u002Factivate\npython manage.py runserver\n```\n\nTab 3 - Background worker:\n```bash\nsource .venv\u002Fbin\u002Factivate\npython manage.py process_tasks\n```\n\nOpen http:\u002F\u002Flocalhost:8000 and log in with the superuser you created.\n\n### Daily workflow (Docker-free)\n\n```bash\nsource .venv\u002Fbin\u002Factivate                # activate Python env\npython manage.py runserver               # start web server\n# (open another tab)\npython manage.py process_tasks           # start worker\n```\n\n> **Note:** SQLite is fine for local development and small deployments. For production or heavy concurrent usage, switch to PostgreSQL.\n\n## Running Tests\n\n```bash\npytest\n```\n\nWith coverage:\n\n```bash\npytest --cov=apps --cov-report=term-missing\n```\n\n## Linting & Type Checking\n\n```bash\nruff check .                             # lint\nruff format --check .                    # format check\nmypy apps\u002F config\u002F --ignore-missing-imports  # type check\n```\n\nAuto-fix lint issues:\n\n```bash\nruff check --fix .\nruff format .\n```\n\n## Production Deployment\n\n### Docker Compose on a VPS (recommended)\n\n```bash\n# On your server:\ngit clone https:\u002F\u002Fgithub.com\u002Fbrightbeanxyz\u002Fbrightbean-studio.git\ncd brightbean-studio\ncp .env.example .env\n# Edit .env:\n#   SECRET_KEY=\u003Cgenerate a random 50+ char string>\n#   DEBUG=false\n#   ALLOWED_HOSTS=yourdomain.com\n#   APP_URL=https:\u002F\u002Fyourdomain.com\n#   DATABASE_URL=postgres:\u002F\u002Fpostgres:\u003Cstrong-password>@postgres:5432\u002Fbrightbean\n\ndocker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build\ndocker compose exec app python manage.py createsuperuser\n```\n\nThis starts 5 containers: app (Gunicorn), worker, PostgreSQL, Caddy (auto-HTTPS), and a one-shot migrate container that runs database migrations automatically on startup. Edit the `Caddyfile` with your domain.\n\nTo update:\n\n```bash\ngit pull\ndocker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build\n```\n\n### Other Platforms\n\n| Platform | Config file | Notes |\n|----------|-------------|-------|\n| **Heroku** | `Procfile` + `app.json` | Deploy-button ready. Must use Basic+ dynos (Eco dynos break the worker). |\n| **Railway** | `railway.toml` | Three services: web, worker, managed PostgreSQL. |\n| **Render** | `render.yaml` | Blueprint with web, worker, PostgreSQL. Must use paid tier. |\n\nAll platforms with ephemeral filesystems require `STORAGE_BACKEND=s3` - see `.env.example` for S3 configuration.\n\nSee `architecture.md` for detailed per-platform instructions and cost breakdowns.\n\n## Project Structure\n\n```\nbrightbean-studio\u002F\n├── config\u002F\n│   ├── settings\u002F\n│   │   ├── base.py            # Shared settings\n│   │   ├── development.py     # Local dev overrides\n│   │   ├── production.py      # Production hardening\n│   │   └── test.py            # Test overrides\n│   ├── urls.py                # Root URL configuration\n│   ├── wsgi.py\n│   └── asgi.py\n├── apps\u002F\n│   ├── accounts\u002F              # Custom User model, auth, OAuth, sessions\n│   ├── organizations\u002F         # Organization management\n│   ├── workspaces\u002F            # Workspace CRUD\n│   ├── members\u002F               # RBAC, invitations, middleware, decorators\n│   ├── settings_manager\u002F      # Configurable defaults with cascade logic\n│   ├── credentials\u002F           # Platform API credential storage (encrypted)\n│   └── common\u002F                # Shared: encrypted fields, scoped model managers\n├── providers\u002F                 # Social platform API modules (one file per platform)\n├── templates\u002F                 # Django templates\n│   ├── base.html              # Layout with sidebar + nav\n│   └── components\u002F            # Reusable HTMX partials\n├── static\u002F\n│   └── js\u002F                    # Vendored HTMX + Alpine.js\n├── theme\u002F                     # django-tailwind theme app\n│   └── static_src\u002F\n│       ├── src\u002Fstyles.css     # Tailwind directives\n│       └── tailwind.config.js\n├── Dockerfile\n├── docker-compose.yml         # Dev: app + worker + postgres\n├── docker-compose.prod.yml    # Prod override: adds Caddy, uses Gunicorn\n├── Caddyfile                  # Reverse proxy + auto-HTTPS config\n├── .env.example               # All environment variables\n├── Procfile                   # Heroku\n├── app.json                   # Heroku deploy button\n├── railway.toml               # Railway config\n└── render.yaml                # Render blueprint\n```\n\n> **Settings selection:** The `DJANGO_SETTINGS_MODULE` environment variable controls which settings file Django uses. The defaults are already wired for each context: `manage.py` uses `development`, `wsgi.py`\u002F`asgi.py` use `production`, and `pytest` uses `test` (via `pyproject.toml`). Docker Compose files and platform deploy configs (Heroku, Render) also set it explicitly. You only need to override it manually if you want a non-default module for a specific command, e.g. `DJANGO_SETTINGS_MODULE=config.settings.production python manage.py check --deploy`.\n\n## Platform Credentials\n\nTo connect social media accounts, you need API credentials from each platform's developer portal. You can set these via environment variables in `.env` (see `.env.example`) or through the admin UI at **Settings → Platform Credentials**.\n\n**Redirect URI:** When registering your app on any platform, set the OAuth redirect URI to:\n\n```\n{APP_URL}\u002Fsocial-accounts\u002Fcallback\u002F{platform}\u002F\n```\n\nFor example, if your `APP_URL` is `https:\u002F\u002Fbrightbean.example.com`, the Facebook redirect URI would be `https:\u002F\u002Fbrightbean.example.com\u002Fsocial-accounts\u002Fcallback\u002Ffacebook\u002F`.\n\n### Meta (Facebook, Instagram, Threads)\n\nFacebook, Instagram, and Threads all use the same Meta app credentials.\n\n1. Go to [Meta for Developers](https:\u002F\u002Fdevelopers.facebook.com\u002F) and create a new app (type: **Business**)\n2. Under **App Settings → Basic**, copy your **App ID** and **App Secret**\n3. In the App Dashboard, go to **Use cases** and add the following four use cases. For each use case, click into it and go to **Permissions and features** to add the required optional permissions:\n\n   **Use case: \"Manage everything on your Page\"** (Facebook)\n   - This use case auto-includes `business_management`, `pages_show_list`, and `public_profile`\n   - Add these optional permissions: `pages_manage_posts`, `pages_read_engagement`, `pages_read_user_content`, `pages_manage_metadata`\n\n   **Use case: \"Messenger from Meta\"** (Facebook Messaging)\n   - Required to enable the `pages_messaging` permission, which is not available under the \"Manage Pages\" use case\n   - Add the optional permission: `pages_messaging`\n\n   **Use case: \"Manage messaging & content on Instagram\"** (Instagram)\n   - Add these permissions: `instagram_basic`, `instagram_content_publish`, `instagram_manage_comments`, `instagram_manage_insights`\n\n   **Use case: \"Access the Threads API\"** (Threads)\n   - This use case auto-includes `threads_basic`\n   - Add these optional permissions: `threads_content_publish`, `threads_manage_insights`, `threads_manage_replies`\n\n4. Under **Facebook Login → Settings → Valid OAuth Redirect URIs**, add the following redirect URIs:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Ffacebook\u002F\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Finstagram\u002F\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Fthreads\u002F\n   ```\n5. Set the environment variables:\n   ```\n   PLATFORM_FACEBOOK_APP_ID=your-app-id\n   PLATFORM_FACEBOOK_APP_SECRET=your-app-secret\n   ```\n\n### Instagram (Direct, via Instagram Login)\n\nThe Instagram (Direct) connector uses the **Instagram API with Instagram Login** - a separate OAuth flow from the Facebook Login-based Instagram connector above. It works with **Professional** Instagram accounts (Business or Creator) **without** requiring a linked Facebook Page.\n\n> **Account-type requirement:** Personal Instagram accounts have no API access since the Instagram Basic Display API was retired on 2024-12-04. Users must convert their account to Professional first (free, in IG Settings → *Account type and tools* → *Switch to professional account*).\n\n1. In the same Meta app, go to **Use cases** and add the **\"Instagram API\"** use case\n2. Under **API setup with Instagram Login**, note your **Instagram App ID** and **Instagram App Secret** (these are different from your Facebook App ID\u002FSecret)\n3. Go to **Permissions and features** and add the required permissions:\n   - `instagram_business_basic`, `instagram_business_content_publish`, `instagram_business_manage_comments`, `instagram_business_manage_messages`\n4. Under **API setup with Instagram Login → Step 4: Set up Instagram business login**, click **Set up** and add the redirect URI (must match exactly, including the trailing slash):\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Finstagram_login\u002F\n   ```\n5. Under **API setup with Instagram Login → Step 3: Configure webhooks**, set:\n   - **Callback URL:** `{APP_URL}\u002Fwebhooks\u002Finstagram_login\u002F`\n   - **Verify token:** the value of `INSTAGRAM_LOGIN_WEBHOOK_VERIFY_TOKEN` from your `.env` (any random string; generate one and set the env var before clicking Verify and save). After verification, subscribe to the `messages`, `comments`, and `mentions` fields.\n6. Set the environment variables:\n   ```\n   PLATFORM_INSTAGRAM_APP_ID=your-instagram-app-id\n   PLATFORM_INSTAGRAM_APP_SECRET=your-instagram-app-secret\n   INSTAGRAM_LOGIN_WEBHOOK_VERIFY_TOKEN=your-random-verify-token\n   ```\n\n### LinkedIn\n\nBrightbean Studio supports two LinkedIn paths. Pick whichever your LinkedIn dev app can obtain - or both, on separate apps.\n\n**Path A - Personal-only (any individual developer can do this):**\n\n1. Go to the [LinkedIn Developer Portal](https:\u002F\u002Fdeveloper.linkedin.com\u002F) and create a new app (no Company Page verification required).\n2. Under **Products**, request access to (both auto-approved):\n   - **Sign In with LinkedIn using OpenID Connect**\n   - **Share on LinkedIn**\n3. Under **Auth**, add the redirect URI:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Flinkedin_personal\u002F\n   ```\n4. Scopes: `openid`, `profile`, `email`, `w_member_social`.\n5. Set the environment variables:\n   ```\n   PLATFORM_LINKEDIN_PERSONAL_CLIENT_ID=your-client-id\n   PLATFORM_LINKEDIN_PERSONAL_CLIENT_SECRET=your-client-secret\n   ```\n\n> **Limitations of Path A:** access tokens last ~60 days and LinkedIn does not issue refresh tokens for these scopes - users must manually reconnect every ~60 days. Inbox \u002F comment-reading is not available for personal accounts on this path.\n\n**Path B - Company Pages (also enables full Personal features):**\n\n1. Go to the [LinkedIn Developer Portal](https:\u002F\u002Fdeveloper.linkedin.com\u002F) and create a new app.\n2. Verify the app's association with a LinkedIn Company Page.\n3. Under **Products**, request access to:\n   - **Community Management API** *(restricted - requires LinkedIn review)*\n4. Under **Auth**, add **both** redirect URIs:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Flinkedin_personal\u002F\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Flinkedin_company\u002F\n   ```\n5. Scopes:\n   - **Personal:** `r_basicprofile`, `w_member_social`, `r_member_social`\n   - **Company:** `r_basicprofile`, `w_member_social`, `w_organization_social`, `r_organization_social`, `rw_organization_admin`\n6. Set the environment variables:\n   ```\n   PLATFORM_LINKEDIN_COMPANY_CLIENT_ID=your-client-id\n   PLATFORM_LINKEDIN_COMPANY_CLIENT_SECRET=your-client-secret\n   ```\n\nIf you set only the Path B (Company) credentials, Brightbean Studio automatically reuses them for personal connections too - refresh tokens (365-day) and inbox both work. You only need Path A vars if you have a separate Personal-only app.\n\n> **Note:** \"Sign In with LinkedIn using OpenID Connect\" \u002F \"Share on LinkedIn\" and \"Community Management API\" are **mutually exclusive** on a single LinkedIn app. You need separate apps for Path A and Path B.\n\n> **Backwards compatibility:** the legacy `PLATFORM_LINKEDIN_CLIENT_ID` \u002F `PLATFORM_LINKEDIN_CLIENT_SECRET` env vars are still honored as a fallback for both `linkedin_personal` and `linkedin_company` - existing self-hosters keep working without changes. The legacy credentials are assumed to be CM-approved; if your legacy app is OIDC-only, migrate it to `PLATFORM_LINKEDIN_PERSONAL_*`.\n\n### TikTok\n\n1. Go to the [TikTok Developer Portal](https:\u002F\u002Fdevelopers.tiktok.com\u002F) and create a new app\n2. Add the products **Login Kit** and **Content Posting API**\n3. Configure the redirect URI under your app's settings:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Ftiktok\u002F\n   ```\n4. Required scopes: `user.info.basic`, `video.publish`, `video.upload`\n5. Note: TikTok uses **Client Key** (not Client ID). Copy the **Client Key** and **Client Secret** from your app dashboard\n6. Set the environment variables:\n   ```\n   PLATFORM_TIKTOK_CLIENT_KEY=your-client-key\n   PLATFORM_TIKTOK_CLIENT_SECRET=your-client-secret\n   ```\n\n### Google (YouTube, Google Business Profile)\n\nYouTube and Google Business Profile share the same Google Cloud credentials.\n\n1. Go to the [Google Cloud Console](https:\u002F\u002Fconsole.cloud.google.com\u002F) and create a new project (or select an existing one)\n2. Enable the following APIs under **APIs & Services → Library**:\n   - **YouTube Data API v3** (for YouTube)\n   - **My Business Account Management API**, **My Business Business Information API**, and **Google My Business API** (for Google Business Profile)\n3. Go to **APIs & Services → Credentials** and create an **OAuth 2.0 Client ID** (type: Web application)\n4. Add the following redirect URIs under **Authorized redirect URIs**:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Fyoutube\u002F\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Fgoogle_business\u002F\n   ```\n5. Copy the **Client ID** and **Client Secret**\n6. Required scopes:\n   - **YouTube:** `https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fyoutube.upload`, `https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fyoutube.readonly`, `https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fyoutube.force-ssl`\n   - **Google Business Profile:** `https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fbusiness.manage`\n7. Set the environment variables:\n   ```\n   PLATFORM_GOOGLE_CLIENT_ID=your-client-id\n   PLATFORM_GOOGLE_CLIENT_SECRET=your-client-secret\n   ```\n\n### Pinterest\n\n1. Go to the [Pinterest Developer Portal](https:\u002F\u002Fdevelopers.pinterest.com\u002F) and create a new app\n2. Under your app settings, add the redirect URI:\n   ```\n   {APP_URL}\u002Fsocial-accounts\u002Fcallback\u002Fpinterest\u002F\n   ```\n3. Copy the **App ID** and **App Secret**\n4. Required scopes: `boards:read`, `pins:read`, `pins:write`\n5. Set the environment variables:\n   ```\n   PLATFORM_PINTEREST_APP_ID=your-app-id\n   PLATFORM_PINTEREST_APP_SECRET=your-app-secret\n   ```\n\n### Bluesky\n\nNo developer app registration needed. Users connect by entering their Bluesky handle and an **App Password**:\n\n1. Log in to [Bluesky](https:\u002F\u002Fbsky.app\u002F)\n2. Go to **Settings → Privacy and Security → App Passwords**\n3. Create a new app password and use it when connecting your account in Brightbean Studio\n\n### Mastodon\n\nNo developer app registration needed. Brightbean Studio automatically registers an OAuth application on each Mastodon instance when a user connects their account. Users just need to enter their instance URL (e.g., `mastodon.social`).\n\n## Inbox: Backfill Historical Messages\n\nSee the [Supported Platforms](#supported-platforms) matrix above for per-platform inbox capabilities.\n\nTo import historical messages (e.g., from the last 7 days):\n\n```bash\npython manage.py backfill_inbox --days 7\n```\n\nOptions:\n- `--days N` - Number of days to backfill (default: 7)\n- `--platform NAME` - Only backfill a specific platform (e.g., `youtube`, `linkedin`, `tiktok`)\n- `--account-id UUID` - Only backfill a specific account\n\n---\n\n## Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| Backend | Django 5.x |\n| Frontend | Django templates, HTMX, Alpine.js |\n| CSS | Tailwind CSS 4 via django-tailwind |\n| Database | PostgreSQL 16+ |\n| Background jobs | django-background-tasks (no Redis required) |\n| Auth | django-allauth (email + Google OAuth) |\n| Media | Pillow (images), FFmpeg (video) |\n| Deployment | Docker, Gunicorn, Caddy |\n\n---\n\n## Troubleshooting\n\n**Docker: `postgres` container is unhealthy**\nWait 10-15 seconds after `docker compose up` for the health check to pass, then retry your command. Check logs with `docker compose logs postgres`.\n\n**`python manage.py migrate` fails with connection errors**\nMake sure PostgreSQL is running and healthy. For Docker: `docker compose ps` should show postgres as \"healthy\". For local: verify the `DATABASE_URL` in `.env` matches your setup.\n\n**Tailwind CSS changes not appearing**\nMake sure the Tailwind watcher is running: `cd theme\u002Fstatic_src && npm run start`. If styles still don't update, try `npm run build` for a full rebuild.\n\n**OAuth callback errors (\"redirect URI mismatch\")**\nThe redirect URI registered on the platform must exactly match `{APP_URL}\u002Fsocial-accounts\u002Fcallback\u002F{platform}\u002F`. Check that `APP_URL` in `.env` matches the URL you're accessing (including `http` vs `https` and port number).\n\n**Background tasks not running (posts not publishing)**\nMake sure the worker is running: `python manage.py process_tasks`. In Docker: check `docker compose logs worker`.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding guidelines, and how to submit pull requests.\n\n## Security\n\nTo report a security vulnerability, see [SECURITY.md](SECURITY.md). Do not open a public issue.\n\n## License\n\n[AGPL-3.0](LICENSE) - see LICENSE for details.\n","BrightBean Studio 是一个开源的、可自托管的社交媒体管理平台，专为创作者、代理机构和中小企业设计。它支持从单一控制面板安排、发布和管理超过10个平台上的内容，包括Facebook、Instagram、LinkedIn等，提供了与Buffer、Sendible和SocialPilot类似的功能但完全免费。该平台基于Python构建，并使用Django框架，支持通过Docker容器化部署，确保了跨平台兼容性和易于维护性。其核心功能涵盖多工作区管理、内容创作与排期、审批流程及统一社交收件箱等，特别适合需要同时管理多个客户账户且希望拥有自己社交技术栈而非依赖昂贵SaaS解决方案的专业人士或团队使用。",2,"2026-06-11 03:49:32","high_star"]