Update AGENTS.md
This commit is contained in:
253
AGENTS.md
253
AGENTS.md
@@ -1,4 +1,4 @@
|
||||
# AGENTS.md — Convex Turbo Monorepo
|
||||
# AGENTS.md — Convex + Payload Turbo Monorepo
|
||||
|
||||
This is the definitive onboarding guide for AI agents (and humans) working in this
|
||||
repository. Read it fully before making any changes. It covers architecture, patterns,
|
||||
@@ -22,7 +22,7 @@ breaking things or introducing inconsistencies.
|
||||
11. [Docker & Deployment](#11-docker--deployment)
|
||||
12. [Code Style Reference](#12-code-style-reference)
|
||||
13. [Adding New Features — Checklists](#13-adding-new-features--checklists)
|
||||
14. [Expo App — Known Issues, Do Not Touch](#14-expo-app--known-issues-do-not-touch)
|
||||
14. [Expo App — Scaffold Only, Not Production-Ready](#14-expo-app--scaffold-only-not-production-ready)
|
||||
15. [Known Issues & Technical Debt](#15-known-issues--technical-debt)
|
||||
16. [Quick Command Reference](#16-quick-command-reference)
|
||||
|
||||
@@ -32,20 +32,24 @@ breaking things or introducing inconsistencies.
|
||||
|
||||
This is a personal full-stack monorepo template for spinning up self-hosted web
|
||||
applications quickly. The core idea: clone the repo, configure the environment
|
||||
variables, stand up two Docker containers for Convex, reverse-proxy them through
|
||||
nginx-proxy-manager, and you have a production-ready Next.js website with:
|
||||
variables, stand up the Convex services, connect the app to an external Postgres
|
||||
database for Payload CMS, reverse-proxy everything through nginx-proxy-manager,
|
||||
and you have a production-ready Next.js website with:
|
||||
|
||||
- **Self-hosted Convex** as the backend/database (not Convex Cloud)
|
||||
- **Convex Auth** with two providers: Authentik (OAuth SSO) and a custom Password
|
||||
provider with email OTP via a self-hosted UseSend instance
|
||||
- **Payload CMS** embedded inside the Next.js app for admin, REST/GraphQL APIs, and
|
||||
editable landing-page content backed by Postgres
|
||||
- **Sentry** for error tracking and performance monitoring
|
||||
- **Plausible** for privacy-focused analytics
|
||||
- A **stubbed Expo app** that is present for future mobile work but is not the focus
|
||||
|
||||
The primary deliverable from this template is the **Next.js web app**. Every project
|
||||
built from this template has been entirely focused on `apps/next/` and
|
||||
`packages/backend/`. The Expo app exists structurally but is non-functional and
|
||||
should be ignored unless explicitly asked to work on it.
|
||||
`packages/backend/`. The Next.js app now contains both the public frontend and the
|
||||
embedded Payload CMS surfaces. The Expo app exists structurally but is non-functional
|
||||
and should be ignored unless explicitly asked to work on it.
|
||||
|
||||
When working in this repo as an AI agent, you are almost certainly working on an
|
||||
existing running instance of this template — the Convex backend is already deployed,
|
||||
@@ -70,11 +74,27 @@ configured and difficult to re-stabilize.
|
||||
only works when the config itself is a `.js` file. Renaming it to `.ts` will break
|
||||
the build.
|
||||
|
||||
- **NEVER remove `withPayload(...)` from `apps/next/next.config.js`** — Payload's
|
||||
admin routes, REST API, GraphQL API, and generated integration files depend on the
|
||||
Next config being wrapped correctly.
|
||||
|
||||
- **NEVER rename `apps/next/src/proxy.ts` to `middleware.ts`** — `proxy.ts` is the
|
||||
correct and intentional name for the Next.js route handler file in Next.js 16+.
|
||||
This was an official rename from the Next.js team to reduce confusion. The file
|
||||
works exactly as middleware did; it's just named differently now.
|
||||
|
||||
- **NEVER manually edit Payload-generated files** — these are copied/generated by the
|
||||
Payload integration and may be rewritten at any time. Leave these alone unless you
|
||||
are explicitly regenerating Payload boilerplate:
|
||||
- `apps/next/payload-types.ts`
|
||||
- `apps/next/src/app/(payload)/layout.tsx`
|
||||
- `apps/next/src/app/(payload)/admin/importMap.js`
|
||||
- `apps/next/src/app/(payload)/admin/[[...segments]]/page.tsx`
|
||||
- `apps/next/src/app/(payload)/admin/[[...segments]]/not-found.tsx`
|
||||
- `apps/next/src/app/(payload)/api/[...slug]/route.ts`
|
||||
- `apps/next/src/app/(payload)/api/graphql/route.ts`
|
||||
- `apps/next/src/app/(payload)/api/graphql-playground/route.ts`
|
||||
|
||||
- **NEVER modify the Sentry configuration files without explicit instruction** — these
|
||||
took significant effort to get working correctly with the standalone Docker build,
|
||||
Plausible proxy, and self-hosted Sentry. The files to leave alone are:
|
||||
@@ -134,6 +154,10 @@ configured and difficult to re-stabilize.
|
||||
explicit file extensions for ESM imports. The `.js` extension is required even
|
||||
though the source files are `.ts`.
|
||||
|
||||
- **ALWAYS put user-authored Next.js routes in `apps/next/src/app/(frontend)/`** —
|
||||
the `(payload)` route group is the embedded Payload integration layer. Treat it as
|
||||
copied/generated infrastructure, not as the place for custom frontend pages.
|
||||
|
||||
---
|
||||
|
||||
## 3. Monorepo Architecture Overview
|
||||
@@ -186,6 +210,13 @@ imports needed.
|
||||
to the Convex deployment. The `scripts/` and `types/` directories sit outside
|
||||
`convex/` intentionally so they're not uploaded to Convex cloud.
|
||||
|
||||
`apps/next` now contains two distinct app-router route groups:
|
||||
|
||||
- `src/app/(frontend)/` — the public site and authenticated app pages you actually
|
||||
build features in
|
||||
- `src/app/(payload)/` — the embedded Payload admin/API surface that gets copied in
|
||||
from Payload's Next integration
|
||||
|
||||
### Turborepo pipeline
|
||||
|
||||
`turbo.json` defines the task pipeline. Key points for agents:
|
||||
@@ -207,17 +238,26 @@ to the Convex deployment. The `scripts/` and `types/` directories sit outside
|
||||
|
||||
### Before any development work can start
|
||||
|
||||
The Convex backend must be running and reachable. `bun dev:next` will fail or behave
|
||||
unexpectedly if it cannot connect to Convex. In practice, when you are working in this
|
||||
repo on an active project, the Convex containers are already running on the server and
|
||||
have been configured. If you are starting fresh from the template, see the README for
|
||||
the full setup walkthrough.
|
||||
The Convex backend must be running and reachable, and the Payload Postgres database
|
||||
must be reachable for any Payload-backed pages or admin routes to work. `bun dev:next`
|
||||
can start without one of these dependencies, but parts of the app will fail at runtime.
|
||||
In practice, when you are working in this repo on an active project, the Convex
|
||||
containers are already running on the server and the Payload database already exists.
|
||||
If you are starting fresh from the template, see the README for the full setup
|
||||
walkthrough.
|
||||
|
||||
The two Convex-related Docker containers are:
|
||||
|
||||
- **`convex-backend`** — the actual Convex runtime (default: `https://api.convexmonorepo.gbrown.org`)
|
||||
- **`convex-dashboard`** — the admin UI (default: `https://dashboard.convexmonorepo.gbrown.org`)
|
||||
|
||||
### Payload Postgres
|
||||
|
||||
Payload is configured inside `apps/next/src/payload.config.ts` and uses a Postgres
|
||||
connection string from `PAYLOAD_DB_URL`. Right now that database is expected to be
|
||||
external to `docker/compose.yml`; the Compose file passes the env vars through to the
|
||||
`next-app` container but does not provision a Postgres service for Payload.
|
||||
|
||||
### The `packages/backend/.env.local` file
|
||||
|
||||
You may notice a `.env.local` file in `packages/backend/`. This file is
|
||||
@@ -256,26 +296,28 @@ date whenever you add a new env var.**
|
||||
|
||||
### Complete variable reference
|
||||
|
||||
| Variable | Used By | Purpose | Sync to Convex? |
|
||||
| --------------------------------- | -------------- | ------------------------------------------------------------------------ | --------------- |
|
||||
| `NODE_ENV` | Next.js | `development` / `production` | No |
|
||||
| `SENTRY_AUTH_TOKEN` | Next.js build | Source map upload to Sentry | No |
|
||||
| `NEXT_PUBLIC_SITE_URL` | Next.js | Public URL of the Next.js app | No |
|
||||
| `NEXT_PUBLIC_CONVEX_URL` | Next.js | Convex backend API URL | No |
|
||||
| `NEXT_PUBLIC_PLAUSIBLE_URL` | Next.js | Self-hosted Plausible instance URL | No |
|
||||
| `NEXT_PUBLIC_SENTRY_DSN` | Next.js | Sentry DSN for error reporting | No |
|
||||
| `NEXT_PUBLIC_SENTRY_URL` | Next.js build | Self-hosted Sentry URL | No |
|
||||
| `NEXT_PUBLIC_SENTRY_ORG` | Next.js build | Sentry organization slug | No |
|
||||
| `NEXT_PUBLIC_SENTRY_PROJECT_NAME` | Next.js build | Sentry project name | No |
|
||||
| `CONVEX_SELF_HOSTED_URL` | Convex CLI | URL of the self-hosted Convex backend | No |
|
||||
| `CONVEX_SELF_HOSTED_ADMIN_KEY` | Convex CLI | Admin key for the self-hosted backend | No |
|
||||
| `CONVEX_SITE_URL` | Convex Auth | CORS domain for token exchange (localhost:3000 for dev) | Yes (Dashboard) |
|
||||
| `USESEND_API_KEY` | Convex backend | API key for the self-hosted UseSend instance | Yes |
|
||||
| `USESEND_URL` | Convex backend | URL of the self-hosted UseSend instance | Yes |
|
||||
| `USESEND_FROM_EMAIL` | Convex backend | From address for transactional emails (e.g. `App <noreply@example.com>`) | Yes |
|
||||
| `AUTH_AUTHENTIK_ID` | Convex backend | Authentik OAuth client ID | Yes |
|
||||
| `AUTH_AUTHENTIK_SECRET` | Convex backend | Authentik OAuth client secret | Yes |
|
||||
| `AUTH_AUTHENTIK_ISSUER` | Convex backend | Authentik issuer URL | Yes |
|
||||
| Variable | Used By | Purpose | Sync to Convex? |
|
||||
| --------------------------------- | ----------------- | ------------------------------------------------------------------------ | --------------- |
|
||||
| `NODE_ENV` | Next.js | `development` / `production` | No |
|
||||
| `SENTRY_AUTH_TOKEN` | Next.js build | Source map upload to Sentry | No |
|
||||
| `NEXT_PUBLIC_SITE_URL` | Next.js / Payload | Public URL of the Next.js app and Payload live-preview server URL | No |
|
||||
| `NEXT_PUBLIC_CONVEX_URL` | Next.js | Convex backend API URL | No |
|
||||
| `NEXT_PUBLIC_PLAUSIBLE_URL` | Next.js | Self-hosted Plausible instance URL | No |
|
||||
| `NEXT_PUBLIC_SENTRY_DSN` | Next.js | Sentry DSN for error reporting | No |
|
||||
| `NEXT_PUBLIC_SENTRY_URL` | Next.js build | Self-hosted Sentry URL | No |
|
||||
| `NEXT_PUBLIC_SENTRY_ORG` | Next.js build | Sentry organization slug | No |
|
||||
| `NEXT_PUBLIC_SENTRY_PROJECT_NAME` | Next.js build | Sentry project name | No |
|
||||
| `PAYLOAD_SECRET` | Payload CMS | Payload application secret | No |
|
||||
| `PAYLOAD_DB_URL` | Payload CMS | Postgres connection string used by Payload | No |
|
||||
| `CONVEX_SELF_HOSTED_URL` | Convex CLI | URL of the self-hosted Convex backend | No |
|
||||
| `CONVEX_SELF_HOSTED_ADMIN_KEY` | Convex CLI | Admin key for the self-hosted backend | No |
|
||||
| `CONVEX_SITE_URL` | Convex Auth | CORS domain for token exchange (localhost:3000 for dev) | Yes (Dashboard) |
|
||||
| `USESEND_API_KEY` | Convex backend | API key for the self-hosted UseSend instance | Yes |
|
||||
| `USESEND_URL` | Convex backend | URL of the self-hosted UseSend instance | Yes |
|
||||
| `USESEND_FROM_EMAIL` | Convex backend | From address for transactional emails (e.g. `App <noreply@example.com>`) | Yes |
|
||||
| `AUTH_AUTHENTIK_ID` | Convex backend | Authentik OAuth client ID | Yes |
|
||||
| `AUTH_AUTHENTIK_SECRET` | Convex backend | Authentik OAuth client secret | Yes |
|
||||
| `AUTH_AUTHENTIK_ISSUER` | Convex backend | Authentik issuer URL | Yes |
|
||||
|
||||
### Typesafe env vars — `apps/next/src/env.ts`
|
||||
|
||||
@@ -357,25 +399,25 @@ The current catalogs:
|
||||
|
||||
```json
|
||||
"catalog": {
|
||||
"@eslint/js": "^9.38.0",
|
||||
"@tailwindcss/postcss": "^4.1.16",
|
||||
"@types/node": "^22.19.15",
|
||||
"eslint": "^9.39.4",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
"@types/node": "^25.5.0",
|
||||
"eslint": "^10.1.0",
|
||||
"prettier": "^3.8.1",
|
||||
"tailwindcss": "^4.1.16",
|
||||
"typescript": "^5.9.3",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "^6.0.2",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"catalogs": {
|
||||
"convex": {
|
||||
"convex": "^1.33.1",
|
||||
"@convex-dev/auth": "^0.0.81"
|
||||
"@convex-dev/auth": "^0.0.87",
|
||||
"convex": "^1.34.1"
|
||||
},
|
||||
"react19": {
|
||||
"@types/react": "~19.1.0",
|
||||
"@types/react-dom": "~19.1.0",
|
||||
"react": "19.1.4",
|
||||
"react-dom": "19.1.4"
|
||||
"@types/react": "~19.2.14",
|
||||
"@types/react-dom": "~19.2.3",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -681,47 +723,80 @@ bun with-env npx convex env set JWKS "..."
|
||||
|
||||
### Files you should not casually modify
|
||||
|
||||
| File | Why |
|
||||
| ------------------------------- | ---------------------------------------------------------- |
|
||||
| `next.config.js` | Sentry, Plausible, standalone build — carefully configured |
|
||||
| `src/proxy.ts` | Auth routing + IP banning — the project's middleware |
|
||||
| `src/env.ts` | The env contract — add to it, don't restructure it |
|
||||
| `src/instrumentation.ts` | Sentry server setup — don't touch |
|
||||
| `src/instrumentation-client.ts` | Sentry client setup — don't touch |
|
||||
| `src/sentry.server.config.ts` | Sentry server config — don't touch |
|
||||
| `src/app/styles.css` | Tailwind setup + theme import — don't touch |
|
||||
| File / Area | Why |
|
||||
| ---------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `next.config.js` | Sentry, Plausible, Payload, standalone build — carefully configured |
|
||||
| `src/proxy.ts` | Auth routing + IP banning — the project's middleware |
|
||||
| `src/env.ts` | The env contract — add to it, don't restructure it |
|
||||
| `src/instrumentation.ts` | Sentry server setup — don't touch |
|
||||
| `src/instrumentation-client.ts` | Sentry client setup — don't touch |
|
||||
| `src/sentry.server.config.ts` | Sentry server config — don't touch |
|
||||
| `src/app/(frontend)/styles.css` | Tailwind setup + theme import — don't touch |
|
||||
| `payload-types.ts` | Auto-generated by Payload |
|
||||
| `src/app/(payload)/**` generated entries | Payload admin/API/layout files are copied/generated and may be replaced |
|
||||
|
||||
### Route structure
|
||||
|
||||
The app uses the Next.js App Router. All authenticated routes live in the `(auth)`
|
||||
route group (which doesn't create a URL segment — it's just for organization):
|
||||
The app uses the Next.js App Router, but it is now split into two top-level route
|
||||
groups:
|
||||
|
||||
| Route | File | Rendering | Purpose |
|
||||
| ------------------ | ------------------------------------- | ---------------- | ---------------------------------------------- |
|
||||
| `/` | `app/page.tsx` | Server Component | Landing page (hero, features, tech stack, CTA) |
|
||||
| `/sign-in` | `app/(auth)/sign-in/page.tsx` | Client Component | Sign in, sign up, email OTP — all in one |
|
||||
| `/profile` | `app/(auth)/profile/page.tsx` | Server Component | User profile management |
|
||||
| `/forgot-password` | `app/(auth)/forgot-password/page.tsx` | Client Component | Password reset flow |
|
||||
- **`(frontend)`** — all user-authored public pages and authenticated app pages
|
||||
- **`(payload)`** — the embedded Payload CMS admin/API surface copied from Payload
|
||||
|
||||
The `/profile` route is protected — `src/proxy.ts` redirects unauthenticated users to
|
||||
`/sign-in`. The `/sign-in` route redirects already-authenticated users to `/`.
|
||||
All new product/frontend routes should go in `(frontend)`, not `(payload)`.
|
||||
|
||||
| Route | File | Rendering | Purpose |
|
||||
| ------------------------- | ------------------------------------------------ | ---------------- | ---------------------------------------- |
|
||||
| `/` | `app/(frontend)/page.tsx` | Server Component | Landing page backed by a Payload global |
|
||||
| `/sign-in` | `app/(frontend)/(auth)/sign-in/page.tsx` | Client Component | Sign in, sign up, email OTP — all in one |
|
||||
| `/profile` | `app/(frontend)/(auth)/profile/page.tsx` | Server Component | User profile management |
|
||||
| `/forgot-password` | `app/(frontend)/(auth)/forgot-password/page.tsx` | Client Component | Password reset flow |
|
||||
| `/admin` | `app/(payload)/admin/[[...segments]]/page.tsx` | Server Component | Payload admin panel |
|
||||
| `/api/*` | `app/(payload)/api/[...slug]/route.ts` | Route Handlers | Payload REST API |
|
||||
| `/api/graphql` | `app/(payload)/api/graphql/route.ts` | Route Handler | Payload GraphQL API |
|
||||
| `/api/graphql-playground` | `app/(payload)/api/graphql-playground/route.ts` | Route Handler | Payload GraphQL playground |
|
||||
|
||||
The `/profile` and `/admin` routes are protected — `src/proxy.ts` redirects
|
||||
unauthenticated users to `/sign-in`. The `/sign-in` route redirects
|
||||
already-authenticated users to `/`.
|
||||
|
||||
To protect a new route, add its pattern to `isProtectedRoute` in `src/proxy.ts`:
|
||||
|
||||
```typescript
|
||||
const isProtectedRoute = createRouteMatcher([
|
||||
'/profile',
|
||||
'/admin',
|
||||
'/dashboard',
|
||||
'/settings',
|
||||
]);
|
||||
```
|
||||
|
||||
### Payload CMS integration
|
||||
|
||||
Payload is configured inside the Next app rather than as a separate service. The key
|
||||
pieces are:
|
||||
|
||||
- **`apps/next/src/payload.config.ts`** — the source of truth for Payload config,
|
||||
collections, globals, editor, secret, and Postgres adapter
|
||||
- **`apps/next/tsconfig.json`** — defines the `@payload-config` alias used by the
|
||||
generated admin/API files
|
||||
- **`apps/next/src/payload/collections/`** and `apps/next/src/payload/globals/` — the
|
||||
editable Payload schema files you should actually work in
|
||||
- **`apps/next/src/lib/payload/`** — server helpers for obtaining the cached Payload
|
||||
client and fetching CMS content
|
||||
- **`apps/next/src/components/payload/refresh-route-on-save.tsx`** — enables live
|
||||
preview refreshes for the landing page when `?preview=true` is present
|
||||
|
||||
The current homepage is backed by the `landing-page` Payload global. The server page at
|
||||
`apps/next/src/app/(frontend)/page.tsx` calls
|
||||
`apps/next/src/lib/payload/get-landing-page-content.ts`, which merges saved Payload
|
||||
content with defaults from `apps/next/src/components/landing/content.ts`.
|
||||
|
||||
### The dual Convex provider setup
|
||||
|
||||
Two providers are required and both must be present:
|
||||
|
||||
**1. `ConvexAuthNextjsServerProvider`** — wraps the root `<html>` element in
|
||||
`app/layout.tsx`. This is the server-side half that handles cookie reading and
|
||||
`app/(frontend)/layout.tsx`. This is the server-side half that handles cookie reading and
|
||||
initial token passing. It has no visible UI.
|
||||
|
||||
**2. `ConvexClientProvider`** — a `'use client'` component in
|
||||
@@ -730,7 +805,7 @@ and initializes the `ConvexReactClient`. All client-side reactive queries and
|
||||
mutations flow through this.
|
||||
|
||||
```tsx
|
||||
// app/layout.tsx (server)
|
||||
// app/(frontend)/layout.tsx (server)
|
||||
<ConvexAuthNextjsServerProvider>
|
||||
<html lang='en'>
|
||||
<body>
|
||||
@@ -743,6 +818,9 @@ mutations flow through this.
|
||||
Removing either provider breaks auth. The server provider is needed for SSR token
|
||||
hydration; the client provider is needed for reactive updates.
|
||||
|
||||
Payload uses a separate generated layout at `apps/next/src/app/(payload)/layout.tsx`.
|
||||
Do not try to merge the frontend and Payload layouts into one file.
|
||||
|
||||
### SSR data preloading — the preferred pattern for new pages
|
||||
|
||||
For any page that needs Convex data, use `preloadQuery` on the server and
|
||||
@@ -752,7 +830,7 @@ SSR-rendered content.
|
||||
**Server component (the page file):**
|
||||
|
||||
```tsx
|
||||
// app/(auth)/some-page/page.tsx
|
||||
// app/(frontend)/(auth)/some-page/page.tsx
|
||||
import { SomeComponent } from '@/components/some-component';
|
||||
import { preloadQuery } from 'convex/nextjs';
|
||||
|
||||
@@ -834,6 +912,7 @@ This file is the Next.js proxy/middleware. It does two things in sequence:
|
||||
|
||||
2. **Auth routing** — `convexAuthNextjsMiddleware` handles authentication:
|
||||
- Unauthenticated users hitting `/profile` are redirected to `/sign-in`
|
||||
- Unauthenticated users hitting `/admin` are redirected to `/sign-in`
|
||||
- Authenticated users hitting `/sign-in` are redirected to `/`
|
||||
|
||||
Session cookies are configured with a 30-day max age.
|
||||
@@ -865,24 +944,26 @@ This handles the nginx-proxy-manager reverse proxy setup correctly.
|
||||
- **`serverExternalPackages: ['require-in-the-middle']`** — Sentry compatibility
|
||||
- **`transpilePackages: ['@gib/backend', '@gib/ui']`** — workspace packages need
|
||||
transpilation since Next.js doesn't transpile `node_modules` by default
|
||||
- **`withPayload(config)`** — required for embedded Payload admin/API support
|
||||
- **`images.remotePatterns`** — currently only allows `*.gbrown.org`. If you're
|
||||
deploying for a different domain, update this or profile pictures won't load.
|
||||
- **`serverActions.bodySizeLimit: '10mb'`** — allows large file uploads for avatar
|
||||
- The config is wrapped with `withPlausibleProxy` then `withSentryConfig`
|
||||
- The config is wrapped with `withPlausibleProxy`, then `withPayload`, then
|
||||
`withSentryConfig`
|
||||
|
||||
### Fonts
|
||||
|
||||
Fonts are configured in `apps/next/src/app/layout.tsx` using `next/font`. The current
|
||||
typeface system:
|
||||
Fonts are configured in `apps/next/src/app/(frontend)/layout.tsx` using `next/font`.
|
||||
The current typeface system:
|
||||
|
||||
- **Kanit** — display font used in the header logo and CTA (loaded via `next/font/google`)
|
||||
- **Poppins** — primary sans-serif body font
|
||||
- **Libre Baskerville** — serif font (available for editorial use)
|
||||
- **Victor Mono** — monospace font (available for code blocks)
|
||||
- **Geist** — primary sans font for the frontend layout
|
||||
- **Geist Mono** — monospace font for the frontend layout
|
||||
- **Kanit** — display font loaded locally in `src/components/layout/header/index.tsx`
|
||||
for the brand wordmark
|
||||
|
||||
The fonts are injected as CSS variables and mapped in `tools/tailwind/theme.css`.
|
||||
To change fonts, update the `next/font` imports in `layout.tsx` and update the
|
||||
corresponding CSS variable assignments in `theme.css`.
|
||||
To change the frontend base fonts, update the `next/font` imports in
|
||||
`apps/next/src/app/(frontend)/layout.tsx`. If you also want the brand wordmark to
|
||||
change, update `apps/next/src/components/layout/header/index.tsx`.
|
||||
|
||||
### Analytics and monitoring
|
||||
|
||||
@@ -1195,7 +1276,13 @@ deployment), these things should be updated:
|
||||
|
||||
- `apps/next/src/lib/metadata.ts` — update the title template and metadata
|
||||
- `apps/next/next.config.js` — update `images.remotePatterns` for your domain
|
||||
- `apps/next/src/app/layout.tsx` — update the root `<html lang>`, site title, etc.
|
||||
- `apps/next/src/app/(frontend)/layout.tsx` — update the root `<html lang>`, site title, etc.
|
||||
- `apps/next/src/components/landing/content.ts` — update the fallback landing-page copy,
|
||||
repository URL, and quick-start text
|
||||
- `apps/next/src/payload/globals/landing-page.ts` — update or replace the current landing
|
||||
page global schema
|
||||
- `apps/next/src/payload.config.ts` — add/remove Payload collections and globals as the
|
||||
project evolves
|
||||
- Root `package.json` — update the workspace `name` field to fit the new project
|
||||
- `/.env` — fill out all values for the new deployment
|
||||
- `docker/.env` — fill out container names and domain URLs
|
||||
@@ -1224,7 +1311,8 @@ deployment), these things should be updated:
|
||||
|
||||
### Adding a new page
|
||||
|
||||
1. Create `apps/next/src/app/<route>/page.tsx`
|
||||
1. Create the page inside `apps/next/src/app/(frontend)/...` unless you are explicitly
|
||||
working on the embedded Payload admin/API surface
|
||||
2. If the page needs data: use the `preloadQuery` + `usePreloadedQuery` SSR pattern
|
||||
3. If the page should be protected: add its path to `isProtectedRoute` in `src/proxy.ts`
|
||||
4. Add a layout file if you need a custom `<title>`:
|
||||
@@ -1233,6 +1321,15 @@ deployment), these things should be updated:
|
||||
```
|
||||
5. Run `bun typecheck` to validate
|
||||
|
||||
### Adding or changing Payload content
|
||||
|
||||
1. Edit the relevant schema file in `apps/next/src/payload/collections/` or
|
||||
`apps/next/src/payload/globals/`
|
||||
2. Register the collection/global in `apps/next/src/payload.config.ts`
|
||||
3. Fetch the content from server code via `apps/next/src/lib/payload/`
|
||||
4. If you need fresh Payload types, regenerate `apps/next/payload-types.ts`
|
||||
5. Do not hand-edit the generated files in `apps/next/src/app/(payload)/`
|
||||
|
||||
### Adding a new environment variable
|
||||
|
||||
See the 4-step checklist in [Section 5](#5-environment-variables--complete-reference).
|
||||
|
||||
@@ -11,7 +11,7 @@ export default buildConfig({
|
||||
editor: lexicalEditor(),
|
||||
collections: [Users],
|
||||
globals: [LandingPage],
|
||||
secret: env.PAYLOAD_SECRET ?? '',
|
||||
secret: env.PAYLOAD_SECRET,
|
||||
db: postgresAdapter({
|
||||
pool: {
|
||||
connectionString: env.PAYLOAD_DB_URL,
|
||||
|
||||
Reference in New Issue
Block a user