Approved drafts publish via a single n8n `publish-content` webhook; the panel
POSTs the effective content (founder edits merged over generated body) and
awaits a synchronous Respond-to-Webhook result (sp.semih.ai is Tailscale-only,
so we avoid an n8n→panel callback). n8n routes by channel.
- lib/n8n.ts: publishToN8n client (X-Content-Secret header, timeout, tolerant
result parsing: ok|success + publishedUrl|url|postUrl|permalink)
- publishDraft server action: approved|failed → publishing → published(+url) /
failed(+error), audit-logged; effective content = bodyJson + founderEdits
- DraftCard: "Yayınla" / "Yeniden yayınla" button + publishing state
- docs/n8n: importable publish-content workflow (Webhook → Switch → LinkedIn /
HTTP-blog → Respond) + runbook (contract, panel envs, LinkedIn OAuth setup,
blog endpoint = sase.tr POST /blog/posts/internal Bearer)
Needs panel-web envs N8N_PUBLISH_WEBHOOK_URL + N8N_WEBHOOK_SECRET. Publish is a
graceful no-op (clear error) until those are set and the n8n workflow exists.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>