Zhejiang University Morningside Cultural China Scholars Program
现代化的项目官网,基于 Next.js 14 App Router + TypeScript + Tailwind + Drizzle ORM 构建
浙江大学晨兴文化中国人才计划是一个非学分制、精英化的跨学科教育项目,旨在培养具有全球视野且认同中华传统文化的未来领袖。
本项目为其官方网站,采用混合内容策略:
- 核心静态内容:本地化存储(使命背景、培养宗旨、师资名录等)
- 时效性内容:通过外部链接引用微信公众号推文(新闻、活动、随笔)
- 多语言支持:支持中英双语版本(当前优先完成中文版本,英文版本待 Phase 5 实施)
- ⚙️ 全栈 RSC 架构:默认 Server Components,Route Handlers 处理 API
- 🎨 新中式设计系统:Tailwind + shadcn/ui,沉稳的晨兴红 / 典雅金配色
- 🗄 类型安全数据层:Drizzle ORM + PostgreSQL,Zod 校验环境变量
- 🧱 模块化目录:基于功能的清晰结构,便于扩展后台与前台功能
graph TB
subgraph "前端层 Frontend"
A[Next.js App Router] --> B[Server Components]
A --> C[Client Components]
B --> D[直接 DB 查询]
C --> E[Server Actions]
C --> F[API Routes]
end
subgraph "UI 层 UI Layer"
G[Tailwind CSS] --> H[shadcn/ui]
H --> I[自定义组件]
end
subgraph "数据层 Data Layer"
J[Drizzle ORM] --> K[PostgreSQL]
J --> L[Zod 校验]
end
D --> J
E --> J
F --> J
style A fill:#962E2A,color:#fff
style J fill:#E2BA3E,color:#000
style K fill:#1F2937,color:#fff
sequenceDiagram
participant User as 用户
participant RSC as Server Component
participant DB as Database
participant CC as Client Component
participant SA as Server Action
User->>RSC: 访问页面
RSC->>DB: 直接查询数据
DB-->>RSC: 返回数据
RSC-->>User: 渲染页面
User->>CC: 交互操作
CC->>SA: 调用 Server Action
SA->>DB: 数据变更
DB-->>SA: 返回结果
SA-->>CC: 更新状态
CC-->>User: 反馈结果
mindmap
root((技术栈))
前端
Next.js 14 App Router
TypeScript 5+
Tailwind CSS 3.4
shadcn/ui
Framer Motion
Lucide React
后端
Server Components
Server Actions
Route Handlers
Drizzle ORM
PostgreSQL
Zod 校验
工具链
pnpm
ESLint
Drizzle Kit
date-fns
src/
├── app/ # Next.js App Router
│ ├── api/ # API Routes
│ │ └── health/db/ # 数据库健康检查
│ ├── intro/ # 计划介绍相关页面
│ │ ├── mission/ # 使命背景
│ │ ├── purpose/ # 培养宗旨
│ │ └── center/ # 儒商中心
│ ├── activities/ # 特色活动
│ ├── admissions/ # 招生信息
│ ├── alumni/ # 学员风采
│ ├── curriculum/ # 课程教学
│ ├── layout.tsx # 根布局(Header/Footer)
│ ├── page.tsx # 首页
│ └── globals.css # 全局样式
│
├── components/
│ ├── home/ # 首页专用组件
│ │ └── hero-carousel.tsx # 轮播组件
│ ├── shared/ # 跨页面共享组件
│ │ ├── header.tsx # 导航栏
│ │ ├── footer.tsx # 页脚
│ │ ├── page-shell.tsx # 页面容器/标题/分区
│ │ ├── page-enter.tsx # 页面进入动画
│ │ ├── image-lightbox.tsx # 图片放大预览
│ │ └── entry-gate.tsx # 开屏遮罩(已禁用)
│ └── ui/ # shadcn/ui 基础组件
│ └── button.tsx
│
├── db/
│ └── schema.ts # Drizzle 数据模型
│ ├── resources # 外部资源(新闻/活动)
│ ├── alumni # 学员信息
│ └── faculty # 师资信息
│
└── lib/
├── db.ts # 数据库连接
├── env.ts # 环境变量校验(Zod)
└── utils.ts # 工具函数(cn 等)
- Server Components First:默认服务端组件,仅在需要交互时使用
"use client" - 类型安全:TypeScript Strict Mode + Zod 运行时校验
- 模块化:基于功能组织代码,而非文件类型
- DRY 原则:复用组件与工具函数,避免重复代码
- Node.js ≥ 18(建议 18 LTS 或 20+)
- pnpm(已通过 Corepack 启用)
- Docker(可选,用于快速启动本地 PostgreSQL)
-
克隆仓库并安装依赖
git clone <repository-url> cd culture_china/project pnpm install
-
配置环境变量
cp env.example .env
编辑
.env,设置数据库连接:# 本地开发 DATABASE_URL=postgresql://dev:devpass@localhost:5433/culture_china # 或 Vercel Postgres(自动提供 POSTGRES_URL) # POSTGRES_URL=postgres://...
如需直接联调线上 Supabase(包含
media_assets/activity_media最新表数据),请额外配置以下变量,并使用 Supabase 提供的 pooler 端口(6543),否则会出现relation "activity_media" does not exist等错误。POSTGRES_URL=postgres://postgres.xxx:password@aws-1-us-east-1.pooler.supabase.com:6543/postgres?sslmode=require&supa=base-pooler.x SUPABASE_URL=https://<project-ref>.supabase.co SUPABASE_SERVICE_ROLE_KEY=<service-role-key> SUPABASE_STORAGE_BUCKET=media
建议:使用
direnv、source .env或 VSCodedotenv插件,确保pnpm dev/pnpm db:*与 Next.js 运行时共享同一套 Supabase 凭据。- 访问路径:
/admin/login,登录后可根据角色进入相应模块。 - 角色划分:
content_editor:可管理 外链资源 + 活动媒体。super_admin:拥有全部权限,额外开放 学员风采管理。
- 环境变量(本地/受控环境可直接存明文;若部署公网请改造为哈希或对接外部身份服务):
ADMIN_MEDIA_USER="media_editor" ADMIN_MEDIA_PASSWORD="media-editor-password" ADMIN_ROOT_USER="root_admin" ADMIN_ROOT_PASSWORD="culture_china2025" ADMIN_SESSION_SECRET="32+chars-random"
- 会话策略:登录成功后写入
admin_sessionHttpOnly Cookie,默认有效期 12 小时,可在任意页面点击“退出登录”注销。
- 访问路径:
-
启动数据库(Docker 示例)
docker run --name culture-china-db \ -e POSTGRES_USER=dev \ -e POSTGRES_PASSWORD=devpass \ -e POSTGRES_DB=culture_china \ -p 5433:5432 -d postgres:15
-
执行数据库迁移
pnpm db:generate # 基于 schema.ts 生成 SQL pnpm db:migrate # 执行迁移
-
启动开发服务器
pnpm dev
若使用线上 Supabase,请确认上述变量已生效(可在
pnpm dev输出看到Environments: .env),否则页面会因连接到空库而缺少最新表。访问
http://localhost:3000,并通过http://localhost:3000/api/health/db检查数据库连通性。
| 命令 | 说明 |
|---|---|
pnpm dev |
启动开发服务器(热重载) |
pnpm build |
生产构建 |
pnpm start |
本地预览生产构建 |
pnpm lint |
运行 ESLint |
pnpm db:generate |
生成 Drizzle 迁移文件 |
pnpm db:migrate |
执行数据库迁移 |
pnpm db:studio |
打开 Drizzle Studio(可视化数据库) |
- 登录入口:
/admin/login(内置账号密码鉴权,见上文环境变量配置)。 - 功能概览:
- 外链资源管理:新增/编辑/删除公众号推文,支持 Featured & Pinned 开关。
- 活动媒体管理:维护首页轮播与
/activities图库,支持图片上传(原图 ≤ 8MB,自动压缩至 ≤ 1MB)、排序与启停。- 学员风采管理(仅
super_admin):提供筛选、手动录入、编辑、归档、照片替换、教育/经历维护等能力(照片自动裁剪为 5:7,≤1MB)。
- 学员风采管理(仅
- 上传限制:所有批量导入(Excel/CSV/Zip)及手动上传文件体积须 ≤ 700MB,超出将被拒绝并提示。
- 会话安全:登录后写入 HttpOnly Cookie,默认 12 小时有效,可随时手动退出。
- 当前项目在 EdgeOne Pages 上已验证可以以与 Vercel 基本一致的方式运行,不再需要
NEXT_PUBLIC_EDGE_DEPLOY等特殊开关。 - 所有运行环境(包括 Vercel、EdgeOne 等)都需要提供可用的数据库连接:
POSTGRES_URL或DATABASE_URL,否则服务端渲染会直接报错。 - EdgeOne 图片显示问题:如果发现
public/目录下的图片(如微信公众号二维码、师资照片等)无法显示,且浏览器控制台显示/next/image?url=...返回 400 错误,请在 EdgeOne 环境变量中设置NEXT_IMAGE_UNOPTIMIZED=true。这会禁用 Next.js Image Optimization API,直接使用静态文件路径,确保图片正常显示。 - 如目标平台仅支持“纯静态文件托管”,且无法运行 Node.js/Next.js 服务器,则本项目将无法完整提供动态功能(数据库查询、API Routes 等)。
culture_china/project/
├── public/
│ └── images/ # 静态资源
│ ├── branding/ # Logo、Banner、Icon
│ ├── events/ # 活动图片
│ └── people/ # 人员照片
│
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API Routes
│ │ ├── intro/ # 计划介绍页面
│ │ ├── activities/ # 特色活动
│ │ ├── admissions/ # 招生信息
│ │ ├── alumni/ # 学员风采
│ │ ├── curriculum/ # 课程教学
│ │ ├── layout.tsx # 根布局
│ │ ├── page.tsx # 首页
│ │ └── globals.css # 全局样式
│ │
│ ├── components/
│ │ ├── home/ # 首页组件
│ │ ├── shared/ # 共享组件
│ │ └── ui/ # UI 基础组件
│ │
│ ├── db/
│ │ └── schema.ts # Drizzle 数据模型
│ │
│ └── lib/
│ ├── db.ts # 数据库连接
│ ├── env.ts # 环境变量校验
│ └── utils.ts # 工具函数
│
├── docs/ # 项目文档
│ ├── background/ # 背景介绍
│ ├── basic_rule/ # 规范文档
│ ├── plan/ # 功能规划
│ └── task/ # 任务清单
│
├── drizzle.config.ts # Drizzle 配置
├── components.json # shadcn/ui 配置
├── tailwind.config.ts # Tailwind 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 项目依赖
| 文件/目录 | 说明 |
|---|---|
src/app/ |
Next.js App Router 路由与页面 |
src/components/shared/ |
跨页面共享组件(Header/Footer/PageShell) |
src/components/home/ |
首页专用组件(HeroCarousel) |
src/db/schema.ts |
数据库模型定义(resources/alumni/faculty) |
src/lib/env.ts |
环境变量 Zod 校验(支持 Vercel Postgres) |
drizzle.config.ts |
Drizzle CLI 配置 |
components.json |
shadcn/ui 组件配置 |
- Server Components First:默认服务端组件,仅在需要
useState/useEffect/事件监听时使用"use client" - Composition:拆分大型组件为小型、单一职责的组件
- Props Interface:显式定义 Props 接口,禁止
any
graph LR
A[Server Component] -->|直接查询| B[Database]
C[Client Component] -->|调用| D[Server Action]
C -->|或| E[API Route]
D --> B
E --> B
- 必须使用 Tailwind CSS,禁止 CSS Modules / styled-components
- 使用
cn()工具函数合并条件类名 - 类名排序:布局 → 盒模型 → 排版 → 视觉 → 其他
- UI 层:使用
error.tsx(Error Boundaries) - Server Actions:返回
{ success: boolean, data?: T, error?: string }
| 文档 | 说明 |
|---|---|
docs/basic_rule/ARCHITECTURE.md |
技术架构规范 |
docs/basic_rule/DESIGH_SYSTEM.md |
视觉与设计系统 |
docs/plan/FEATURE_LIST.md |
功能规划清单 |
docs/task/TODO.md |
阶段性开发进度 |
docs/background/intro.md |
项目背景介绍 |
graph TD
A[开发功能] --> B[运行 pnpm lint]
B --> C{通过?}
C -->|否| D[修复错误]
D --> B
C -->|是| E[更新 TODO.md]
E --> F[Git Commit]
F --> G[可选: Git Push]
根据 docs/task/TODO.md,当前 Phase 0–3 已完成:
- Phase 0:基础设施与数据库环境 ✅
- Phase 1:前端页面骨架(首页 / 介绍 / 学员风采 / 特色活动 / 招生等)✅
- Phase 2:后端数据库模型与管理后台(外链资源 / 活动媒体 / 学员风采)✅
- Phase 3:前后台数据打通(首页轮播、活动流、学员风采列表等)✅
后续将进入 Phase 4:视觉打磨与性能优化(细节样式、动画、SEO 等)。
- 遵循项目规范(见
docs/basic_rule/) - 完成模块后更新
docs/task/TODO.md - 提交前运行
pnpm lint确保代码质量 - 使用清晰的 commit message
© 2025 浙江大学晨兴文化中国人才计划
