JJourney AI

Site template

How the Next.js site template that publishes Journey AI content is structured, configured, and turns a request into a page.

Updated 8 October 20265 min read

This page covers what the site template is, how the project is laid out, which environment variables it needs, and how a request becomes a page.

Journey AI is a headless CMS. Editors work in the panel, and the API serves the content as JSON. The site visitors actually see is rendered by the site template: a Next.js project in the Cms-Landing-Core repository. Every new site starts as a copy of this template.

Tech stack

AreaUsed
FrameworkNext.js 16 (App Router), React 19, TypeScript
StylingTailwind CSS v4, shadcn/ui, lucide-react
Formsreact-hook-form, zod
Contentreact-markdown, remark-gfm
Package managerpnpm only
Outputoutput: "standalone", Docker and Node 22

Quick start

Terminal
git clone <Cms-Landing-Core> my-site && cd my-site
cp .env.example .env.local   # fill in NEXT_PUBLIC_API_URL and NEXT_PUBLIC_SITE_URL
pnpm install
pnpm dev                     # http://localhost:3000
pnpm exec tsc --noEmit && pnpm lint

New site projects are created with the repository's scripts/create-landing-project.sh script. Node 22 or later is required; use pnpm only as the package manager.

The README is out of date

The repository's README refers to folders that no longer exist (templates/next-core/, examples/proxy.ts). Follow this page and the repository's .env.example file when setting up.

Project structure

proxy.ts
page.tsx
layout.tsx
sitemap.ts
robots.txt/route.ts
indexnow.txt/route.ts
globals.css
types/cms.ts
next.config.ts
.env.example

Per-project configuration

FileWhat you set
src/lib/template-config.tsHome page slug (HOME_SLUG), default language (DEFAULT_LANGUAGE), HTML_LANG, OG_LOCALE, header and footer slugs, paths excluded from the sitemap, form messages
src/lib/middleware/languages.tsLanguages enabled on the site (TEMPLATE_LANGUAGES)
src/lib/middleware/config.tsLanguage prefix behavior, proxy settings
src/app/globals.cssTailwind v4 @theme and shadcn color variables
next.config.tsRemote image sources, panel domains allowed to frame the site

Environment variables

Fill in values following the comments in .env.example. Never commit secret values.

VariablePurpose
NEXT_PUBLIC_API_URLRequired. CMS API root, for example https://api.example.com.
PRIVATE_API_ADDRESSOptional. Internal CMS address used on the server side.
NEXT_PUBLIC_SITE_URLRoot for canonical, Open Graph, and share URLs.
NEXT_PUBLIC_SITE_NAMESite name used in the title template.
PREVIEW_MODEServer-only. When true, the deployment runs as the preview site.
NEXT_PUBLIC_INSPECTOR_ENABLEDPanel inspector. Enable on the preview deployment only.
SITE_PROXY_SECRETShared key for forwarding visitor details to the CMS on form submissions.
REVALIDATE_ALLOWED_ORIGINSOrigins allowed to call the revalidation endpoint.
REVALIDATE_NODESOther server instances that revalidation is forwarded to.
NEXT_PUBLIC_BUILD_IMG_SERVER_ADDRESS, NEXT_PUBLIC_RUNTIME_IMG_SERVER_ADDRESSPreconnect targets for the image CDN.

Without NEXT_PUBLIC_API_URL, development shows a setup screen. In production, pages return 404.

A single content route

The site has no hand-written pages. All content goes through one catch-all route: src/app/[[...slug]]/page.tsx. The address /kurumsal/ekip maps to the slug kurumsal/ekip, and / maps to HOME_SLUG.

How a request becomes a page

The proxy runs

src/proxy.ts skips static files, cleans up malformed URL leftovers, applies the redirect map from the CMS, 301-redirects uppercase paths to lowercase, and resolves the language prefix.

The page is fetched from the CMS

The route calls GET /api/v1/page/detail/{language}?path={slug}. The call is wrapped in react.cache, so metadata and the page body share a single request.

The component tree is rendered

Each top-level item in components[] is turned into a React component by DynamicComponent. See Components.

Metadata is generated

buildMetadata builds the title, description, canonical, Open Graph, Twitter, and robots tags from the SEO fields. PageSchemas prints the JSON-LD blocks.

The shell is added

The header, footer, and navigation come from the template fetched on the server in the root layout, so they are part of the first HTML response.

The result is cached

The page is cached with 300-second ISR. See Caching and preview.

Code conventions

  • Write server components by default. Add "use client" only when you need state or a browser API.
  • Stay on the Tailwind scale: text-lg, not text-[17px].
  • Use semantic tokens instead of raw colors: bg-background, text-muted-foreground.
  • Icons come from lucide-react only. Load GSAP lazily through src/lib/gsap.ts, never at module level.

Next steps

Related pages

On this page