← back to Norma
app/api/orgs/signup/route.ts
73 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { auditLog } from '@/lib/audit';
/**
* POST /api/orgs/signup
* Nonprofit signup/intake form — creates or updates an organization with
* political alignment, advocacy profile, and matching preferences.
*/
export async function POST(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
try {
const data = await request.json();
if (!data.name || typeof data.name !== 'string' || data.name.trim() === '') {
return NextResponse.json({ error: 'Organization name is required' }, { status: 400 });
}
const result = await query(
`INSERT INTO organizations (
name, type, tax_status, key_issues, geo_focus, geo_focus_detail,
state, city, political_leaning, advocacy_intensity,
bipartisan_willingness, supporter_count, outreach_channels,
response_speed, urgency_threshold, sentiment_preference,
preferred_actions, primary_contact, email, phone, website,
description, onboard_status, source
) VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10,
$11, $12, $13,
$14, $15, $16,
$17, $18, $19, $20, $21,
$22, 'signup', 'self_signup'
) RETURNING id, name, onboard_status`,
[
data.name.trim(),
data.org_type || null,
data.tax_status || null,
data.key_issues || [],
data.geo_focus || null,
data.geo_focus_detail || null,
data.state || null,
data.city || null,
data.political_leaning || null,
data.advocacy_intensity || null,
data.bipartisan_willingness || null,
data.supporter_count || null,
data.outreach_channels || [],
data.response_speed || null,
data.urgency_threshold || null,
data.sentiment_preference || null,
data.preferred_actions || [],
data.primary_contact || null,
data.email || null,
data.phone || null,
data.website || null,
data.description || null,
],
);
const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || undefined;
await auditLog('org.signup', 'organization', result.rows[0].id, { name: data.name }, ip);
return NextResponse.json({ organization: result.rows[0] }, { status: 201 });
} catch (err) {
console.error('[api/orgs/signup] POST error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to register organization' }, { status: 500 });
}
}