# 01 — Social Publishing Overview (Auto + Manual)

Target: publish **photos** and **videos** to Facebook and LinkedIn destinations, both **automatically** (schedule) and **manually** (human trigger).

---

## 1. Current vs target destinations

| Destination | Today | Target |
|-------------|-------|--------|
| Facebook **Page** | Live (photo / text) | Live + **video feed** |
| Facebook **personal profile** | Not supported | Product decision — usually **not available** via Meta Graph for 3rd parties |
| Instagram Business (via Page) | Live (single image) | Keep; video/Reels = later phase |
| LinkedIn **member profile** | Live (text + image) | + video when scopes/API ready |
| LinkedIn **Company Page** | Not supported | **Required** — `w_organization_social` + org URN author |
| YouTube | Live (MP4 if FFmpeg) | Keep as video sink |

Evidence today:

- Facebook Page: `src/lib/social/facebook-publish.ts`, `meta-oauth.ts` (`/me/accounts`)
- LinkedIn person: `linkedin-publish.ts` (`author: urn:li:person:…`, scope `w_member_social`)
- Shared core: `publish-post.ts`
- Manual: `POST /api/generation/posts/[id]/publish`
- Auto: `run-scheduled-publish.ts` + cron poller

---

## 2. Two posting modes

### 2.1 Manual

**User intent:** “I have a photo/video (or AI-generated asset) — post it now to selected destinations.”

```
Upload / select media + caption (AI optional via RAG)
  → Choose destinations:
       [FB Page A] [LI Profile] [LI Company Page B]
  → Optional preview
  → Publish now
  → Per-destination success / permalink / error
```

UI anchors today: Live Generation + `QuickPublishPanel`, Post Review.  
Extend with: destination multi-select (Page vs Company Page), media type picker (photo/video).

### 2.2 Automatic

**User intent:** “Every morning/evening, generate (or take queued draft) and publish without me clicking.”

```
Smart Schedule slots (1–2 / day)
  + Automation rules (loop-sequence, high-score, smart-timing)
  → cron-poller / CRON_SECRET endpoint
  → claim slot (idempotent)
  → generate or pick queued draft
  → publish to all connected *active* destinations
  → log + stats
```

**Product recommendation:** add `require_approval_before_auto_publish` for enterprise (today loop-sequence can skip human approve).

---

## 3. Media types

| Media | Manual | Auto | Notes |
|-------|--------|------|-------|
| Photo (single image) | Yes (today LI/FB/IG) | Yes | Primary path |
| Video (MP4) | Target FB Page + LI | Target | YT already; FB Graph video upload; LI video UGC |
| Carousel | Later | Later | Not in scope of this doc phase |
| Stories / Reels | Later | Later | Different APIs |

User-supplied media (manual upload) should land in `media_assets` / `data/media/` and be referenced by `GeneratedPost.imageUrl` / `videoUrl`.

---

## 4. Unified publish request (target contract)

```ts
type PublishDestination =
  | { network: "facebook"; target: "page"; externalId: string }
  | { network: "facebook"; target: "user" } // only if ever supported
  | { network: "linkedin"; target: "member" }
  | { network: "linkedin"; target: "organization"; externalId: string };

type PublishRequest = {
  postId: string;
  projectId: string;
  userId: string;
  destinations: PublishDestination[];
  media: { type: "image" | "video" | "text"; url?: string };
  caption: string;
  mode: "manual" | "auto";
};
```

One orchestrator: extend `publish-post.ts` to branch on `target`, not only `platform`.

---

## 5. Connection model (accounts)

Store **multiple destinations per project**:

| Field | Meaning |
|-------|---------|
| `platform` | `facebook` \| `linkedin` \| … |
| `targetType` | `page` \| `member` \| `organization` \| `user` |
| `externalId` | Page ID / person URN / org URN |
| `label` | Display name |
| `publishToken` | Page token or member token (encrypt!) |
| `status` | connected / expired / disconnected |

Today `ConnectedAccount` is flatter; add `targetType` in a migration.

---

## 6. Error handling (global best practice)

| Case | Behavior |
|------|----------|
| Token expired | Refresh or mark destination failed; continue others |
| One network fails | Partial success; surface per-destination errors |
| Duplicate slot | Lock / `schedule_slot_fires` prevents double post |
| Video too large | Preflight validate size/codec; fail fast |
| Policy rejection | Store platform error message on post |

---

## 7. Related docs

- [02-FACEBOOK.md](./02-FACEBOOK.md)
- [03-LINKEDIN.md](./03-LINKEDIN.md)
- [../architecture/02-GLOBAL-REVIEW.md](../architecture/02-GLOBAL-REVIEW.md)
