All files / src/app/api/admin/workflows route.ts

100% Statements 115/115
82.35% Branches 14/17
100% Functions 2/2
100% Lines 115/115

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 1161x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 5x 5x 5x 5x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 3x 3x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x 1x 1x 1x 12x 12x 12x 12x 12x 12x 3x 3x 9x 9x 9x 9x 9x 9x 12x 12x 12x 12x 12x 12x 8x 8x 8x 8x 8x 1x 1x 1x  
export const dynamic = "force-dynamic";
 
import { NextRequest, NextResponse } from 'next/server';
import { } from "next-auth";
import { prisma } from "@/lib/prisma";
import { logger } from "@/lib/logging";
import { Prisma } from "@prisma/client";
import { WorkflowEngine, workflowCreateSchema } from "@/lib/workflows";
import {
  withAdmin,
  withErrorHandling,
  successResponse,
  createdResponse,
  ApiError,
  ApiSuccessResponse,
  ApiErrorResponse } from "@/lib/api";
import { } from "@/lib/api/middleware";
 
const LOG_CATEGORY = "ADMIN_WORKFLOWS_API";
 
/**
 * GET /api/admin/workflows
 * List all marketing workflows
 */
async function handleGet(request: NextRequest): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const { searchParams } = new URL(request.url);
  const page = parseInt(searchParams.get("page") || "1");
  const limit = parseInt(searchParams.get("limit") || "20");
  const trigger = searchParams.get("trigger");
  const isActive = searchParams.get("isActive");
  const includeStats = searchParams.get("includeStats") === "true";
 
  const skip = (page - 1) * limit;
 
  const where: Record<string, unknown> = {};
  if (trigger) where.trigger = trigger;
  if (isActive !== null) where.isActive = isActive === "true";
 
  const [workflows, total] = await Promise.all([
    prisma.marketingWorkflow.findMany({
      where,
      skip,
      take: limit,
      orderBy: { createdAt: "desc" } }),
    prisma.marketingWorkflow.count({ where }),
  ]);
 
  // Build response data with optional stats
  const responseData = await Promise.all(
    workflows.map(async (workflow) => {
      const baseData = {
        id: workflow.id,
        name: workflow.name,
        description: workflow.description,
        trigger: workflow.trigger,
        triggerConfig: workflow.triggerConfig,
        stepsCount: Array.isArray(workflow.steps)
          ? (workflow.steps as unknown[]).length
          : 0,
        isActive: workflow.isActive,
        isDraft: workflow.isDraft,
        version: workflow.version,
        createdAt: workflow.createdAt,
        updatedAt: workflow.updatedAt,
        stats: null as Awaited<ReturnType<typeof WorkflowEngine.getWorkflowStats>> | null };
 
      if (includeStats) {
        baseData.stats = await WorkflowEngine.getWorkflowStats(workflow.id);
      }
 
      return baseData;
    })
  );
 
  return successResponse({
    workflows: responseData,
    pagination: {
      page,
      limit,
      total,
      totalPages: Math.ceil(total / limit) } });
}
 
/**
 * POST /api/admin/workflows
 * Create a new marketing workflow
 */
async function handlePost(request: NextRequest): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const body = await request.json();
 
  // Validate input
  const validationResult = workflowCreateSchema.safeParse(body);
  if (!validationResult.success) {
    throw ApiError.validation("Validation failed", validationResult.error.issues);
  }
 
  const validatedData = validationResult.data;
 
  const workflow = await prisma.marketingWorkflow.create({
    data: {
      name: validatedData.name,
      description: validatedData.description || null,
      trigger: validatedData.trigger,
      triggerConfig: validatedData.triggerConfig ?? Prisma.DbNull,
      steps: validatedData.steps as Prisma.InputJsonArray,
      isActive: validatedData.isActive,
      isDraft: validatedData.isDraft } });
 
  logger.info("Workflow created", { category: LOG_CATEGORY, workflowId: workflow.id, name: workflow.name });
 
  return createdResponse(workflow);
}
 
export const GET = withErrorHandling(withAdmin(handleGet));
export const POST = withErrorHandling(withAdmin(handlePost));