import { NextRequest, NextResponse } from 'next/server'; import { adminApiDisabledResponse, isAdminApiEnabled } from '@/lib/runtime/adminApi'; interface RouteParams { params: Promise<{ id: string; }>; } // GET /api/funnels/[id]/history - получить историю изменений воронки export async function GET(request: NextRequest, { params }: RouteParams) { if (!isAdminApiEnabled()) { return adminApiDisabledResponse(); } try { const { id } = await params; const [ { default: connectMongoDB }, { default: FunnelHistoryModel }, ] = await Promise.all([ import('@/lib/mongodb'), import('@/lib/models/FunnelHistory'), ]); await connectMongoDB(); const { searchParams } = new URL(request.url); const sessionId = searchParams.get('sessionId'); const limit = parseInt(searchParams.get('limit') || '50'); const includeSnapshots = searchParams.get('snapshots') === 'true'; const filter: Record = { funnelId: id }; if (sessionId) { filter.sessionId = sessionId; } const historyQuery = FunnelHistoryModel .find(filter) .sort({ createdAt: -1, sequenceNumber: -1 }) .limit(limit); // Включать снимки данных или только метаданные if (!includeSnapshots) { historyQuery.select('-funnelSnapshot'); } const history = await historyQuery.lean(); return NextResponse.json({ history: history.map(entry => ({ ...entry, _id: entry._id.toString(), funnelId: entry.funnelId.toString() })) }); } catch (error) { console.error('GET /api/funnels/[id]/history error:', error); return NextResponse.json( { error: 'Failed to fetch funnel history' }, { status: 500 } ); } } // POST /api/funnels/[id]/history - создать новую запись в истории export async function POST(request: NextRequest, { params }: RouteParams) { if (!isAdminApiEnabled()) { return adminApiDisabledResponse(); } try { const { id } = await params; const [ { default: connectMongoDB }, { default: FunnelHistoryModel }, ] = await Promise.all([ import('@/lib/mongodb'), import('@/lib/models/FunnelHistory'), ]); await connectMongoDB(); const body = await request.json(); const { sessionId, funnelSnapshot, actionType, description, changeDetails } = body; // Валидация if (!sessionId || !funnelSnapshot || !actionType) { return NextResponse.json( { error: 'sessionId, funnelSnapshot and actionType are required' }, { status: 400 } ); } // Получаем следующий номер последовательности const lastEntry = await FunnelHistoryModel .findOne({ funnelId: id, sessionId }) .sort({ sequenceNumber: -1 }); const nextSequenceNumber = (lastEntry?.sequenceNumber || -1) + 1; // Создаем запись const historyEntry = await FunnelHistoryModel.create({ funnelId: id, sessionId, funnelSnapshot, actionType, sequenceNumber: nextSequenceNumber, description, changeDetails }); // Очищаем старые записи истории (оставляем последние 100) const KEEP_ENTRIES = 100; const entriesToDelete = await FunnelHistoryModel .find({ funnelId: id, sessionId }) .sort({ sequenceNumber: -1 }) .skip(KEEP_ENTRIES) .select('_id'); if (entriesToDelete.length > 0) { const idsToDelete = entriesToDelete.map((entry: { _id: unknown }) => entry._id); await FunnelHistoryModel.deleteMany({ _id: { $in: idsToDelete } }); } return NextResponse.json({ _id: historyEntry._id, actionType: historyEntry.actionType, description: historyEntry.description, sequenceNumber: historyEntry.sequenceNumber, isBaseline: historyEntry.isBaseline, createdAt: historyEntry.createdAt, changeDetails: historyEntry.changeDetails }, { status: 201 }); } catch (error) { console.error('POST /api/funnels/[id]/history error:', error); return NextResponse.json( { error: 'Failed to create history entry' }, { status: 500 } ); } }