# 个人主页 — 需求文档 ## 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. 数据模型 ### 日志 frontmatter(src/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 → 静态托管**。