diff --git a/.env.example b/.env.example index 884e9ed..b15ce32 100644 --- a/.env.example +++ b/.env.example @@ -15,9 +15,12 @@ NEXT_PUBLIC_APP_NAME="Classical Virtues" # API_KEY= # Basehub CMS +# Both come from the Basehub project dashboard (Settings โ†’ Read tokens / Webhooks). +# Leave empty for local work: the app degrades gracefully (empty story list / null story). BASEHUB_TOKEN= BASEHUB_WEBHOOK_SECRET= # Development Settings -NODE_ENV=development +# Note: do NOT set NODE_ENV here โ€” Next.js manages it automatically and warns +# when it is set manually. It is intentionally omitted. NEXT_TELEMETRY_DISABLED=1 diff --git a/README.md b/README.md index 7d3d83b..7a4cf63 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,13 @@ This project implements a **dual-content architecture** with BaseHub CMS as the ## ๐Ÿ› ๏ธ Getting Started +> **New here?** [SETUP.md](./SETUP.md) is the concise, verified quickstart (prerequisites, +> install, env vars, commands, and how to add a new virtue story). The notes below are an overview. + ### Prerequisites -- Node.js 18+ and pnpm -- BaseHub account and project setup +- Node.js `>=20.9.0` (verified on Node 24) and pnpm 10+ +- BaseHub account and project setup (optional locally โ€” the app degrades gracefully without a token) - Vercel account for deployment ### Local Development diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..34ebcae --- /dev/null +++ b/SETUP.md @@ -0,0 +1,124 @@ +# SETUP โ€” Classical Virtues + +Concise, verified quickstart for getting the repo running locally and shipping changes. +For the deep Basehub schema walkthrough see [BASEHUB-SETUP.md](./BASEHUB-SETUP.md); for +architecture conventions see [CLAUDE.md](./CLAUDE.md). + +- **Repo:** https://github.com/huntsyea/classical-virtues +- **Live:** https://www.classicalvirtues.com/ +- **Stack:** Next.js 16 (App Router, React 19, Turbopack) ยท Basehub CMS ยท Tailwind 3 ยท shadcn/ui + +## Prerequisites + +| Tool | Version | Notes | +| ---- | ------- | ----- | +| Node | `>=20.9.0` (per `package.json` engines) | Verified on Node 24.16.0 | +| pnpm | 10+ | Verified on pnpm 11.7.0; CI pins major 10 | + +This project uses **pnpm only** (a `pnpm-lock.yaml` is committed; `package-lock.json` / +`yarn.lock` are git-ignored). Don't mix package managers. + +## Install + +```bash +pnpm install +``` + +Postinstall builds `sharp` and `unrs-resolver` (allow-listed in `pnpm-workspace.yaml`). +A clean install takes a few seconds and produces no errors. + +## Environment + +```bash +cp .env.example .env.local +``` + +`.env*.local` is git-ignored โ€” never commit real tokens. Variables: + +| Variable | Required? | Where it comes from | +| -------- | --------- | ------------------- | +| `BASEHUB_TOKEN` | For live content | Basehub dashboard โ†’ project โ†’ Settings โ†’ **Read tokens** (format `bshb_pk_โ€ฆ`) | +| `BASEHUB_WEBHOOK_SECRET` | For content-revalidation webhook | Basehub dashboard โ†’ **Webhooks** (Svix signing secret, format `whsec_โ€ฆ`) | +| `NEXT_PUBLIC_APP_URL` | No | Defaults to `http://localhost:3000` | +| `NEXT_PUBLIC_APP_NAME` | No | Display name | +| `NEXT_TELEMETRY_DISABLED` | No | Set to `1` to opt out of Next telemetry | + +### Fastest path: pull secrets from Vercel + +If you have access to the `dudesdesign/classical-virtues` Vercel project, you don't need +to copy tokens by hand โ€” pull them straight into a git-ignored `.env.local`: + +```bash +npx vercel link --yes --project classical-virtues --scope dudesdesign # writes .vercel/ (git-ignored) +npx vercel env pull .env.local # downloads development env vars +``` + +This populates `BASEHUB_TOKEN`, `BASEHUB_WEBHOOK_SECRET`, and `BLOB_READ_WRITE_TOKEN`. +Add `NEXT_PUBLIC_APP_URL` / `NEXT_PUBLIC_APP_NAME` from `.env.example` if you want them. + +**Graceful degradation (verified):** with `BASEHUB_TOKEN` empty, the app still runs. +`getAllStories()` returns `[]` and `getStoryBySlug()` returns `null` +(see `src/lib/stories.ts`), so the home page, `/stories`, `/about`, and `/api/stories` +all render โ€” just with no stories. This lets you work on layout/UI without a token. + +## Commands + +| Command | What it does | +| ------- | ------------ | +| `pnpm run dev` | `basehub dev & next dev` โ€” dev server at http://localhost:3000 | +| `pnpm run build` | `basehub && next build` โ€” production build (**requires `BASEHUB_TOKEN`**, see below) | +| `pnpm run build:local` | `next build` only โ€” builds **without** a token using the committed `basehub-types.d.ts` | +| `pnpm run start` | Serve the production build | +| `pnpm run lint` | ESLint (currently clean) | +| `pnpm run basehub` | Regenerate `basehub-types.d.ts` from the Basehub schema (needs a token) | + +### About the build and the Basehub token + +The `build` and `dev` scripts call the `basehub` CLI, which **hard-fails without a +`BASEHUB_TOKEN`** (`๐Ÿ”ด Token not found`): + +- `pnpm run dev` โ€” the `basehub dev` half errors, but it's backgrounded (`&`), so + `next dev` still boots normally. You'll just see the token warning. +- `pnpm run build` โ€” the `basehub` codegen step runs first and exits non-zero **before** + `next build`, so the full build fails without a token. +- `pnpm run build:local` โ€” skips codegen and runs `next build` directly. This works + token-less because `basehub-types.d.ts` is committed; the app then degrades gracefully. + +In CI and on Vercel the token is present, so the standard `basehub && next build` is correct +there. Only regenerate types (`pnpm run basehub`) when the Basehub schema changes. + +> Note: don't set `NODE_ENV` in `.env.local` โ€” Next.js manages it and warns when it's set +> manually. It's intentionally omitted from `.env.example`. + +## Adding a new virtue story + +Content lives in **Basehub**, not in the repo โ€” adding a story usually needs **no code +changes or deploy**. + +1. Open the Basehub project dashboard and edit the **`stories`** collection. +2. Create a new entry and fill the fields the app reads (see `src/lib/basehub.ts` / + the `StoryData` interface in `src/lib/stories.ts`): + - **title** (entry title) ยท **virtue** (e.g. "Courage") ยท **image** (hero) ยท + **summary** ยท **virtueDescription** (the moral) ยท **audioUrl** (optional narration) ยท + **content** (rich text / Markdown or MDX). +3. **Publish.** ISR + the `/revalidate-sitemap` webhook pick it up; the story appears at + `/stories/` and in the story grid, sitemap, and structured data automatically. +4. If you **added or renamed schema fields**, run `pnpm run basehub` locally to regenerate + `basehub-types.d.ts`, wire the new field through `src/lib/basehub.ts` โ†’ + `src/lib/stories.ts`, and commit those type changes. + +See [BASEHUB-SETUP.md](./BASEHUB-SETUP.md) for the full field-by-field schema reference. + +## Deploying (Vercel) + +The repo is **not** yet linked locally (no `.vercel/` dir). To connect to the existing +`classicalvirtues.com` Vercel project (do **not** create a new project): + +1. `vercel link` (or use the Vercel dashboard) to link this repo to the existing project. +2. Set environment variables in the Vercel project (Production + Preview): + `BASEHUB_TOKEN`, `BASEHUB_WEBHOOK_SECRET` (+ optional `NEXT_PUBLIC_APP_URL`). +3. Build command: `basehub && next build` (the default `build` script). Install: `pnpm install`. +4. Point the Basehub webhook at `https://www.classicalvirtues.com/revalidate-sitemap`. + +CI (`.github/workflows/ci-cd.yml`) runs lint + build on push/PR and needs a `BASEHUB_TOKEN` +repo secret for the build step to pass. diff --git a/package.json b/package.json index 97520e7..e6f594a 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "dev": "basehub dev & next dev", "build": "basehub && next build", + "build:local": "next build", "start": "next start", "lint": "eslint .", "basehub": "basehub"