feat(cms): install Payload and serve the admin panel
Payload 3.88 runs inside the Next app against the existing Postgres, in
its own 'payload' schema so no pipeline operation on public — the app
tables, Airflow's metadata, migrate_csv_to_db.py --drop — can reach blog
content.
Its REST API is mounted at /cms-api. /api is the FastAPI proxy's
catch-all, which would swallow every admin call and forward it to the
backend with no error. The mount points live in lib/payloadRoutes.ts so
there is one definition and a test can assert it without importing
Payload: it is ESM-only, next/jest will not transform it, and appending
transformIgnorePatterns cannot un-ignore a package. Forcing it through
transpilePackages would change how the production build bundles Payload
to serve a test, so the live proof that /api still reaches FastAPI stays
where it belongs — the e2e journeys, which call /api/schools.
The package becomes ESM ("type": "module"), which Payload's CLI requires:
richtext-lexical has top-level await and the config cannot be require()d.
Only two files needed renaming, jest.config.cjs and a build script.
The build is verified to succeed with DATABASE_URL and PAYLOAD_SECRET
both unset, which is how CI builds it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017YmbBhr8s7GusjDE12hrZM
This commit is contained in:
1 parent
2437ffce42
commit
c5a4d106da
19 files changed
+5441
-226
No files matched your search
@@ -0,0 +1,15 @@
|
||||
import { getPayload } from 'payload';
|
||||
import config from '@payload-config';
|
||||
import type { Payload } from 'payload';
|
||||
|
||||
/**
|
||||
* One Payload instance per process. getPayload() is itself memoised by
|
||||
* Payload, but routing every caller through here keeps the config import in a
|
||||
* single place and gives page code one name to mock in tests.
|
||||
*
|
||||
* Never call this at module scope: CI builds the image with no database
|
||||
* reachable, so a build-time connection attempt fails the build.
|
||||
*/
|
||||
export function getCachedPayload(): Promise<Payload> {
|
||||
return getPayload({ config });
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Where Payload mounts, defined once.
|
||||
*
|
||||
* These are imported by payload.config.ts and asserted by
|
||||
* __tests__/payload/routes.test.ts. They live in their own module because
|
||||
* payload.config.ts cannot be imported from a Jest test: Payload ships
|
||||
* ESM-only, and next/jest's transformIgnorePatterns skips node_modules — you
|
||||
* cannot un-ignore a package by appending patterns, and forcing it through
|
||||
* `transpilePackages` would change how the production build bundles Payload
|
||||
* to serve a test. Keeping the values here makes them testable without
|
||||
* loading Payload at all.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Payload's API base. It must NOT be '/api': that path belongs to
|
||||
* app/(frontend)/api/[...path]/route.ts, a catch-all that proxies to FastAPI.
|
||||
* It would swallow every admin API call and forward it to the backend, and
|
||||
* the failure is silent — no error, just wrong responses.
|
||||
*/
|
||||
export const PAYLOAD_API_ROUTE = '/cms-api';
|
||||
|
||||
/** The admin panel. Kept out of the index by robots.txt and X-Robots-Tag. */
|
||||
export const PAYLOAD_ADMIN_ROUTE = '/admin';
|
||||
Reference in new issue
Block a user