Files
Onyva-Postling/LINKEDIN_SETUP.md
Ruben Fischer f14515e9cf Major updates: LinkedIn auto-posting, timezone fixes, and Docker improvements
Features:
- Add LinkedIn OAuth integration and auto-posting functionality
- Add scheduler service for automated post publishing
- Add metadata field to generated_posts for LinkedIn URLs
- Add privacy policy page for LinkedIn API compliance
- Add company management features and employee accounts
- Add license key system for company registrations

Fixes:
- Fix timezone issues (use UTC consistently across app)
- Fix datetime serialization errors in database operations
- Fix scheduling timezone conversion (local time to UTC)
- Fix import errors (get_database -> db)

Infrastructure:
- Update Docker setup to use port 8001 (avoid conflicts)
- Add SSL support with nginx-proxy and Let's Encrypt
- Add LinkedIn setup documentation
- Add migration scripts for schema updates

Services:
- Add linkedin_service.py for LinkedIn API integration
- Add scheduler_service.py for background job processing
- Add storage_service.py for Supabase Storage
- Add email_service.py improvements
- Add encryption utilities for token storage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 11:30:20 +01:00

218 lines
6.0 KiB
Markdown

# LinkedIn Auto-Posting Setup Guide
This guide walks you through setting up the LinkedIn auto-posting feature.
## Overview
Employees can link their LinkedIn accounts to automatically post scheduled content directly to LinkedIn, eliminating manual copy-paste work.
## Prerequisites
1. A LinkedIn Developer account
2. Access to your server's environment variables
3. HTTPS domain (required for OAuth)
## Step 1: Create LinkedIn App
1. Go to [LinkedIn Developers](https://www.linkedin.com/developers/apps)
2. Click "Create app"
3. Fill in app details:
- **App name**: Your app name (e.g., "LinkedInWorkflow Auto-Poster")
- **LinkedIn Page**: Select your company page
- **App logo**: Upload a logo (optional)
4. Check the agreement and create the app
## Step 2: Configure OAuth Settings
1. In your app dashboard, go to the **Auth** tab
2. Add OAuth 2.0 redirect URLs:
```
https://yourdomain.com/settings/linkedin/callback
```
3. Request the following **OAuth 2.0 scopes**:
- `openid` - For user identity
- `profile` - For user profile data
- `email` - For user email
- `w_member_social` - **CRITICAL** - For posting on user's behalf
Note: `w_member_social` requires app review by LinkedIn. Submit for review if not already approved.
4. Note your **Client ID** and **Client Secret** (found in Auth tab)
## Step 3: Generate Encryption Key
Run the helper script to generate a secure encryption key:
```bash
python scripts/generate_encryption_key.py
```
Copy the generated key for the next step.
## Step 4: Configure Environment Variables
Add these variables to your `.env` file:
```env
# LinkedIn API (Custom OAuth for auto-posting)
LINKEDIN_CLIENT_ID=your_client_id_here
LINKEDIN_CLIENT_SECRET=your_client_secret_here
LINKEDIN_REDIRECT_URI=https://yourdomain.com/settings/linkedin/callback
# Token Encryption
ENCRYPTION_KEY=your_generated_fernet_key_here
```
⚠️ **Security**: Never commit these values to git! Keep them secure.
## Step 5: Run Database Migration
Apply the database migration to create the `linkedin_accounts` table:
```bash
# Using psql
psql $DATABASE_URL -f config/migrate_add_linkedin_accounts.sql
# Or via Supabase dashboard SQL editor
# Copy and paste the contents of config/migrate_add_linkedin_accounts.sql
```
## Step 6: Install Dependencies
Install the new dependencies:
```bash
pip install -r requirements.txt
```
## Step 7: Restart Application
Restart your application to load the new environment variables:
```bash
# If using systemd
sudo systemctl restart linkedinworkflow
# If using docker
docker-compose restart
# If running directly
# Stop the current process and restart
```
## Step 8: Test the Integration
1. Log in as an employee user
2. Go to **Settings** (`/settings`)
3. Click **"Mit LinkedIn verbinden"**
4. Complete the LinkedIn OAuth flow
5. Verify the account shows as connected
6. Schedule a test post
7. Wait for the scheduled time (or manually trigger the scheduler)
8. Verify the post appears on LinkedIn
## Troubleshooting
### OAuth Errors
**"Invalid redirect_uri"**
- Make sure the redirect URI in your .env matches exactly with the one configured in LinkedIn app settings
- Include the protocol (`https://`) and no trailing slash
**"Insufficient permissions"**
- Ensure `w_member_social` scope is requested and approved
- Some scopes require LinkedIn app review
### Token Errors
**"Token expired"**
- LinkedIn tokens typically last 60 days
- The system will attempt to refresh automatically
- If refresh fails, user needs to reconnect
**"Encryption error"**
- Verify `ENCRYPTION_KEY` is set in environment
- Never change the encryption key after storing tokens (or all tokens become unreadable)
### Posting Errors
**"Rate limit exceeded"**
- LinkedIn has rate limits on posting
- The system will fall back to email notification
- Wait before retrying
**"Image upload failed"**
- Check that the image URL is publicly accessible
- Supabase storage URLs must be publicly readable
- System will post without image if upload fails
## Rate Limits
LinkedIn API has the following rate limits (as of 2024):
- **Posts**: ~100 per day per user
- **API calls**: Varies by endpoint
Plan your posting schedule accordingly.
## Security Best Practices
1. **Never log tokens**: Tokens are encrypted at rest and should never be logged in plaintext
2. **HTTPS only**: OAuth requires HTTPS in production
3. **Secure cookies**: Session cookies use httponly, secure, and samesite flags
4. **Token rotation**: Encourage users to reconnect periodically
5. **Audit logging**: Monitor for suspicious activity in `linkedin_accounts.last_error`
## Architecture
```
┌─────────────────┐
│ Employee │
│ (Settings Page) │
└────────┬────────┘
│ 1. OAuth Flow
┌─────────────────────────┐
│ linkedin_accounts table │
│ (encrypted tokens) │
└────────┬────────────────┘
│ 2. Scheduler checks
┌─────────────────────────┐
│ LinkedIn API Service │
│ (UGC Posts API) │
└─────────────────────────┘
```
## Monitoring
Key metrics to monitor:
- **Token expiry**: Check `linkedin_accounts.token_expires_at`
- **API errors**: Check `linkedin_accounts.last_error`
- **Success rate**: Compare scheduled posts vs. published posts
- **Fallback rate**: How often email fallback is used
Query to check accounts needing attention:
```sql
SELECT
user_id,
linkedin_name,
last_error,
last_error_at,
token_expires_at
FROM linkedin_accounts
WHERE
(last_error IS NOT NULL OR token_expires_at < NOW() + INTERVAL '7 days')
AND is_active = true;
```
## Support
For issues or questions:
1. Check logs for detailed error messages
2. Review LinkedIn API documentation
3. Verify environment configuration
4. Test with a single user account first