Skip to Content
ChannelsChannel Action Items

Channel Action Items

Status: [Live May 2026]

AI-generated improvement suggestions for each connected channel, reviewed and actioned by the DM team.


Overview

After an insight worker completes health scoring for a channel, it automatically enqueues the channel-action-suggester worker. The suggester reads the insight’s healthDimensions, strengths, weaknesses, and recommendations and generates a prioritised list of concrete action items. DM reviewers can then approve, dismiss, or directly execute suggestions (which creates an Activity and enqueues the relevant agent).


Data Model

ChannelActionItem

model ChannelActionItem { id String @id @default(cuid()) tenantId String connectedChannelId String channelInsightId String title String description String rationale String dimension String // health dimension (e.g. "content_quality") priority Int // 1 (high) → 3 (low) isManual Boolean @default(false) agentQueue String? // e.g. "agent__blog-writer"; null for manual tasks status String @default("pending_review") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(...) connectedChannel ConnectedChannel @relation(...) channelInsight ChannelInsight @relation(...) }

Status machine

pending_review → approved → in_progress → done ↘ dismissed (approved) → dismissed (restore)
StatusMeaning
pending_reviewFreshly generated; awaiting DM decision
approvedDM approved; ready to execute
in_progressExecution triggered; Activity created and agent enqueued
doneCompleted (manual mark-done or agent finished)
dismissedDM dismissed; restorable

Queue

Queue name: agent__channel-action-suggester

Registered in: packages/queue/src/queues.ts

Enqueue helper: enqueueChannelActionSuggester({ tenantId, tenantName, connectedChannelId, channelInsightId, channelType }) — exported from packages/queue/src/index.ts

Payload type: ChannelActionSuggesterPayload in packages/queue/src/types.ts


Worker

File: packages/agents/src/workers/insights/channel-action-suggester.worker.ts

Trigger: Auto-enqueued at the end of each insight worker’s completed handler — all 8 insight workers auto-chain:

  • gsc-insights.worker.ts
  • ga-insights.worker.ts
  • facebook-insights.worker.ts
  • instagram-insights.worker.ts
  • linkedin-insights.worker.ts
  • gbp-insights.worker.ts
  • google-ads-insights.worker.ts
  • meta-ads-insights.worker.ts

What it does:

  1. Loads the ChannelInsight record (must have status="done" and healthScore != null)
  2. Calls Claude with the health dimensions, scores, strengths, weaknesses, and recommendations
  3. Generates 3–8 prioritised suggestions with title, description, rationale, dimension, priority, and optional agentQueue
  4. Bulk-inserts ChannelActionItem records
  5. Sends a DM notification: “X improvement suggestions ready for [channel name]”

AgentConfig seed: role channel-action-suggester with allowedTools: [], maxTurnsPerRun: 1.


API Routes

Tenant (/tenant/v1/channel-action-items)

Auth: requireTenantUser

MethodPathDescription
GET/List items for a channel (?channelId=)
POST/generateManually trigger suggestion generation
PATCH/:id/statusUpdate status (approved / dismissed / done)
POST/:id/executeExecute approved item → creates Activity + enqueues agent

File: apps/api/src/routers/landing-pages.ts (registered in both app.ts and index.ts)

DM (/dm/v1/channel-action-items)

Auth: requireDMAccesstenantId always in query/body (never in JWT)

MethodPathDescription
GET/List items for a channel (?tenantId=&channelId=[&status=])
GET/channel-infoChannel metadata + latest insight (?tenantId=&channelId=)
POST/generateManually trigger suggestion generation (body: { tenantId, connectedChannelId })
PATCH/:id/statusUpdate status (body: { tenantId, status })
POST/:id/executeExecute approved item → Activity + agent (body: { tenantId })

File: apps/api/src/routers/dm/channel-action-items.ts

Execute → Activity mapping

agentQueuedeliverableType
agent__blog-writerblog_post
agent__social-post-writersocial_post
agent__gbp-post-writergbp_post
agent__landing-page-writerlanding_page
agent__email-writeremail_newsletter

Blog posts use enqueueBlogWriterFresh; all others use dynamic queue dispatch.


Dashboard UI

Suggestions tab — channel detail pages

All 7 channel detail pages have a Suggestions tab alongside Analytics and Insights:

PageComponent
Google Search ConsoleGoogleSearchConsoleChannelDetail.tsx
Google AnalyticsGoogleAnalyticsChannelDetail.tsx
FacebookFacebookChannelDetail.tsx
InstagramInstagramChannelDetail.tsx
LinkedInLinkedInChannelDetail.tsx
Google AdsGoogleAdsChannelDetail.tsx
Google Business ProfileGoogleBusinessProfileChannelDetail.tsx

All render <ChannelActionItemsTab channelId={...} apiUrl={...} token={...} readonly={true} />.

readonly={true} — client view shows approved items only; no approve/dismiss/execute controls.

Component file: apps/dashboard/src/app/(dashboard)/channels/[id]/ChannelActionItemsTab.tsx

Channel health badge

Each channel card on /channels/health shows a violet badge when pendingSuggestionsCount > 0:

⚡ 3 improvement suggestions ready

pendingSuggestionsCount is computed via db.channelActionItem.groupBy({ by: ["connectedChannelId"], where: { tenantId, status: "pending_review" } }) — added to both buildHealthSummary() and the dashboard page.tsx direct query.


DM Portal UI

/channels/health

DM channel health page shows an amber badge when pendingSuggestionsCount > 0:

⚡ 3 suggestions pending review

Clicking a channel card navigates to /channels/[id].

/channels/[id] — DM Channel Detail

Files:

  • apps/dm/src/app/(dm)/channels/[id]/page.tsx — server component, fetches from /dm/v1/channel-action-items/channel-info
  • apps/dm/src/app/(dm)/channels/[id]/DmChannelDetailClient.tsx — client component

Tabs: Suggestions (default) · Insights

Suggestions tab

  • Pending section — Approve / Dismiss buttons per item
  • Active section — Execute (for non-manual) / Mark Done (for manual) buttons
  • History section — Dismissed items with Restore button
  • Refresh button — reloads items from API
  • Regenerate button — calls POST /dm/v1/channel-action-items/generate to re-run the suggester

Insights tab

  • Health score progress arc (0–100)
  • Dimension scores list
  • Strengths / Weaknesses / Recommendations sections (from latest ChannelInsight)

Channel header

  • Colour-coded 2-letter type initials
  • Channel type label + title
  • Health score badge
  • “Connected” / “Disconnected” status badge
  • Breadcrumb → /channels/health

© 2026 Leadmetrics — Internal use only