# 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
