personal-homepage/REQUIREMENTS.md

283 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 个人主页 — 需求文档
## 1. 项目范围
本项目是一个**公开静态站点 + 构建时数据同步层**。
站点运行时仍然是纯静态页面,但在构建阶段由本项目主动向 Gitea / Seafile 拉取所需数据,清洗后生成本地只读数据文件,再交给 Astro 渲染。
也就是说:
- **运行时**:纯静态站点,对外公开访问
- **构建时**:服务端脚本拉取远程数据、生成内容文件
AstrBot、定时任务、手动脚本等都可以作为“触发构建”的外部入口但**同步逻辑本身属于这个仓库的一部分**。
- 域名:`sepcomet.xyz`(备案中)
- 部署:自有服务器 Docker 环境
- 访问:完全公开,求职时可直接给链接
- 用户背景Unity 客户端开发Web 经验不多,怎么方便怎么来
---
## 2. 页面与功能
### 2.1 首页
- **Hero 区**头像、名字、一句话简介、社交链接GitHub/Gitea/Blog 等)
- **开发日志摘要**:最新 3-5 条日志的卡片列表
- **精选项目**featured 项目的卡片展示
- **Gitea 活动概览**:贡献热力图(可选)
### 2.2 开发日志(/logs
- 按时间倒序的日志列表
- 每条日志卡片:标题、日期、标签、摘要
- 点击进入日志详情页(/logs/[slug]
- 日志详情Markdown 全文渲染,关联的仓库名和 commit 链接
- 内容来自 `src/content/logs/` 下的 `.md` 文件
- 首版允许日志继续由手动维护或外部系统写入;日志生成逻辑不要求在本项目内实现
### 2.3 项目展示(/projects
- 项目卡片网格布局
- 每个项目卡片:名称、描述、封面图、标签
- 点击可展开/跳转详情演示视频如有、Gitea 仓库链接、Seafile 下载链接(如有)
- 数据来源:构建时从 Gitea / Seafile 拉取并生成的结构化数据文件
- 页面层只读取最终生成数据,不直接处理上游 API 响应
### 2.4 Gitea 统计(可嵌入首页或独立页)
- 贡献热力图
- 最近活动列表
- 仓库简要信息(名称、描述、更新时间、链接等)
- 数据由构建脚本从 Gitea 拉取并清洗
- 运行时不依赖浏览器直接访问带 token 的私有 API
### 2.5 Seafile 分享(/shares 或首页侧栏)
- 文件分享链接列表,每条含:文件名、描述、链接、时间
- 数据来源:构建时从 Seafile 拉取并生成的结构化数据文件
- 支持展示特定目录或特定文件(如项目打包产物)
- 首版优先展示文件元数据与下载链接;如确有需要,可在后续增加“构建时镜像文件到站点静态目录”的能力
---
## 3. 功能优先级
**P0必须有**
- 首页 Hero 区(个人简介 + 链接)
- 日志列表 + 详情页Markdown 渲染)
- 项目展示卡片
- 构建时 Gitea / Seafile 数据同步入口
**P1很重要**
- Gitea 贡献热力图(基于构建期抓取的数据渲染)
- 仓库摘要信息同步
- Seafile 分享列表同步
- 响应式布局
**P2锦上添花**
- 日志按标签/时间筛选
- 项目演示视频嵌入
- 构建时镜像特定 Seafile 文件到站点静态目录
- 深色模式
---
## 4. 技术选型
| 层 | 选型 | 理由 |
|----|------|------|
| **框架** | [Astro](https://astro.build) | 静态站点生成,原生 `.md` 支持,零 JS 默认 + 可选交互岛 |
| **样式** | CSS当前 / Tailwind CSS可选 | 首版以简单直接、低心智负担为主,是否接 Tailwind 以后续实现成本决定 |
| **交互组件** | Astro 原生 + 按需引入 React | 默认静态渲染;只有热力图等确需交互时再引入前端组件 |
| **内容存储** | 文件系统(`.md` + `.json` | 构建脚本先把远程数据清洗为本地文件,再统一消费 |
| **数据同步** | Node.js 构建脚本 | 服务端拉取 Gitea / Seafile 数据,避免浏览器暴露 token |
| **部署** | Nginx + Docker | 静态文件服务,单容器 |
| **构建触发** | 手动 / 定时任务 / AstrBot | `npm run content:sync``npm run build` → 部署静态产物 |
---
## 5. 数据模型
### 日志 frontmattersrc/content/logs/*.md
```yaml
---
title: "personal-homepage 项目初始化"
date: 2026-05-03
repo: "sepcomet/personal-homepage"
tags: [astro, init, setup]
summary: "搭建 Astro 项目骨架,确定目录结构与部署方案"
---
正文内容Markdown — 客观 diff 分析 + 主观动机,由 AstrBot 生成后写入
```
### 项目数据(示例:`src/data/generated/projects.json`
```json
[
{
"name": "personal-homepage",
"description": "个人主页 Dashboard",
"gitea_repo": "sepcomet/personal-homepage",
"repo_url": "https://gitea.sepcomet.xyz/sepcomet/personal-homepage",
"cover_image": "/images/projects/homepage.png",
"demo_video": "https://...",
"download_link": "https://seafile.sepcomet.xyz/...",
"tags": ["astro", "web"],
"featured": true,
"updated_at": "2026-05-05T00:00:00Z",
"source": "gitea+seafile"
}
]
```
### Gitea 活动数据(示例:`src/data/generated/gitea-activity.json`
```json
{
"updatedAt": "2026-05-05T00:00:00Z",
"days": [
{ "date": "2026-05-01", "count": 3 },
{ "date": "2026-05-02", "count": 0 }
],
"recent": [
{
"type": "push",
"repo": "sepcomet/personal-homepage",
"message": "更新首页模块结构",
"url": "https://gitea.sepcomet.xyz/...",
"time": "2026-05-05T00:00:00Z"
}
]
}
```
### 分享 / 下载数据(示例:`src/data/generated/shares.json`
```json
[
{
"name": "personal-homepage-demo.zip",
"description": "项目打包产物",
"url": "https://seafile.sepcomet.xyz/...",
"time": "2026-05-05T00:00:00Z",
"size": 12345678,
"source": "seafile"
}
]
```
### 站点配置src/config.ts
```ts
export const site = {
name: "SepComet",
title: "个人主页",
tagline: "Unity 开发者",
avatar: "/images/avatar.png",
gitea: {
url: "https://gitea.sepcomet.xyz",
username: "sepcomet"
},
links: [
{ name: "Gitea", url: "https://gitea.sepcomet.xyz" },
{ name: "GitHub", url: "https://github.com/sepcomet" }
]
}
```
---
## 6. 目录结构
```
personal-homepage/
├── src/
│ ├── pages/
│ │ ├── index.astro # 首页
│ │ ├── logs/
│ │ │ ├── index.astro # 日志列表
│ │ │ └── [slug].astro # 日志详情
│ │ ├── projects/
│ │ │ └── index.astro # 项目展示
│ │ └── shares.astro # Seafile 分享
│ ├── components/
│ │ ├── Header.astro
│ │ ├── Footer.astro
│ │ ├── Hero.astro
│ │ ├── LogCard.astro
│ │ ├── ProjectCard.astro
│ │ └── GiteaHeatmap.jsx # React Island
│ ├── content/
│ │ └── logs/ # *.md 日志内容
│ ├── data/
│ │ └── generated/ # 构建时同步生成的 JSON
│ │ ├── gitea-activity.json
│ │ ├── projects.json
│ │ └── shares.json
│ ├── config.ts
│ └── styles/
│ └── global.css
├── scripts/
│ ├── fetch-gitea.ts
│ ├── fetch-seafile.ts
│ └── sync-content.ts
├── public/
│ ├── images/
│ │ └── avatar.png
│ └── downloads/ # 可选:构建时镜像的下载文件
│ └── favicon.svg
├── astro.config.mjs
├── Dockerfile
├── docker-compose.yml
└── package.json
```
---
## 7. 部署
```yaml
# docker-compose.yml
services:
homepage:
build: .
ports:
- "8080:80"
volumes:
- ./src/content:/app/src/content # 日志/项目内容热更新
- ./public/images:/app/public/images
restart: unless-stopped
```
- Docker 构建阶段:`npm run build` 生成静态文件
- Docker 构建阶段:先执行 `npm run content:sync`,再执行 `npm run build`
- 运行阶段Nginx 托管 `dist/` 目录
- 日常更新:定时任务 / AstrBot 触发同步与重建
- Gitea / Seafile token 只存在于构建环境,不进入前端产物
---
## 8. 实施计划
| Phase | 内容 | 产出 |
|-------|------|------|
| **1** | Astro 项目初始化 + 首页/日志/项目/分享骨架 | 可访问的骨架页面 |
| **2** | 日志系统:列表页 + 详情页 + frontmatter 解析 + 示例内容 | 日志模块 |
| **3** | 数据同步层Gitea / Seafile 拉取脚本、环境变量、生成文件 | 构建期数据链路 |
| **4** | 页面改读生成数据 + Gitea 活动真实化 + 仓库摘要接入 | 统计与项目模块 |
| **5** | Docker、定时重建、响应式打磨、深色模式、SEO | 收尾 |
---
## 9. 不在此项目范围内
- AstrBot 插件开发(独立项目)
- 日志 markdown 文件的生成逻辑(可由 AstrBot 或其他系统负责)
- 自动化部署流程CI/CD可后续补充
本项目负责:**构建时拉取远程数据 / 读取本地日志 → 生成站点数据文件 → 渲染为 HTML → 静态托管**。