← back to Norma

app/api/email-analyzer/search/route.ts

73 lines

/**
 * GET /api/email-analyzer/search?q=foo&favorites_only=true
 *
 * Search across saved analysis drafts and versions.
 * Ranking: favorites first, then trigram similarity, then newest.
 * Returns a flat list so the client can show "successful emails" inline.
 */

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

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

  try {
    const { searchParams } = new URL(request.url);
    const q = (searchParams.get('q') || '').trim();
    const favoritesOnly = searchParams.get('favorites_only') === 'true';
    const limit = Math.min(Number(searchParams.get('limit') || 25), 100);

    const conditions: string[] = [];
    const params: unknown[] = [];

    if (favoritesOnly) conditions.push(`d.is_favorite = TRUE`);
    if (q) {
      params.push(`%${q}%`);
      conditions.push(`(d.label ILIKE $${params.length} OR d.current_version ILIKE $${params.length})`);
    }

    const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';

    // Rank: favorites float to top, then trigram similarity to label+body, then newest.
    params.push(q || '');       // $N: trigram source
    const simParamIdx = params.length;
    params.push(limit);
    const limitParamIdx = params.length;

    const { rows } = await query(
      `SELECT
          d.id,
          d.session_id,
          d.version_number,
          d.label,
          d.tone,
          d.word_count,
          d.paragraph_count,
          d.current_version AS content,
          d.is_favorite,
          d.created_at,
          CASE WHEN $${simParamIdx} = '' THEN 0
               ELSE similarity(
                 COALESCE(d.label,'') || ' ' || COALESCE(d.current_version,''),
                 $${simParamIdx}
               )
          END AS sim
         FROM email_analyzer_drafts d
         ${where}
         ORDER BY d.is_favorite DESC,
                  sim DESC,
                  d.created_at DESC
         LIMIT $${limitParamIdx}`,
      params,
    );

    return NextResponse.json({ results: rows });
  } catch (err) {
    console.error('[email-analyzer/search] error:', (err as Error).message);
    return NextResponse.json({ error: 'Search failed' }, { status: 500 });
  }
}