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>
26 lines
707 B
TypeScript
26 lines
707 B
TypeScript
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' } },
|
|
);
|
|
}
|