← back to Norma

app/api/onboard/trigger/route.ts

80 lines

import { NextRequest, NextResponse } from 'next/server';
import { requireRole } from '@/lib/require-role';

// ─── POST /api/onboard/trigger ────────────────────────────────────────────────
// Body: { topic_id: string }
// Triggers the onboard agent at http://127.0.0.1:9808/api/skill/discover

const ONBOARD_AGENT_URL = 'http://127.0.0.1:9808/api/skill/discover';
const AGENT_TIMEOUT_MS = 30_000;

export async function POST(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const body = (await request.json()) as { topic_id?: string; topic?: string };
    const { topic_id, topic } = body;

    if (!topic_id && !topic) {
      return NextResponse.json(
        { error: 'Provide either topic_id or topic in the request body.' },
        { status: 400 },
      );
    }

    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), AGENT_TIMEOUT_MS);

    let agentResponse: Response;
    try {
      agentResponse = await fetch(ONBOARD_AGENT_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ topic_id, topic }),
        signal: controller.signal,
      });
    } finally {
      clearTimeout(timeout);
    }

    if (!agentResponse.ok) {
      const errorText = await agentResponse.text();
      return NextResponse.json(
        {
          error: `Onboard agent returned HTTP ${agentResponse.status}`,
          agent_response: errorText,
        },
        { status: 502 },
      );
    }

    const agentData = await agentResponse.json();
    return NextResponse.json({
      success: true,
      topic_id: topic_id ?? null,
      topic: topic ?? null,
      agent_result: agentData,
    });
  } catch (err: unknown) {
    const msg = (err as Error).message ?? 'Unknown error';

    if (msg.includes('abort') || msg.includes('timeout')) {
      return NextResponse.json(
        { error: 'Onboard agent timed out after 30s.' },
        { status: 504 },
      );
    }

    if (msg.includes('ECONNREFUSED') || msg.includes('fetch failed')) {
      return NextResponse.json(
        { error: 'Onboard agent is not reachable (port 9808).' },
        { status: 503 },
      );
    }

    console.error('[api/onboard/trigger] Error:', msg);
    return NextResponse.json({ error: msg }, { status: 500 });
  }
}