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>
This commit is contained in:
217
LINKEDIN_SETUP.md
Normal file
217
LINKEDIN_SETUP.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user