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)| Status | Meaning |
|---|---|
pending_review | Freshly generated; awaiting DM decision |
approved | DM approved; ready to execute |
in_progress | Execution triggered; Activity created and agent enqueued |
done | Completed (manual mark-done or agent finished) |
dismissed | DM 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.tsga-insights.worker.tsfacebook-insights.worker.tsinstagram-insights.worker.tslinkedin-insights.worker.tsgbp-insights.worker.tsgoogle-ads-insights.worker.tsmeta-ads-insights.worker.ts
What it does:
- Loads the
ChannelInsightrecord (must havestatus="done"andhealthScore != null) - Calls Claude with the health dimensions, scores, strengths, weaknesses, and recommendations
- Generates 3–8 prioritised suggestions with
title,description,rationale,dimension,priority, and optionalagentQueue - Bulk-inserts
ChannelActionItemrecords - 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
| Method | Path | Description |
|---|---|---|
GET | / | List items for a channel (?channelId=) |
POST | /generate | Manually trigger suggestion generation |
PATCH | /:id/status | Update status (approved / dismissed / done) |
POST | /:id/execute | Execute 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: requireDMAccess — tenantId always in query/body (never in JWT)
| Method | Path | Description |
|---|---|---|
GET | / | List items for a channel (?tenantId=&channelId=[&status=]) |
GET | /channel-info | Channel metadata + latest insight (?tenantId=&channelId=) |
POST | /generate | Manually trigger suggestion generation (body: { tenantId, connectedChannelId }) |
PATCH | /:id/status | Update status (body: { tenantId, status }) |
POST | /:id/execute | Execute approved item → Activity + agent (body: { tenantId }) |
File: apps/api/src/routers/dm/channel-action-items.ts
Execute → Activity mapping
agentQueue | deliverableType |
|---|---|
agent__blog-writer | blog_post |
agent__social-post-writer | social_post |
agent__gbp-post-writer | gbp_post |
agent__landing-page-writer | landing_page |
agent__email-writer | email_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:
| Page | Component |
|---|---|
| Google Search Console | GoogleSearchConsoleChannelDetail.tsx |
| Google Analytics | GoogleAnalyticsChannelDetail.tsx |
FacebookChannelDetail.tsx | |
InstagramChannelDetail.tsx | |
LinkedInChannelDetail.tsx | |
| Google Ads | GoogleAdsChannelDetail.tsx |
| Google Business Profile | GoogleBusinessProfileChannelDetail.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 readypendingSuggestionsCount 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 reviewClicking 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-infoapps/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/generateto 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