一个背单词应用,看起来只需要一个手机页面:展示单词、点击认识或不认识、记录学习进度。
但只要继续往下做,很快就会发现:用户负责背单词,那单词、单词书和内容到底由谁来维护?
这就是 danci 项目真正的起点。
一、先从一个最简单的背单词页面开始
假设我们准备做一个单词学习应用。
用户打开页面以后:
选择单词书
↓
开始学习
↓
apple
↓
认识 / 不认识
↓
下一个单词
第一版看起来并不复杂。
但继续往下想,很快就会遇到几个问题:
“四级词汇”这本单词书是谁创建的?
一本单词书里有哪些单词?
某个单词释义写错了怎么办?
以后想增加“考研词汇”怎么办?
如果所有内容都直接写死在代码里,那么每改一个单词,都需要程序员修改代码、重新发布。
显然不合理。
所以第一个需求自然出现了:
需要一个后台管理系统,让内容维护人员自己管理单词和单词书。
于是 danci 不再只是一个 H5 页面,而是开始分成两个部分:
danci
├── 后台管理系统
│ └── 给管理员维护内容
│
└── H5 单词学习应用
└── 给普通用户背单词
这也是很多真实产品都会出现的结构:
运营 / 管理员
↓
后台系统
↓
数据库
↑
用户应用
↑
普通用户
后台负责维护数据,用户端负责使用数据。
二、后台第一步做什么?先做单词书管理
既然用户需要:
四级词汇
六级词汇
考研词汇
那么后台最先需要管理的就是:
books
单词书
管理员进入后台以后,需要完成:
创建单词书
查询单词书
修改单词书
删除单词书
这其实就是最经典的 CRUD:
Create 创建
Read 查询
Update 更新
Delete 删除
例如 /books 页面可能展示:
| 单词书 | 单词数量 | 操作 |
|---|---|---|
| 四级核心词汇 | 2600 | 编辑 / 删除 |
| 六级核心词汇 | 3200 | 编辑 / 删除 |
| 考研核心词汇 | 5500 | 编辑 / 删除 |
这个页面看起来很普通,但它已经说明了一件很重要的事:
后台系统的核心不是“页面多漂亮”,而是让业务人员能够维护系统里的数据。
三、谁都能进入后台吗?
单词书可以创建和删除。
那显然不能让所有普通用户都访问:
/books
否则任何人都能修改甚至删除系统数据。
所以第二个需求又自然出现了:
后台需要管理员身份。
可以先设计两种角色:
超级管理员
普通管理员
普通管理员负责内容维护,例如:
维护单词书
维护单词
审核数据
超级管理员除了拥有这些能力,还可以:
添加管理员
删除管理员
管理管理员权限
于是后台又增加了一个模块:
/admin-users
到这里,后台最基础的结构已经出来了:
后台管理系统
├── /books
│ └── 单词书管理
│
└── /admin-users
└── 管理员管理
四、但是第一个管理员是谁创建的?
现在出现一个很有意思的问题:
只有管理员
↓
才能创建管理员
那么系统刚上线的时候:
第一个管理员是谁创建的?
总不能出现:
需要管理员创建管理员
↓
但是现在没有管理员
↓
所以永远无法创建第一个管理员
因此需要一个“系统初始化”流程。
例如:
系统第一次启动
↓
检查有没有超级管理员
↓
没有
↓
进入超级管理员注册页
↓
创建唯一的初始超级管理员
于是 / 的逻辑可能是:
访问 /
↓
检查系统状态
第一次:
没有超级管理员
↓
/signup
↓
注册超级管理员
↓
/signin
↓
登录
↓
/books
以后:
已经存在超级管理员
↓
/signin
↓
登录成功
↓
/books
这件事看起来只是几个页面跳转,但它背后其实是在做:
业务流程设计。
页面只是业务规则最终表现出来的形式。
五、后台页面越来越多,UI 难道都自己写?
现在后台至少会出现:
登录表单
注册表单
侧边栏
表格
按钮
输入框
确认删除弹窗
下拉菜单
分页
这些东西在各种后台系统里高度重复。
例如一个“删除单词书”的功能,通常就是:
删除按钮
↓
确认弹窗
↓
取消 / 确认
如果每一个项目都从零实现:
Button
Input
Dialog
Table
Sidebar
Select
Dropdown
大量时间都会花在重复造轮子上。
所以这里自然会引出:
UI 组件库。
六、为什么这个项目使用 shadcn/ui
传统组件库,例如 Ant Design、Element Plus,通常是:
安装组件库
↓
从 npm 包中 import 组件
↓
直接使用
shadcn/ui 的思路有些不同。
例如添加 Button、Dialog、Table 后,项目中会出现类似:
components/
└── ui/
├── button.tsx
├── dialog.tsx
├── input.tsx
└── table.tsx
也就是说:
组件源码直接进入自己的项目。
所以它有一个很明显的特点:
不是完全接受组件库提供的最终样子
↓
而是拿到一套不错的基础组件
↓
继续按照自己的项目修改
这对于后台系统很适合。
因为后台里 80% 的基础组件本来就高度趋同:
按钮还是按钮
输入框还是输入框
表格还是表格
弹窗还是弹窗
真正需要定制的是:
组合方式
业务字段
交互规则
视觉风格
而不是重新实现一个 <button>。
七、Tailwind CSS 在这里负责什么
shadcn/ui 经常和 Tailwind CSS 一起使用。
两者不要混为一谈。
可以理解成:
shadcn/ui
↓
提供可复用 UI 组件
Tailwind CSS
↓
负责组件的样式表达
例如:
<Button>创建单词书</Button>
背后依然需要处理:
padding
颜色
边框
圆角
hover
disabled
响应式
这些属于样式系统负责的事情。
因此:
Next.js
↓
组织应用
shadcn/ui
↓
提供 UI 组件
Tailwind CSS
↓
负责样式
三者职责并不相同。
八、为什么这种组件方式对 Coding Agent 也很友好
假设项目已经有:
components/ui/button.tsx
components/ui/dialog.tsx
components/ui/input.tsx
现在让 Coding Agent 完成:
实现“新增单词书”弹窗
它可以直接读取已有组件,然后组合:
Dialog
+
Input
+
Button
而不是重新生成另一套按钮和弹窗。
这其实体现了一条很重要的 AI Coding 原则:
项目规范越清晰,AI 越不需要猜。
对于开发者也是一样。
如果整个项目的 Button、Dialog、Table 都有统一实现,那么新增页面时就只需要关心:
这个业务到底要什么?
而不是每次重新处理基础 UI。
九、为什么 danci 先做后台 + H5
一个单词产品未来可以运行在很多“端”上:
PC Web
H5
小程序
Android
iOS
桌面端
但这些并不应该一开始全部开发。
PC Web
运行在电脑浏览器中,更适合:
后台管理
办公
内容浏览
需要 SEO 的 Web 页面
H5
在国内开发语境里,H5 通常指:
面向手机浏览器的移动 Web 页面或 Web 应用。
它本质上依然是:
HTML
CSS
JavaScript
只是重点变成:
手机屏幕
触摸操作
移动端布局
响应式适配
Android / iOS
属于移动客户端。
跨平台开发可以考虑:
React Native
Flutter
桌面端
Windows、macOS 等桌面应用可以使用 Electron 等方案,让 Web 技术运行在桌面客户端中。
十、为什么不是第一天就做所有端
如果一开始就同时做:
PC
H5
小程序
Android
iOS
Electron
会产生大量额外成本。
更合理的路线是:
先把核心业务跑通
↓
后台管理系统
+
H5
↓
验证产品
↓
再根据需求扩展其他端
因此“多端”更适合作为:
未来扩展能力
而不是第一版必须全部实现的功能。
十一、到这里,项目架构已经不是“拍脑袋选技术”
把整个过程重新串一次:
想做一个背单词应用
↓
单词内容需要有人维护
↓
需要后台管理系统
↓
后台先做单词书 CRUD
↓
后台不能谁都能进
↓
需要管理员
↓
第一个管理员无法凭空出现
↓
需要超级管理员初始化流程
↓
后台有大量通用 UI
↓
使用 shadcn/ui
↓
整个 Web 应用需要统一组织
↓
使用 Next.js
所以真正重要的不是背:
Next.js + shadcn/ui + Tailwind CSS
而是理解:
为什么项目走到这里以后,这些东西会自然出现。
十二、但是现在还有一个更重要的问题
到这里,页面可以做出来了。
例如管理员在 /books 点击:
创建单词书
填写:
name = 四级词汇
然后点击:
保存
问题来了:
这本“四级词汇”到底保存到哪里?
页面里的一个变量显然不够。
所以接下来就必须进入整个项目最重要的数据层:
PostgreSQL
Supabase
ORM
Drizzle
schema
migration
RLS
下一篇就从这个问题开始。