← back to Stayclaim

src/app/api/la-records/lookup/route.ts

61 lines

/**
 * Live LA County records lookup endpoint.
 *
 * Used by the /submit form to show a real-time preview of what we know about
 * a typed address — year built, sqft, lot size, assessed value — so the user
 * sees product value before they hit submit.
 *
 * Server-side wrapper around lib/la-arcgis.ts. Cache-first via la_parcel table.
 */
import { NextResponse } from 'next/server';
import { getOrFetchParcelForAddress } from '@/lib/la-arcgis';
import { rateLimit } from '@/lib/rate-limit';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

export async function GET(req: Request) {
  const rl = await rateLimit('la-records');
  if (!rl.ok) {
    return NextResponse.json(
      { ok: false, error: 'rate_limited' },
      { status: 429, headers: { 'Retry-After': String(rl.retryAfter ?? 60) } },
    );
  }

  const { searchParams } = new URL(req.url);
  const q = searchParams.get('q')?.trim();
  if (!q || q.length < 6) {
    return NextResponse.json({ ok: false, error: 'query too short' }, { status: 400 });
  }
  if (q.length > 200) {
    return NextResponse.json({ ok: false, error: 'query too long' }, { status: 400 });
  }
  try {
    const parcel = await getOrFetchParcelForAddress(q, null);
    if (!parcel) {
      return NextResponse.json({ ok: true, found: false });
    }
    return NextResponse.json({
      ok: true,
      found: true,
      apn: parcel.apn,
      situs_address: parcel.situs_address,
      city: parcel.city,
      zip: parcel.zip,
      year_built: parcel.year_built,
      sqft_main: parcel.sqft_main,
      bedrooms: parcel.bedrooms,
      bathrooms: parcel.bathrooms,
      use_description: parcel.use_description,
      total_value: parcel.total_value,
      roll_year: parcel.roll_year,
      lat: parcel.lat,
      lng: parcel.lng,
    });
  } catch (e) {
    console.error('[la-records/lookup] error', e);
    return NextResponse.json({ ok: false, error: 'lookup_failed' }, { status: 500 });
  }
}