Skip to main content

Operation Inventory — platform-core / comms-engine / campaign-engine

Task 1.1 audit deliverable. Generated by static analysis of NestJS controllers (@Controller, @Get/@Post/@Put/@Patch/@Delete/@All, @ApiTags) since the three services were not running in this environment (see design.md D3 — static enumeration is an accepted substitute for the HTTP fetch used at generation time).

How this was built

  • Enumerated every *.controller.ts file in agentic-os-platform-core/src, agentic-os-comms-engine/src, agentic-os-campaign-engine/src.
  • For each route handler, recorded HTTP method + path (controller base path + method path), the effective tag, and the derived operationId.
  • operationId is not set explicitly anywhere in any of the three codebases (grep -r operationId found zero decorator usages). All three services call SwaggerModule.createDocument(app, config) with no operationIdFactory override, so @nestjs/swagger’s default factory applies: operationId = "${ControllerClassName}_${methodName}" (no API version is configured, so the version suffix branch never applies). Source: @nestjs/swagger/dist/swagger-explorer.js.
  • Tag is the value passed to @ApiTags(...) on the controller class. Where a controller has no @ApiTags decorator, @nestjs/swagger falls back to autoTagControllers (default true when unset — none of the three DocumentBuilder configs disable it), which derives the tag as the controller class name with a trailing Controller stripped (explorers/api-use-tags.explorer.js). These are marked (default) below. This default-tag mechanism is confirmed by requirements.md itself, which names Callback and Attempt as tags to hard-exclude — both are campaign-engine controllers with no @ApiTags decorator.
  • Paths include the service’s global prefix (api/v1) except routes each service’s main.ts explicitly excludes from that prefix (health checks, and campaign-engine’s root /, and comms-engine’s api/whatsapp/webhook). NestJS Swagger’s document paths include the global prefix by default (no ignoreGlobalPrefix option is set in any swagger.config.ts), so this matches what GET /api/docs-json will actually return.

Count reconciliation vs. requirements.md “measured starting point”

Notes on drift (do not force-reconcile to 423 — reporting actual counts per task instructions):
  • comms-engine: 192 → 180 is a meaningful drift (-12 operations). Possible causes: routes removed/merged since the requirements doc was written, or the original count included routes this audit’s static grep pattern missed (e.g. decorators split across multiple lines, or a route defined via a helper/base class not visible to a single-controller grep). Recommend a live GET /api/docs-json diff against this file once services are running, per task 5.1, to confirm whether this is real drift or an audit gap.
  • campaign-engine: 55 → 56. ServiceInfoController and RootController both register a bare GET at the app root (one at /api/v1 via ServiceInfoController, one at unprefixed / via RootController in common/health/health.controller.ts). These are two distinct paths, not a duplicate — likely why the measured count differs from the live count by exactly one, depending on whether the original measurement’s Swagger scan included the unprefixed root.
  • Path counts (146/130/40) were not independently re-verified in this static pass — computing them requires grouping the operations below by unique path, which is mechanical from this table but out of scope for the audit file itself (task 3’s generation script does this against real specs).

Tag inventory (for task 1.2 classification)

platform-core (32 tags)

Health, Admin Analytics, Admin Auth, Admin Session, Admin Billing, Admin Health, Admin Pricing, Admin Tenants, Admin Users, Agent Templates, Logs, Auth, Billing, Admin Catalog, Favorites, Admin Feature Flags, Feature Flags (internal), Features, Integrations, Admin Integrations, Internal, Pricing, Profile, Roadmap, Service Tokens, Telephony Applications, Virtual Numbers, Wallet, Analytics, Tenants, Testing, Users, API Keys

comms-engine (33 tags)

Health, agent-widget-customization, widget-preview, agents, analytics, call-logs, internal/call-logs, InternalCampaignRuntime (default), internal-callbacks, channels, internal-live-call, internal-whatsapp, chatbot, Integrations, Internal, knowledge-bases, llm, Prompts (default), ratings, Service, sessions, stt-providers, Tools (default), transcripts, tts-providers, internal-voice-languages, voice-languages, voice-numbers, VoiceProfile (default), internal-voices, voices, webhooks, whatsapp-webhook, widget

campaign-engine (14 tags)

Health, Attempt (default), Callback (default), CampaignActions (default), InternalCampaignRuntime (default), Campaign (default), ContactList (default), Contact (default), Service, SmsAgentCampaignInternal (default), SmsAgentCampaign (default), WhatsAppCampaign (default), WhatsAppInternal (default), WhatsAppTemplate (default) Total distinct tags across all three specs: ~74 (some names collide across services, e.g. Health, Integrations, Internal, Service — task 1.2 should decide whether that’s fine per-service or needs disambiguation once merged, per design.md D2 merge step).

platform-core — 180 operations (33 controllers)


comms-engine — 180 operations (38 controllers)


campaign-engine — 56 operations (16 controller classes)


Open questions for task 1.2 (tag classification)

  • Callback and Attempt (campaign-engine, default tags) are explicitly named for exclusion in requirements.md — confirmed present above.
  • Roadmap and Favorites (platform-core) are explicitly named for exclusion — confirmed present above.
  • whatsapp-webhook and widget-preview (comms-engine) are explicitly named for exclusion — confirmed present above.
  • Testing (platform-core) is explicitly named for exclusion — confirmed present above; also contains a wallet-credit and email-verification backdoor as described in requirements.md.
  • Several default (unlabeled) tags read oddly as public-facing group names if ever allowlisted by mistake: CampaignActions, ContactList, Contact, SmsAgentCampaignInternal, WhatsAppInternal, InternalCampaignRuntime, VoiceProfile, Tools, Prompts — none currently have a @ApiTags decorator, so adding one (or classifying by controller instead of tag) should be considered in task 1.2 for the ones meant to be published.
  • Tag name collisions across services once merged (design.md D2): Health, Integrations, Internal, Service. Task 1.2 / config (task 2) should decide whether allowlist entries need to be service-qualified.