Files
pn-new-crm/src/app/api/public/health/route.ts

26 lines
707 B
TypeScript
Raw Normal View History

feat(berths): public berths API + health env-match endpoint Adds the read-only public-website data feed promised by plan §4.5 and §7.3. The marketing site's `getBerths()` swap is now a one-line URL change against the existing 5-min TTL behaviour. - src/app/api/public/berths/route.ts: GET / unauth, returns the full port-nimara berth list as { list, pageInfo } in the verbatim NocoDB shape ("Mooring Number", "Side Pontoon", quoted-key fields). Cache: s-maxage=300 + stale-while-revalidate=60. portSlug query param lets future ports opt in. - src/app/api/public/berths/[mooringNumber]/route.ts: GET single. Up- front regex validation (^[A-Z]+\\d+$) rejects malformed lookups with 400 + cache-control:no-store before hitting the DB. 404 + no-store when not found. - src/app/api/public/health/route.ts: returns { status, env, appUrl, timestamp } so the marketing site can refuse to start when its CRM_PUBLIC_URL points at a different deployment env (§14.8 critical env-mismatch protection). - src/lib/services/public-berths.ts: pure mapper with derivePublicStatus ("sold" wins; otherwise specific-interest junction OR status='under_offer' -> "Under Offer"; else "Available"). - 11 unit tests covering numeric coercion, status derivation, archived-berth handling, missing-map-data omission, and the status-precedence rule that "sold" trumps the specific-interest signal. Smoke-tested: /api/public/berths -> 117 rows, A1 correctly shows "Under Offer" (has interest_berths.is_specific_interest=true link), INVALID -> 400, Z99 -> 404. Total tests: 996 -> 1007. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 02:52:44 +02:00
import { NextResponse } from 'next/server';
import { env } from '@/lib/env';
/**
* GET /api/public/health
*
* Public-facing health probe. Used by the marketing-website server on
* startup to verify it's pointed at a CRM matching its own deployment
* env (plan §14.8 critical: prevent staging-website-talking-to-prod-CRM).
*
* Returns the CRM's `NODE_ENV` and `APP_URL` so the website can do a
* strict equality check before serving any request.
*/
export function GET(): Response {
return NextResponse.json(
{
status: 'ok',
env: env.NODE_ENV,
appUrl: env.APP_URL,
timestamp: new Date().toISOString(),
},
{ headers: { 'cache-control': 'no-store' } },
);
}