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
34 lines
981 B
TypeScript
34 lines
981 B
TypeScript
import type { CollectionConfig } from 'payload';
|
|
|
|
/**
|
|
* The site's only authenticated surface. There is one account and no
|
|
* registration: `create` is closed to everyone, so the first user is seeded
|
|
* with `payload create-first-user` and no one can add another through the API.
|
|
*/
|
|
export const Users: CollectionConfig = {
|
|
slug: 'users',
|
|
auth: {
|
|
// Slows credential stuffing against a panel that is on the public
|
|
// internet. Five attempts, then a ten-minute lock.
|
|
maxLoginAttempts: 5,
|
|
lockTime: 10 * 60 * 1000,
|
|
},
|
|
access: {
|
|
create: () => false,
|
|
read: ({ req }) => Boolean(req.user),
|
|
update: ({ req }) => Boolean(req.user),
|
|
delete: () => false,
|
|
},
|
|
admin: { useAsTitle: 'email' },
|
|
fields: [
|
|
{
|
|
name: 'displayName',
|
|
type: 'text',
|
|
required: true,
|
|
// Rendered as the byline on every post. First name only — the site
|
|
// publishes no surname and no employer.
|
|
defaultValue: 'Tudor',
|
|
},
|
|
],
|
|
};
|