# Social publishing — production architecture

## Capability registry

Single source of truth: `src/lib/social/config/platform-registry.ts`

Consumed by:

- Env enable/disable reports (`social-config.ts`)
- Client catalog (`platforms.ts`)
- Platform status API
- Publish destination defaults
- Connected Accounts UI (via status API)

## Publish flow

```text
Publish API / scheduler
        ↓
ensureFreshAccountTokens (LinkedIn / Meta / YouTube refresh)
        ↓
createPublishJob → QUEUED → PROCESSING  (data/publish-jobs/*.json)
        ↓
publishPostToPlatforms (per platform, isolated failures)
        ↓
withPublishRetry (env-configurable; default 1 attempt for sync HTTP)
        ↓
Audit log (logs/social-audit-YYYY-MM-DD.log)
        ↓
Job status: PUBLISHED | PARTIALLY_PUBLISHED | FAILED
```

One platform failure never aborts other platforms.

## Retry

Env:

- `SOCIAL_PUBLISH_MAX_ATTEMPTS` (default `1` for sync safety)
- `SOCIAL_PUBLISH_RETRY_DELAYS_MS` (default `30000,120000,600000`)
- `SOCIAL_PUBLISH_FAST_RETRY=true` (tests: zero delay)

Retryable codes only: `NETWORK_ERROR`, `RATE_LIMITED`, `TEMPORARY_PROVIDER_ERROR`, `TIMEOUT`.

## Token lifecycle

`src/lib/social/token-lifecycle.ts`

Statuses: `CONNECTED` | `EXPIRING_SOON` | `EXPIRED` | `REAUTH_REQUIRED` | `REVOKED` | `DISCONNECTED`

Tokens remain server-side (`maskAccountsForClient`). Refresh: `ensure-publish-tokens.ts`.

## Audit

`writeSocialPublishAudit` — never stores secrets (keys matching token/secret/password redacted).

Optional MariaDB: `db/migrations/011_social_publish_jobs.sql`.

## Related docs

- [04-ENV-CONFIGURATION.md](./04-ENV-CONFIGURATION.md)
- [05-PLATFORM-REVIEW.md](./05-PLATFORM-REVIEW.md)
- [06-SECURITY-REVIEW.md](./07-SECURITY-REVIEW.md)
