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>
This commit is contained in:
25
src/app/api/public/health/route.ts
Normal file
25
src/app/api/public/health/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
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' } },
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user