1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
Next blog
=========
A full-stack blog built with Next.js 15 and Payload CMS. Ships authentication,
comments, search, RSS, and an email template out of the box.
Overview
--------
Frontend uses Next.js App Router with Tailwind and shadcn, plus fumadocs layout
pieces for navigation, pagination, and search.
Content is managed by Payload CMS (``payload.config.ts``) with support for rich
text, tags, cover images, and publish states.
Authentication relies on better-auth with Google and GitHub; sessions and
comments are stored in Postgres through Drizzle ORM.
Comments use ``@fuma-comment``, and the site generates both ``/rss.xml`` feeds
and ``/api/search`` indexes.
Features
--------
- **Content Management**: Payload admin handles drafts, published posts, cover
images, tags, and scheduled publishing.
- **Blog Experience**: Includes paginated lists, a tag hub, rich text
rendering, and a one-click share button.
- **Social Interaction**: Supports Google or GitHub login via better-auth and
locally stored Fuma Comments.
- **SEO & Enhancements**: Features RSS feeds, on-the-fly search indexing,
automatic Open Graph banners, and sitemaps.
- **Email System**: Includes a ``newsletter-welcome`` template built with React
Email and Tailwind, ready for Resend.
- **Ops & Tooling**: Ships with ``.env`` validation, local Postgres boot
scripts, and unified Drizzle/Payload migration scripts.
Tech Stack
----------
- **Framework**: Next.js 15 (App Router) with server components and hybrid
static/dynamic rendering.
- **UI**: Tailwind CSS 4 with shadcn and fumadocs-ui for navigation,
pagination, sections, and theming.
- **Content**: Payload CMS for Posts, Users, and Media with Lexical rich text.
- **Data**: PostgreSQL and Drizzle ORM; auth and comments tables are prefixed
``blog_*``.
- **Auth**: better-auth with OAuth (Google/GitHub), sessions, and an extra role
field.
- **Email**: Resend with React Email, welcome template styled by Tailwind.
Quickstart
----------
I recommend using Docker to run Postgres.
Run the following command to start a Postgres instance:
.. code-block:: bash
docker run -d \
--name Next-blog \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=YOUR_PASSWORD_HERE \
-e POSTGRES_DB=db \
-p 5432:5432 \
-v "$(pwd)/pgdata:/var/lib/postgresql/data" \
postgres:15.1
Then copy ``.env.example`` to ``.env`` and fill in the required environment
variables for your setup.
For the Docker command above, ``DATABASE_URL`` should look like this:
.. code-block:: bash
postgresql://admin:YOUR_PASSWORD_HERE@localhost:5432/db
.. code-block:: bash
pnpm install
pnpm tsx scripts/create-payload-schema.mts
pnpm payload:migrate
pnpm db:push
The ``scripts/create-payload-schema.mts`` step creates the PostgreSQL
``payload`` schema required by ``payload.config.ts`` before Payload migrations
create tables inside it.
If OAuth environment variables are not configured locally, skip validation for
database push and development startup:
.. code-block:: bash
SKIP_ENV_VALIDATION=1 pnpm db:push
Start the development server:
.. code-block:: bash
pnpm dev
Optional:
.. code-block:: bash
SKIP_ENV_VALIDATION=1 pnpm dev
Open http://localhost:3000
Core Modules
------------
- **Content Model**: Defined in ``payload.config.ts`` to manage Posts, Users,
and Media with Lexical rich text.
- **Data Fetching**: Wrapped in ``src/lib/payload-posts.ts`` to handle post
queries, tag statistics, and pagination.
- **Pages & Layout**: Located under ``src/app/(main)``, featuring modular
components for the Hero section and post lists.
- **Auth & Comments**: Managed in ``src/server``, utilizing better-auth with
Drizzle ORM and dedicated ``blog_*`` tables.
- **Search & Feed**: API routes generate the search index and Atom/RSS feeds
for content distribution.
- **Email Templates**: Located in ``emails/``, providing React Email components
that dynamically accept post arrays.
Project Structure (excerpt)
---------------------------
.. code-block:: text
src/
├── app/
│ ├── (main)/(home)/page.tsx Home with hero, recent posts, CTA
│ ├── (main)/(home)/posts/[slug]/page.tsx Post detail with comments and 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 and utilities (payload-posts,
│ metadata, auth-client)
├── server/ better-auth and Drizzle schema plus
│ comment storage
└── emails/ React Email templates
Routes and APIs
---------------
.. code-block:: text
/ Home with hero, latest posts, and CTA.
├── posts Paginated posts; /posts/[slug] for detail with rich text,
│ comments, and share.
├── tags Tag cloud with counts.
├── login Google or 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 and 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.
|