Files
Momento/memento-note/app/api/ai/auto-labels/route.ts
Antigravity 88a7d2ad0a
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m59s
CI / Deploy production (on server) (push) Successful in 24s
fix(audit): nettoyage accès, garde-fous build, unification quotas
Semaine 1 — fuites et accès :
- /archive rendu accessible via sidebar (était invisible)
- Suppression pages orphelines : /chat, /graph, /support, test-title-suggestions
- Fixes i18n : search-modal (clé non interpolée), sidebar tooltips, export PDF
- 15 locales mises à jour

Semaine 2 — garde-fous :
- 8 erreurs TS fixees → ignoreBuildErrors: false (build type-safe)
- reactStrictMode: true (dev-only, zero impact prod)
- reserveUsageOrThrow → wrapper deprecie vers reserveAiUsageOrThrow
- auth-guard.ts : requireAuthOrResponse() + requireAdminOrResponse()

Tests 212/212 | Lint 0 erreur | Build OK | tsc 0 erreur
2026-07-17 18:47:44 +00:00

139 lines
3.7 KiB
TypeScript

import { rateLimit } from '@/lib/rate-limit'
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/auth'
import { autoLabelCreationService } from '@/lib/ai/services'
import { getAISettings } from '@/app/actions/ai-settings'
import { hasUserAiConsent } from '@/lib/consent/server-consent'
import { withAiQuota, handleQuotaHttpError } from '@/lib/ai-quota'
/**
* POST /api/ai/auto-labels - Suggest new labels for a notebook
*/
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
)
}
const userId = session.user.id
// GDPR AI Consent check
if (!(await hasUserAiConsent())) {
return NextResponse.json(
{ success: false, error: 'ai_consent_required' },
{ status: 403 }
)
}
// Respect user's autoLabeling toggle
const userSettings = await getAISettings(session.user.id)
if (userSettings.autoLabeling === false) {
return NextResponse.json({ success: true, data: null, message: 'Auto-labeling disabled by user' })
}
const body = await request.json()
const { notebookId, language = 'en' } = body
if (!notebookId || typeof notebookId !== 'string') {
return NextResponse.json(
{ success: false, error: 'Missing required field: notebookId' },
{ status: 400 }
)
}
// Check if notebook belongs to user
const { prisma } = await import('@/lib/prisma')
const notebook = await prisma.notebook.findFirst({
where: {
id: notebookId,
userId: session.user.id,
},
})
if (!notebook) {
return NextResponse.json(
{ success: false, error: 'Notebook not found' },
{ status: 404 }
)
}
const suggestions = await withAiQuota(
userId,
'auto_tag',
() =>
autoLabelCreationService.suggestLabels(
notebookId,
userId,
language,
),
{ lane: 'tags' },
)
if (!suggestions) {
return NextResponse.json({
success: true,
data: null,
message: 'No suggestions available (notebook may have fewer than 15 notes)',
})
}
return NextResponse.json({
success: true,
data: suggestions,
})
} catch (error) {
const quotaResp = handleQuotaHttpError(error)
if (quotaResp) return quotaResp
console.error('[/api/ai/auto-labels] POST failed:', error)
return NextResponse.json({ success: false, error: 'auto_labels_failed' }, { status: 500 })
}
}
/**
* PUT /api/ai/auto-labels - Create suggested labels
*/
export async function PUT(request: NextRequest) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
)
}
const body = await request.json()
const { suggestions, selectedLabels } = body
if (!suggestions || !Array.isArray(selectedLabels)) {
return NextResponse.json(
{ success: false, error: 'Missing required fields: suggestions, selectedLabels' },
{ status: 400 }
)
}
// Create labels
const createdCount = await autoLabelCreationService.createLabels(
suggestions.notebookId,
session.user.id,
suggestions,
selectedLabels
)
return NextResponse.json({
success: true,
data: {
createdCount,
},
})
} catch (error) {
console.error('[/api/ai/auto-labels] PUT failed:', error)
return NextResponse.json({ success: false, error: 'Failed to create labels' })
}
}