# Introduction

How the CMS + Next.js track is organized and what you need before you start


Build a Next.js website that displays erxes CMS content.

The website examples use the Next.js App Router and native `fetch`. They are application examples; they are not shipped by the product repository.

## How content reaches the website

The website's server calls the erxes gateway at its configured `/graphql` endpoint. The gateway authenticates the supplied credential and forwards the request context to the Content API. A server component can render that data directly; an interactive browser component can call a narrowly scoped endpoint on the website.

The gateway's [hostname helper](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/erxes-api-shared/src/utils/utils.ts) considers forwarded hostname headers as well as the request hostname. Tenant database selection also depends on deployment configuration. Use the gateway URL and proxy configuration for your installation.

## Credentials and operation families

A **Client Portal token** is sent as `x-app-token`. The gateway verifies the JWT and identifies the portal named by its `clientPortalId` claim. A separate `client-auth-token` can identify a signed-in portal user. See [gateway authentication](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/gateway/src/middlewares/userMiddleware.ts).

An **Apps token**, sent as `erxes-app-token`, authenticates an application principal. Its access depends on the application's configuration and backend permission checks. Keep this administrative credential on the server.

The CMS exposes two families:

- `cms*` operations serve authenticated administration and tooling.
- `cp*` operations serve client-portal integrations and generally derive their portal from request context ([`forClientPortal` resolver wrapper](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/erxes-api-shared/src/utils/apollo/wrapperResolvers.ts)).

A prefix alone does not guarantee that an operation is read-only or returns only published content. For example, `cpPostList` accepts a status filter, and `cpPost` returns a matching record without adding a publication filter. The examples enforce publication status before returning data to visitors. See [post resolvers](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/src/modules/cms/graphql/queries/posts.ts) and [query builders](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/src/modules/cms/utils/query-builders.ts).

## Keep the integration on the server

Store credentials in server environment variables and keep modules that read them out of the browser import graph. Do not put them in `NEXT_PUBLIC_*` variables or a Next.js configuration `env` block.

The [gateway's CORS configuration](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/gateway/src/main.ts) determines which browser origins it accepts. A separately hosted website may or may not be allowed, depending on that configuration. Server-to-server requests are not subject to browser CORS checks.

The browser example uses a fixed post-search endpoint. Keeping a credential on the server is insufficient if an unrestricted proxy lets visitors execute any operation with it.

## Social publishing is a separate integration

The CMS also has administrative sharing through Postiz. Reading published content through `cpPostList` does not enable social publishing. The [sharing service](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/src/modules/cms/postiz/service.ts) checks membership, CMS access, publication permissions, language access, and the selected post before queuing a delivery.

This feature requires the corresponding `agent` service integration: the [bridge](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/src/modules/cms/postiz/bridge.ts) calls its `postizCms.execute` procedure. That service is not implemented in this repository. Confirm its availability in your deployment before enabling sharing; starting `content_api` alone is insufficient.

See [Social publishing operations](https://erxes.io/docs/content-plug-cms-next-developers-queries#social-publishing-operations) for the CMS-side operations. These administrative operations do not belong in the website's public search endpoint.

## Follow the guides

1. [Setup](https://erxes.io/docs/content-plug-cms-next-developers-setup): configure the portal credential and server fetch helper.
2. [Queries](https://erxes.io/docs/content-plug-cms-next-developers-queries): check operation names, filters, pagination, and response shapes.
3. [Server-side Rendering](https://erxes.io/docs/content-plug-cms-next-developers-ssr): render published content and handle missing records.
4. [Client-side Rendering](https://erxes.io/docs/content-plug-cms-next-developers-csr): add interactive search through a fixed website endpoint.
5. [CMS Migration](https://erxes.io/docs/content-plug-cms-next-developers-cms-migration): update an older integration and verify its behavior.

For product installation, see [Local Setup](https://erxes.io/docs/local-setup) or [Self-Hosting](https://erxes.io/docs/self-hosting). For the separate template repositories, see the [template developer track](https://erxes.io/docs/content-plug-template-developers-introduction).

