import { NextResponse } from "next/server"; import { z } from "zod"; import { AUTOTRADE_API_ERROR_CODE, createAutotradeErrorResponse, getAutotradeSession, getAutotradeUserId, readJsonBody, sanitizeAutotradeError, stopAutotradeSession, } from "@/app/api/autotrade/_shared"; import type { AutotradeStopReason } from "@/features/autotrade/types/autotrade.types"; const stopRequestSchema = z.object({ sessionId: z.string().uuid().optional(), reason: z .enum([ "browser_exit", "external_leave", "manual", "emergency", "heartbeat_timeout", ]) .optional(), }); export async function POST(request: Request) { const userId = await getAutotradeUserId(request.headers); if (!userId) { return createAutotradeErrorResponse({ status: 401, code: AUTOTRADE_API_ERROR_CODE.AUTH_REQUIRED, message: "로그인이 필요합니다.", }); } const rawBody = await readJsonBody(request); const parsed = stopRequestSchema.safeParse(rawBody ?? {}); if (!parsed.success) { return createAutotradeErrorResponse({ status: 400, code: AUTOTRADE_API_ERROR_CODE.INVALID_REQUEST, message: parsed.error.issues[0]?.message ?? "세션 종료 입력값이 올바르지 않습니다.", }); } try { const session = getAutotradeSession(userId); if (!session) { return NextResponse.json({ ok: true, session: null, }); } if (parsed.data.sessionId && parsed.data.sessionId !== session.sessionId) { return createAutotradeErrorResponse({ status: 409, code: AUTOTRADE_API_ERROR_CODE.CONFLICT, message: "세션 식별자가 일치하지 않습니다.", }); } const reason: AutotradeStopReason = parsed.data.reason ?? "manual"; const stopped = stopAutotradeSession(userId, reason); return NextResponse.json({ ok: true, session: stopped, }); } catch (error) { return createAutotradeErrorResponse({ status: 500, code: AUTOTRADE_API_ERROR_CODE.INTERNAL, message: sanitizeAutotradeError(error, "세션 종료 중 오류가 발생했습니다."), }); } }