Skip to content

Latest commit

 

History

History
132 lines (100 loc) · 8.54 KB

File metadata and controls

132 lines (100 loc) · 8.54 KB

AGENTS.md

Project Snapshot

This repository is the official website for Memos at usememos.com. It is a Next.js + TypeScript + Tailwind app that serves a static marketing/documentation site (Fumadocs + MDX) and an authenticated product surface (a Clerk-gated dashboard and /api handlers).

Treat it as a Next.js 16 marketing/docs site plus an authenticated product app. The marketing/docs surface stays static; the authenticated surface is dynamic. Before adding persistence, a new Cloudflare binding, or a new external dependency, follow the conventions in docs/architecture.md rather than introducing them ad-hoc.

Tech Stack

  • Framework: Next.js 16 App Router
  • Runtime target: Cloudflare Workers through OpenNext
  • Content: Fumadocs, MDX, and file-based content under content/
  • Styling: Tailwind CSS 4.x with the local design system
  • Icons: Lucide React using the XxxIcon naming convention
  • Validation: Zod schemas in source.config.ts and server route schemas
  • Auth: Clerk (@clerk/nextjs), optional and env-gated via isClerkConfigured()
  • Node.js: 24.0.0 or newer (pinned in .nvmrc)

Common Commands

Use pnpm for all package scripts.

Task Command Notes
Install dependencies pnpm install Runs Fumadocs source generation automatically
Develop locally pnpm dev Starts Next.js with Turbopack on port 3000
Run tests pnpm test Vitest (*.test.ts/*.test.tsx); pnpm test:watch to watch
Build pnpm build Full production build for the static site
Start production server pnpm start Runs the local Next.js production server
Lint pnpm lint Runs static revalidation audit, metadata audit, and Biome
Format pnpm format Runs Biome format with --write
Check and write fixes pnpm check Runs biome check --write
Refresh generated docs pnpm docs:refresh Downloads OpenAPI specs, regenerates API MDX, formats it, and rebuilds Fumadocs source
Generate Fumadocs source pnpm docs:generate:source Rebuilds ignored .source/ files without downloading API specs
Generate Cloudflare types pnpm typegen Writes cloudflare-env.d.ts
Build Cloudflare Worker pnpm run build:worker Generates Fumadocs source and builds the OpenNext artifact
Cloudflare preview pnpm run preview Builds with OpenNext and serves the Workers runtime on port 8788
Cloudflare deploy pnpm run deploy Deploys an existing OpenNext artifact, preserving existing vars
Cloudflare version upload pnpm run upload Uploads an existing OpenNext artifact without promoting it
Cloudflare dry run pnpm run deploy:dry-run Builds and packages through Wrangler without deploying
Smoke test SMOKE_BASE_URL=http://localhost:8788 pnpm run smoke Run against pnpm run preview
Metadata audit pnpm run metadata:audit Checks metadata title rules
Open Graph audit pnpm run og:audit Audits OG output

For day-to-day work, use pnpm dev. Before deployment-sensitive changes, prefer pnpm run preview because it runs the built app in the Cloudflare Workers runtime instead of the local Node.js server.

Standard verification is pnpm test, pnpm lint, and pnpm build, with pnpm run preview plus smoke tests when the change could affect production routing or runtime behavior. CI runs test, lint, and the Cloudflare dry-run build.

Architecture

See docs/architecture.md for the full architecture and the conventions for expanding the authenticated app (route groups, server-domain layout, the data-access store seam, runtime/caching rules, the auth seam, and a step-by-step for adding an authed feature).

Routes

  • src/app/(public)/ contains unauthenticated public routes.
  • src/app/(public)/docs/ serves Fumadocs documentation.
  • src/app/(public)/blog/ serves blog posts from content/blog/.
  • src/app/(public)/changelog/ serves release notes from content/changelog/.
  • src/app/(public)/features/ contains the feature index and SEO pages at /features/[slug].
  • src/app/(public)/brand/, pricing/, privacy/, sponsors/, and use-cases/ contain static marketing pages.
  • src/app/(tools)/scratchpad/ contains the standalone client-side scratchpad tool.
  • src/app/(app)/ is the authenticated product surface (Clerk-gated, noindex, dynamic); the dashboard lives here. src/app/(auth)/ holds sign-in/sign-up boundaries. Add authed features following docs/architecture.md.

Content

  • Documentation MDX lives in content/docs/.
  • Blog MDX lives in content/blog/.
  • Changelog MDX lives in content/changelog/.
  • source.config.ts defines content schemas and MDX processing.
  • src/shared/content/source.ts configures Fumadocs loaders for docs, blog, and changelog content.
  • .source/ is generated by fumadocs-mdx; never edit it directly.

Feature and Use-Case Data

  • Feature page data lives under src/features/marketing/data/features/.
  • Use-case page data lives under src/features/marketing/data/use-cases/.
  • Feature SEO pages are statically generated from feature slugs with generateStaticParams.
  • To add a feature page, update the relevant slug, data, and accessor modules together.

Components

  • Marketing components: src/features/marketing/components/
  • Docs components and helpers: src/features/docs/components/ and src/features/docs/lib/
  • Editorial components and helpers: src/features/editorial/components/ and src/features/editorial/lib/
  • Scratchpad components, hooks, and helpers: src/features/scratchpad/
  • Shared UI primitives: src/shared/ui/
  • Shared layout and navigation config: src/shared/config/layout.tsx
  • Shared utilities, including cn(): src/shared/lib/utils.ts

Coding Conventions

  • Prefer existing feature-folder patterns over creating new top-level structures.
  • Use the @/* alias for imports from src/*.
  • Use @/.source only for generated Fumadocs output from .source/server.ts.
  • Import Lucide icons as XxxIcon, for example import { ShieldIcon } from "lucide-react".
  • Pass icons as React elements to components, not as string names.
  • Keep MDX components registered through getMDXComponents in src/mdx-components.tsx.
  • Maintain dark mode support with dark: classes when changing UI.
  • Use py-24 for standard marketing section padding and rounded-2xl for card-like surfaces unless the surrounding component uses a different local pattern.
  • Use the teal/cyan palette, especially teal-600 and cyan-600, for primary marketing actions.
  • Remove emojis from marketing content; use Lucide icons instead.
  • Keep pages mobile-first and responsive.

SEO and Metadata

  • Preserve comprehensive Open Graph and Twitter card metadata.
  • Keep feature pages search-oriented with clear titles, descriptions, benefits, use cases, and technical details.
  • Update src/app/sitemap.ts when adding routes that should be discoverable.
  • Run metadata or OG audits when changing metadata structure.

Cloudflare Notes

OpenNext is configured with static-assets incremental caching for this mostly static site. Treat content updates as rebuild and redeploy events. If future ISR or runtime revalidation is required, design a persistent cache backend such as R2 or KV before enabling it.

Cloudflare Workers Builds uses the repository root with these commands:

  • Build command: pnpm run build:worker
  • Deploy command: pnpm run deploy
  • Version command: pnpm run upload

The build command creates .open-next/ once. The deploy command promotes that artifact to production, while the version command uploads it without promotion for non-production builds.

Use pnpm run preview or pnpm run deploy:dry-run to validate Cloudflare production behavior. pnpm start only validates the local Next.js production server.

Gotchas

  • postinstall only regenerates the ignored Fumadocs .source/ files. Run pnpm docs:refresh explicitly when refreshing the committed OpenAPI specs and generated API MDX. The refresh falls back to committed openapi/*.yaml files if the network fetch fails.
  • pnpm may warn about ignored build scripts for esbuild and sharp; this is cosmetic for normal development.
  • The production build generates hundreds of static pages, so pnpm build can take a while.
  • Do not edit generated files in .source/.
  • Auth (Clerk) and /api handlers already exist; the required env vars are NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY (auth is inert when unset). Do not add a database, a new Cloudflare binding, or a new external dependency ad-hoc — follow the sanctioned path in docs/architecture.md ("Future data layer").