summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrand Yuan <bert.yuan@outlook.com>2025-12-16 08:47:10 +0800
committerBertrand Yuan <bert.yuan@outlook.com>2025-12-16 09:05:13 +0800
commit6969f185b0484f00efc38f045d0ba9f9b2938bae (patch)
treeae4198bd3e7f6e74939862f170a26b700d7187d5
parent69728d4a5c8508f24e670b8c4889b2703a2a4721 (diff)
docs: add README in en & zh
-rw-r--r--README-zh.md170
-rw-r--r--README.md169
2 files changed, 339 insertions, 0 deletions
diff --git a/README-zh.md b/README-zh.md
new file mode 100644
index 0000000..a6b1d10
--- /dev/null
+++ b/README-zh.md
@@ -0,0 +1,170 @@
+<div align="center">
+ <h1>shadcn blog</h1>
+ <p>基于 Next.js 15 + Payload CMS 的全栈博客,内置认证、评论、搜索、RSS 与邮件模版。</p>
+ <p>
+ <img src="https://img.shields.io/badge/Next.js-15-black" alt="Next.js 15" />
+ <img src="https://img.shields.io/badge/React-19-61dafb" alt="React 19" />
+ <img src="https://img.shields.io/badge/Database-PostgreSQL-336791" alt="PostgreSQL" />
+ <img src="https://img.shields.io/badge/CMS-Payload-blueviolet" alt="Payload CMS" />
+ </p>
+</div>
+
+## 目录
+
+- [目录](#目录)
+- [项目简介](#项目简介)
+- [主要特性](#主要特性)
+- [技术栈](#技术栈)
+- [快速开始](#快速开始)
+- [核心模块速览](#核心模块速览)
+- [环境变量](#环境变量)
+- [常用脚本](#常用脚本)
+- [页面与接口](#页面与接口)
+- [开发提示](#开发提示)
+
+## 项目简介
+
+- 前端采用 Next.js App Router,UI 基于 tailwind + shadcn,并用 fumadocs 的布局组件快速搭建导航、分页、搜索等。
+- 内容源由 Payload CMS 提供(`payload.config.ts`),支持富文本、标签、封面图与发布状态。
+- 认证使用 better-auth(Google/GitHub 登录),会话与评论数据通过 Drizzle ORM 写入 Postgres。
+- 评论系统集成 `@fuma-comment`,同时生成 `/rss.xml` 订阅源和 `/api/search` 搜索索引。
+
+## 主要特性
+
+- 文章管理:Payload 后台(`/admin`)可创建草稿/已发布文章,支持封面、标签与定时发布时间。
+- 博客体验:列表分页、标签聚合页、文章详情页富文本渲染、分享按钮、一键复制链接。
+- 社交与互动:Google/GitHub 登录、基于 better-auth 的会话管理,Fuma Comment 评论组件存储在本地数据库。
+- 增强功能:RSS 输出、站内搜索索引、自动 Open Graph/OG Banner、站点地图(`next-sitemap`)。
+- 邮件模版:`emails/newsletter-welcome.tsx` 提供 React Email/Tailwind 的欢迎邮件示例,可通过 Resend 发送。
+- 运维友好:`.env` 校验、`start-database.sh` 一键启动本地 Postgres、Drizzle/Payload 脚本统一管理数据库。
+
+## 技术栈
+
+<table>
+ <tr>
+ <th>领域</th>
+ <th>选择</th>
+ <th>说明</th>
+ </tr>
+ <tr>
+ <td>框架</td>
+ <td>Next.js 15 (App Router)</td>
+ <td>服务端组件、动态/静态混合渲染</td>
+ </tr>
+ <tr>
+ <td>UI</td>
+ <td>tailwindcss 4 + shadcn + fumadocs-ui</td>
+ <td>快速搭建导航、分页、Section、主题切换</td>
+ </tr>
+ <tr>
+ <td>内容</td>
+ <td>Payload CMS</td>
+ <td>Posts/Users/Media 集合,Lexical 富文本</td>
+ </tr>
+ <tr>
+ <td>数据</td>
+ <td>PostgreSQL + Drizzle ORM</td>
+ <td>认证与评论表(前缀 <code>blog_*</code>)</td>
+ </tr>
+ <tr>
+ <td>认证</td>
+ <td>better-auth + OAuth (Google/GitHub)</td>
+ <td>社交登录、会话、额外角色字段</td>
+ </tr>
+ <tr>
+ <td>邮件</td>
+ <td>Resend + React Email</td>
+ <td>欢迎邮件模版、Tailwind 样式</td>
+ </tr>
+</table>
+
+## 快速开始
+
+1) 安装依赖与 Node
+ - 推荐 Node 20+,包管理器使用 `pnpm`(已锁定 `pnpm-lock.yaml`)。
+2) 配置环境变量
+ - 复制 `.env.example` 为 `.env`,至少填写 `DATABASE_URL`、`PAYLOAD_SECRET`、`BETTER_AUTH_SECRET`,如需社交登录再补齐 OAuth。
+3) 启动本地数据库(Postgres)
+ - `./start-database.sh`(依赖 Docker/Podman)或使用自带的 Postgres 实例。
+4) 安装依赖并生成数据库结构
+ - `pnpm install`
+ - `pnpm db:generate && pnpm db:migrate`(Drizzle 认证/评论表)
+ - `pnpm payload:migrate`(Payload CMS 表)
+5) 运行开发服务
+ - `pnpm dev`(默认监听 3000,Payload Admin `/admin`,博客 `/`)。
+6) 可选:生成 Payload Types 与邮件预览
+ - `pnpm payload:generate`
+ - `pnpm email:dev -p 3001` 查看邮件模版。
+
+> 开发模式下 Payload 会自动填充 `admin@example.com` / `admin123` 登录框,无需手动创建账户。
+
+## 核心模块速览
+
+- 内容模型:`payload.config.ts` 定义 Posts/Users/Media,文章支持封面上传、标签数组、发布时间与状态。
+- 数据获取:`src/lib/payload-posts.ts` 统一封装文章查询、标签统计、分页与 slug 获取,供页面调用。
+- 页面与布局:`src/app/(main)` 为站点主入口,`_components` 目录包含 Hero、CTA、Post 列表等 UI。
+- 认证与评论:`src/server/auth`(better-auth + Drizzle),`src/server/comments` 将评论存入 `blog_comments` 表。
+- 搜索与订阅:`src/app/(main)/api/search/route.ts` 动态生成索引;`src/app/(main)/rss.xml/route.ts` 输出 Atom feed。
+- 邮件:`emails/newsletter-welcome.tsx` React Email 模版,可传入最新文章数组渲染卡片。
+
+项目结构(节选):
+
+```text
+src/
+├── app/
+│ ├── (main)/(home)/page.tsx # 首页:Hero、最近文章、CTA
+│ ├── (main)/(home)/posts/[slug]/page.tsx # 文章详情 + 评论 + 分享
+│ ├── (main)/(home)/posts/page.tsx # 分页文章列表
+│ ├── (main)/(home)/tags/page.tsx # 标签聚合
+│ ├── (main)/api/search/route.ts # 站内搜索索引
+│ ├── (main)/rss.xml/route.ts # Atom/RSS 输出
+│ └── (payload)/admin/... # Payload CMS 后台
+├── lib/ # 数据与工具(payload-posts、metadata、auth-client)
+├── server/ # better-auth + Drizzle schema + comment storage
+└── emails/ # React Email 模版
+```
+
+## 环境变量
+
+<details>
+<summary>必填与可选</summary>
+
+| 变量 | 说明 |
+| --- | --- |
+| `DATABASE_URL` | Postgres 连接串,例如 `postgresql://user:pass@localhost:5432/blog` |
+| `PAYLOAD_SECRET` | Payload CMS 用于 JWT 加密的密钥 |
+| `BETTER_AUTH_SECRET` | better-auth session 密钥 |
+| `BETTER_AUTH_URL` | 认证回调地址(本地可设 `http://localhost:3000`) |
+| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | 启用 Google 登录时必填 |
+| `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` | 启用 GitHub 登录时必填 |
+| `RESEND_API_KEY` / `RESEND_AUDIENCE_ID` / `EMAIL_FROM` | 发送邮件时必填 |
+| `NEXT_PUBLIC_SERVER_URL` | 生成链接、OG、RSS 的基础地址 |
+| `NEXT_PUBLIC_UMAMI_URL` / `NEXT_PUBLIC_UMAMI_WEBSITE_ID` | 可选,埋点统计 |
+
+</details>
+
+## 常用脚本
+
+- `pnpm dev`:启动 Next.js 开发服务器(含 Payload routes)。
+- `pnpm build` / `pnpm preview`:构建与预览生产版本。
+- `pnpm db:generate` / `pnpm db:migrate`:生成并执行 Drizzle 迁移(认证/评论表)。
+- `pnpm payload:migrate`:同步 Payload CMS 数据表。
+- `pnpm lint` / `pnpm format`:质量与格式检查(biome)。
+- `pnpm email:dev`:本地预览 React Email 模版。
+
+## 页面与接口
+
+- `/`:首页,展示 Hero、最新文章、CTA。
+- `/posts`:文章分页列表;`/posts/[slug]`:详情页、富文本、评论、分享。
+- `/tags`:标签云与计数。
+- `/login`:Google/GitHub 登录入口。
+- `/admin`:Payload CMS 后台。
+- `/api/search`:搜索索引接口(fumadocs search)。
+- `/rss.xml`:Atom/RSS 订阅。
+
+## 开发提示
+
+- 本地优先运行 `./start-database.sh` 启动 Postgres;若端口占用脚本会提示。
+- 认证与评论表前缀为 `blog_`,确保 `drizzle.config.ts` 里的 `tablesFilter` 与迁移脚本保持一致。
+- Payload 在开发环境会预填 `admin@example.com` / `admin123`,方便快速登录后台。
+- 如果只想浏览前端而不接入真实数据,可设置 `SKIP_ENV_VALIDATION=1` 并禁用需要外部服务的功能,但推荐补齐变量以覆盖所有页面。
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..24e47a8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,169 @@
+<div align="center">
+ <h1>shadcn blog</h1>
+ <p>A full-stack blog built with Next.js 15 + Payload CMS, shipping auth, comments, search, RSS, and email templates out of the box.</p>
+ <p>
+ <img src="https://img.shields.io/badge/Next.js-15-black" alt="Next.js 15" />
+ <img src="https://img.shields.io/badge/React-19-61dafb" alt="React 19" />
+ <img src="https://img.shields.io/badge/Database-PostgreSQL-336791" alt="PostgreSQL" />
+ <img src="https://img.shields.io/badge/CMS-Payload-blueviolet" alt="Payload CMS" />
+ </p>
+</div>
+
+## Table of Contents
+
+- [Overview](#overview)
+- [Features](#features)
+- [Tech Stack](#tech-stack)
+- [Quickstart](#quickstart)
+- [Core Modules](#core-modules)
+- [Environment Variables](#environment-variables)
+- [Scripts](#scripts)
+- [Routes & APIs](#routes--apis)
+- [Developer Notes](#developer-notes)
+
+## Overview
+
+- Frontend uses Next.js App Router with Tailwind + shadcn, and fumadocs layout pieces for navigation, pagination, and search.
+- Content is managed by Payload CMS (`payload.config.ts`), supporting rich text, tags, cover images, and publish states.
+_- Authentication via better-auth (Google/GitHub), sessions and comments stored in Postgres through Drizzle ORM._
+- Comments are powered by `@fuma-comment`, and the site generates both `/rss.xml` feeds and `/api/search` indexes.
+
+## Features
+
+- Post management: Payload admin (`/admin`) creates drafts/published posts with cover image, tags, and scheduled publish time.
+- Blog UX: paginated lists, tag hub, rich post detail rendering, share button, one-click copy link.
+- Social & interaction: Google/GitHub login, better-auth session management, Fuma Comment stored locally.
+- Enhancements: RSS feed, on-the-fly search index, automatic Open Graph/OG banners, sitemap via `next-sitemap`.
+- Email template: `emails/newsletter-welcome.tsx` using React Email + Tailwind, ready for Resend.
+- Ops-friendly: `.env` validation, `start-database.sh` to boot local Postgres, unified Drizzle/Payload scripts for schema.
+
+## Tech Stack
+
+<table>
+ <tr>
+ <th>Area</th>
+ <th>Choice</th>
+ <th>Notes</th>
+ </tr>
+ <tr>
+ <td>Framework</td>
+ <td>Next.js 15 (App Router)</td>
+ <td>Server Components with hybrid static/dynamic rendering</td>
+ </tr>
+ <tr>
+ <td>UI</td>
+ <td>Tailwind CSS 4 + shadcn + fumadocs-ui</td>
+ <td>Navigation, pagination, sections, theming</td>
+ </tr>
+ <tr>
+ <td>Content</td>
+ <td>Payload CMS</td>
+ <td>Posts/Users/Media collections, Lexical rich text</td>
+ </tr>
+ <tr>
+ <td>Data</td>
+ <td>PostgreSQL + Drizzle ORM</td>
+ <td>Auth and comments tables (prefix <code>blog_*</code>)</td>
+ </tr>
+ <tr>
+ <td>Auth</td>
+ <td>better-auth + OAuth (Google/GitHub)</td>
+ <td>Social login, sessions, extra role field</td>
+ </tr>
+ <tr>
+ <td>Email</td>
+ <td>Resend + React Email</td>
+ <td>Welcome template, Tailwind styling</td>
+ </tr>
+</table>
+
+## Quickstart
+
+1) Install toolchain
+ - Node 20+ recommended, use `pnpm` (locked by `pnpm-lock.yaml`).
+2) Set environment variables
+ - Copy `.env.example` to `.env`; fill `DATABASE_URL`, `PAYLOAD_SECRET`, `BETTER_AUTH_SECRET`, and OAuth keys if needed.
+3) Start Postgres locally
+ - `./start-database.sh` (Docker/Podman) or your own Postgres instance.
+4) Install deps and build schema
+ - `pnpm install`
+ - `pnpm db:generate && pnpm db:migrate` (Drizzle auth/comments tables)
+ - `pnpm payload:migrate` (Payload CMS tables)
+5) Run dev server
+ - `pnpm dev` (default :3000; Payload Admin `/admin`, blog `/`).
+6) Optional extras
+ - `pnpm payload:generate` (types)
+ - `pnpm email:dev -p 3001` (preview email template).
+
+> In development, Payload pre-fills `admin@example.com` / `admin123` on the login form.
+
+## Core Modules
+
+- Content model: `payload.config.ts` defines Posts/Users/Media with cover uploads, tag arrays, publish time, and status.
+- Data fetching: `src/lib/payload-posts.ts` wraps post queries, tag stats, pagination, and slug helpers for pages.
+- Pages & layout: `src/app/(main)` hosts the site; `_components` includes Hero, CTA, and post list UI.
+- Auth & comments: `src/server/auth` (better-auth + Drizzle) and `src/server/comments` storing into `blog_comments` tables.
+- Search & feed: `src/app/(main)/api/search/route.ts` builds indexes; `src/app/(main)/rss.xml/route.ts` emits Atom/RSS.
+- Email: `emails/newsletter-welcome.tsx` React Email template that accepts a posts array.
+
+Project structure (excerpt):
+
+```text
+src/
+├── app/
+│ ├── (main)/(home)/page.tsx # Home: hero, recent posts, CTA
+│ ├── (main)/(home)/posts/[slug]/page.tsx # Post detail + comments + share
+│ ├── (main)/(home)/posts/page.tsx # Paginated posts list
+│ ├── (main)/(home)/tags/page.tsx # Tag hub
+│ ├── (main)/api/search/route.ts # Search index API
+│ ├── (main)/rss.xml/route.ts # Atom/RSS feed
+│ └── (payload)/admin/... # Payload CMS admin
+├── lib/ # Data + utilities (payload-posts, metadata, auth-client)
+├── server/ # better-auth + Drizzle schema + comment storage
+└── emails/ # React Email templates
+```
+
+## Environment Variables
+
+<details>
+<summary>Required & optional</summary>
+
+| Variable | Description |
+| --- | --- |
+| `DATABASE_URL` | Postgres connection string, e.g. `postgresql://user:pass@localhost:5432/blog` |
+| `PAYLOAD_SECRET` | Secret used by Payload CMS for JWT |
+| `BETTER_AUTH_SECRET` | better-auth session secret |
+| `BETTER_AUTH_URL` | Auth callback base (local: `http://localhost:3000`) |
+| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | Required if enabling Google login |
+| `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` | Required if enabling GitHub login |
+| `RESEND_API_KEY` / `RESEND_AUDIENCE_ID` / `EMAIL_FROM` | Required for sending emails |
+| `NEXT_PUBLIC_SERVER_URL` | Base URL for links/OG/RSS |
+| `NEXT_PUBLIC_UMAMI_URL` / `NEXT_PUBLIC_UMAMI_WEBSITE_ID` | Optional analytics |
+
+</details>
+
+## Scripts
+
+- `pnpm dev`: Start Next.js dev server (includes Payload routes).
+- `pnpm build` / `pnpm preview`: Build and preview production.
+- `pnpm db:generate` / `pnpm db:migrate`: Generate and run Drizzle migrations (auth/comments).
+- `pnpm payload:migrate`: Sync Payload CMS tables.
+- `pnpm lint` / `pnpm format`: Quality and formatting checks (biome).
+- `pnpm email:dev`: Preview React Email templates locally.
+
+## Routes & APIs
+
+- `/`: Home with hero, latest posts, CTA.
+- `/posts`: Paginated posts; `/posts/[slug]`: detail with rich text, comments, share.
+- `/tags`: Tag cloud with counts.
+- `/login`: Google/GitHub login entry.
+- `/admin`: Payload CMS admin.
+- `/api/search`: Search index endpoint (fumadocs search).
+- `/rss.xml`: Atom/RSS feed.
+
+## Developer Notes
+
+- Prefer `./start-database.sh` to boot Postgres locally; the script warns if the port is in use.
+- Auth/comment tables use the `blog_` prefix—keep `drizzle.config.ts` `tablesFilter` in sync.
+- Payload dev mode pre-fills `admin@example.com` / `admin123` to speed up admin login.
+- If you only need to browse the UI without real data, set `SKIP_ENV_VALIDATION=1` and disable features needing external services; full env is recommended for complete coverage.