Skip to content

ContentTasksController

reference
1 min readUpdated

Kind: Controller

Source: atloria-monorepo/apps/api/src/content-tasks/content-tasks.controller.ts

Analytics action queue — project-scoped ContentTask CRUD. Every route rides :projectId and is org-verified fail-closed via ResourceOrgGuard(kind: 'project'); the service additionally filters every query by projectId. Members are scoped to the caller's own organization (resolved from the verified JWT, not the path).

ContentTasksController exposes project-scoped CRUD endpoints for analytics action queue ContentTask records. Every route is protected by ResourceOrgGuard(kind: 'project'), which verifies project organization access fail-closed, while the underlying service applies projectId filtering to every query. Member-related operations resolve organization scope from the verified JWT rather than trusting organization identifiers in request paths.

Diagram

mermaid
graph LR
  Client[Authenticated Client] --> Controller[ContentTasksController]
  Controller --> Guard[ResourceOrgGuard<br/>kind: project]
  Guard --> JWT[Verified JWT Organization]
  Guard -->|Authorized project access| Service[ContentTasksService]
  Service -->|Filter by projectId| Database[(ContentTask Records)]

  JWT -->|Organization scope| Service
  Guard -->|Unauthorized| Denied[403 Forbidden]

Usage

ts
// Example request flow for a project-scoped content task.
//
// POST /projects/proj_123/content-tasks
// Authorization: Bearer <verified-jwt>

const response = await fetch(
  `${API_URL}/projects/proj_123/content-tasks`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      title: 'Review landing page copy',
      status: 'pending',
      priority: 'high',
    }),
  },
);

if (!response.ok) {
  throw new Error(`Unable to create content task: ${response.statusText}`);
}

const contentTask = await response.json();

// Fetch tasks for the same verified project scope.
const tasksResponse = await fetch(
  `${API_URL}/projects/proj_123/content-tasks`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  },
);

const tasks = await tasksResponse.json();
console.log(contentTask, tasks);

AI Coding Instructions

  • Keep all controller routes nested beneath :projectId; treat the project path parameter as the resource scope for every CRUD operation.
  • Preserve ResourceOrgGuard(kind: 'project') on project-scoped endpoints. Do not replace verified authorization with client-provided organization IDs.
  • Ensure service methods filter reads, updates, and deletes by projectId, not only by the content task ID.
  • Resolve member or organization context from the verified JWT/request context, never from an unverified route parameter or request body.
  • Return standard NestJS DTO-based validation errors and authorization responses; do not leak whether tasks exist outside the caller’s organization.

Relationships

  • MODULE_DECLARES → list
  • MODULE_DECLARES → members
  • MODULE_DECLARES → create
  • MODULE_DECLARES → update
  • MODULE_DECLARES → remove
  • DEPENDS_ON → ContentTasksService

Referenced By

  • ContentTasksModule (MODULE_DECLARES)

Was this page helpful?

Download as PDF