Qingkong

Project structure

A map of the codebase — where routes, components, content, and config live.

The app follows the Next.js App Router layout, with a few conventions worth knowing before you start adding features.

Directory layout

content/        Folder-owned MDX entries and their images
public/         Static assets that do not belong to content
src/
  app/          App Router routes — [locale] for locale-addressed pages,
                dash for the Dashboard root, and the metadata routes
  components/   Shared, app-local presentational components
  env/
    client.ts   Validated browser-visible environment variables
    server.ts   Validated server-only environment variables
  lib/          Cross-cutting app infrastructure with multiple consumers
tests/
  e2e/          Playwright specs grouped by user-facing feature
  fixtures/     Test resources with setup and teardown
  helpers/      Stateless test utilities and assertions

Every app also keeps its shared toolchain entry points at the app root: .env, .env.example, .envrc, .gitignore, README.md, components.json, next.config.ts, package.json, playwright.config.ts, postcss.config.mjs, source.config.ts, tsconfig.json, vercel.json, vitest.config.ts, vitest.d.ts, and workspace.env. Vercel owns every runtime value; Development values are pulled into the ignored .env, while .env.example is the committed key-only manifest. Product-specific configuration and directories may be added alongside this baseline.

Keep only Next.js App Router file conventions and CSS stylesheets whose basename matches an App Router file convention below src/app, such as page.tsx, layout.tsx, loading.tsx, route.ts, metadata files, page.css, and layout.css. Custom stylesheet names such as styles.css are not allowed. Put components, helpers, schemas, and tests in their corresponding directories outside src/app.

Routing

Locale-addressed pages live under src/app/[locale] and are statically generated. The marketing surfaces (home, blog, legal, authors) share a layout in the (marketing) route group; the docs section brings its own fumadocs shell.

The Dashboard is a separate, locale-neutral route family rooted at /dash. Every locale uses that stable pathname; the user's locale preference controls its translated interface instead. Locale-prefixed forms such as /zh/dash are invalid.

Content

Docs, blog posts, legal pages, and authors are MDX files under content/, loaded through fumadocs. Add a file, and it shows up — no registration step:

content/blog/my-post/index.mdx  →  /blog/my-post
content/docs/my-page/index.mdx  →  /docs/my-page
content/legal/privacy/index.mdx →  /legal/privacy

Internationalization & SEO

Locale routing, canonical URLs, and the hreflang/JSON-LD wiring are already in place — see the Guides for how they fit together.

On this page