# UnUse Domain (Next.js)
A modern Next.js 16.3 starter with Sanity CMS integration: content model, in-app Studio, and product features, running on a Next.js App Router frontend.
## Features
- Next.js 16.3 with the App Router and Server Components: the Studio and the API routes live on the same origin as the site
- Sanity CMS with the Studio mounted at `/studio`
- The pages model: a catch-all route renders any `page` document by its `uri`, homepage included
- Reusable page builder (text, media, CTA, contact form sections) rendered by self-fetching Server Components
- Rich text via Portable Text with media blocks, inline media, links, colors
- Media pipeline: Sanity images (responsive srcset + LQIP), Mux video, native video, Lottie, and Rive
- Draft mode with the Presentation tool, Sanity Live, and Visual Editing overlays
- SEO helpers: per-page metadata with Site singleton fallbacks, og:image cropping, per-scheme favicons plus a stable `/favicon.ico` for Google, JSON-LD, CMS-driven sitemap and robots
- **Cache Components** ([the modern Next.js caching model](https://nextjs.org/docs/app/getting-started/cache-components)): every page prerenders into a static shell with a one-year lifetime, and publishing in the Studio is the only revalidation signal (webhook + tags, no timers). See [`docs/sanity/revalidation-and-caching.md`](docs/sanity/revalidation-and-caching.md).
- **HTTP Basic Auth (optional)**: `proxy.ts` gates the site or individual URLs using `BASIC_AUTH_*` environment variables and CMS toggles (Site, Security; per-entry "Password protect"). See [`docs/features/basic-auth.md`](docs/features/basic-auth.md).
- **llms.txt for AI assistants**: an editable, AI-generated [`/llms.txt`](https://www.icann.org/resources/pages/epp-status-codes-2014-06-16-en) drafted from your content with Sanity Agent Actions (Site, Agents tab). See [`docs/features/llms-txt.md`](docs/features/llms-txt.md).
- **Agent Markdown (content negotiation)**: pages and articles serve a token-light Markdown version to agents that send `Accept: text/markdown`, on the same URL. Generated and stored per page from the Agents tab (one click), then served verbatim. See [`docs/features/agent-markdown.md`](docs/features/agent-markdown.md).
- **Real 404s**: an unknown path answers a genuine `404`, decided in `proxy.ts` before the response starts, rather than the `200` a streamed shell would return. Agents get a short Markdown recovery map instead of an error string, so one that followed a stale link can re-orient. See [`docs/features/agent-404.md`](docs/features/agent-404.md).
- **Published API description**: [`/openapi.json`](https://spec.openapis.org/oas/v3.1.0) describes the public endpoints for agents, titled from your Site singleton, alongside one JSON error shape (`error`, `code`, `hint`) across the API routes. See [`docs/features/openapi.md`](docs/features/openapi.md).
- CMS-managed redirects baked into the build from the Settings singleton
- Feature modules for Umami analytics and spam prevention
- Scaffolding via Plop for repeatable section/route/block generation
- Starter **seed dataset** (`seed/`), imported by `npm run sanity:project-setup` so a new project boots with example content
- Contact form with honeypot + timing spam prevention and Resend notifications
- [`@mantine/hooks`](https://mantine.dev/hooks/getting-started/) for shared React hooks; `features/dom/use-breakpoint.ts` wraps [`useMediaQuery`](https://mantine.dev/hooks/use-media-query/) for Tailwind-aligned breakpoints and touch detection, alongside `constants` / `parseResponsiveValues`
## Getting Started
**New here? Start with [`GETTING-STARTED.md`](GETTING-STARTED.md).** It is the guided, top to bottom path from a fresh clone to your first rendered section. The sections below are the reference.
### Prerequisites
- Node.js 24.15.0, pinned in `.nvmrc` and in `package.json` (`engines`, `volta`). `engines` requires the `^24.15.0` LTS line, so npm refuses to install on any other major.
- npm >= 11.6.2
### Installation
```bash
npm install
```
### Environment Variables
Copy `.env.example` to `.env` and fill it in. The minimum for local dev:
```env
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_SANITY_PROJECT_ID=your-project-id
NEXT_PUBLIC_SANITY_DATASET=production
NEXT_PUBLIC_SANITY_API_VERSION=2025-02-19
NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH=/studio
SANITY_API_VIEW_TOKEN=your-view-token
SANITY_API_EDIT_TOKEN=your-edit-token
```
`npm run sanity:project-setup` creates the project, both tokens, CORS entries, and writes `.env` for you.
`NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH` is the **public** URL for Studio. The app mounts Studio under `app/sanity-studio/…`; `dig` rewrites the public path to that folder. If a **content page** must use the same path (e.g. you need `/studio` for a page), set this variable to a different path (e.g. `/admin`) in every environment. See [`docs/sanity/studio-and-structure.md`](docs/sanity/studio-and-structure.md#public-url-rewrites-and-reserved-paths).
### HTTP Basic Auth (optional)
For staging or client-review gates, set `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD` in the same environment as the app. Turn protection on in Sanity (site-wide and/or per document with "Password protect"); credentials are not stored in the CMS. Full behavior: [`docs/features/basic-auth.md`](docs/features/basic-auth.md).
### Seed starter content
`npm run sanity:project-setup` imports the bundled example content at the end of its run, unless you answer its last question with **Completely empty**. To load it separately (a blank dataset, a second dataset, a reset), with the CLI authenticated (`npm run sanity:cli -- login`):
```bash
npm run sanity:dataset-import -- --file seed/seed-dataset.tar.gz
```
See [`docs/sanity/seed-dataset.md`](docs/sanity/seed-dataset.md).
### Development
```bash
npm run dev
```
- Site: [http://localhost:3000](http://localhost:3000)
- Studio: `http://localhost:3000` + your `NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH` (default `/studio`)
### Build
```bash
npm run build
npm run start
```
`next build` prerenders every page into a static shell with a one-year lifetime, so a deploy is not what refreshes content: publishing in the Studio is. That takes a Sanity webhook pointed at `/api/revalidate`, created once by hand and secured with `SANITY_REVALIDATE_SECRET`. See [`docs/sanity/revalidation-and-caching.md`](docs/sanity/revalidation-and-caching.md).
## Docs
Feature-level docs live in `docs/` so the root README stays lightweight. Start at [`docs/README.md`](docs/README.md).
## Scripts
- `npm run dev`: Start the dev server (site + Studio + APIs)
- `npm run build`: Build for production (`next build`)
- `npm run start`: Start the production server
- `npm run check`: Run all checks (`check.*` in parallel)
- `npm run check.types`: TypeScript type checking
- `npm run check.biome`: Biome lint (errors only)
- `npm run format`: Format and fix with Biome (`biome check --write --unsafe`)
- `npm test`: Run the unit tests
- `npm run plop`: Scaffold new sections, prefix routes, and rich text blocks
- `npm run clear`: Remove local build and cache output (`.next`, `node_modules/.cache`)
- `npm run sanity:typegen`: Extract the Sanity schema and generate `sanity/types.ts`
- `npm run sanity:cli`: Run the Sanity CLI with `.env` loaded (via dotenvx)
- `npm run sanity:schema-deploy`: Deploy the schema to Sanity (required by Agent Actions)
- `npm run sanity:dataset-export`: Backup a dataset to `./backups/`
- `npm run sanity:dataset-import`: Restore a `.tar.gz` into a dataset
- `npm run sanity:dataset-migrate`: Copy one dataset into another
Every `sanity:*` script above is interactive: run it with no flags and it asks what it needs, prints a summary, and confirms before touching anything. Flags answer those questions up front, `--dry-run` prints the plan and stops, and `--yes` skips every prompt (see `scripts/README.md`).
- `npm run sanity:project-setup`: Interactive wizard for a Sanity project, tokens, CORS, and `.env`
## Project Structure
```text
.
|-- app/
| |-- (web)/ # Site routes ([[...uri]] is the pages model) and the page shell
| |-- api/ # Route handlers (served at /api/*)
| `-- sanity-studio/ # Studio mount, rewritten to your public Studio path
|-- components/ # Shared React components (Button, Icon, Dialog)
|-- features/ # Feature modules (page-builder, site, agents, sanity, rich-text, style, ...)
|-- public/ # Static assets
|-- sanity/ # Sanity Studio config, schema, structure (standalone folder)
|-- seed/ # Starter dataset shipped with the template
|-- scripts/ # Dataset + project-setup CLIs
|-- templates/ # Plop templates
|-- docs/ # Project documentation
|-- proxy.ts # Basic Auth + agent Markdown negotiation + real 404s
|-- env.ts # Typed environment config
`-- dig # Cache Components, Studio rewrite, CMS redirects
```
## Agent Skills
AI guidance for this repository lives in `AGENTS.md` and `.agents/skills/`.
## Learn More
- [Next.js Documentation](https://nextjs.org/docs)
- [Sanity Documentation](https://www.sanity.io/docs)
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
## License
Commercial, one license per buyer. Build unlimited personal, commercial, and client projects with it, and sell what you build. Do not resell or republish the boilerplate itself.
See [`LICENSE.md`](LICENSE.md) for the full terms, and the [Terms of Service](/terms-of-service) for the purchase terms.