docs: README + LICENSE + CONTRIBUTING + CHANGELOG + API reference + issue/PR templates + editorconfig
ci / test (push) Failing after 17m5s
ci / test (push) Failing after 17m5s
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: Bug 报告
|
||||
about: 报告一个可复现的问题
|
||||
title: '[Bug] 简述'
|
||||
labels: bug
|
||||
---
|
||||
|
||||
**环境**
|
||||
- 部署方式:Docker / 源码
|
||||
- 端:浏览器 PWA / Windows 桌面 / 移动端
|
||||
- 版本/提交:
|
||||
|
||||
**复现步骤**
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
**期望行为**
|
||||
|
||||
**实际行为**
|
||||
|
||||
**日志**(`docker logs footprints-sync --tail 50`,注意脱敏 token/密码)
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: 功能建议
|
||||
about: 提议一个新功能或改进
|
||||
title: '[Feature] 简述'
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
**使用场景**(想解决什么问题)
|
||||
|
||||
**期望形态**(记录/检索/统计会长什么样)
|
||||
|
||||
**替代方案**
|
||||
|
||||
**补充**
|
||||
@@ -0,0 +1,15 @@
|
||||
## 变更说明
|
||||
|
||||
<!-- 做了什么、为什么 -->
|
||||
|
||||
## 关联 Issue
|
||||
|
||||
- #
|
||||
|
||||
## 自查清单
|
||||
|
||||
- [ ] `node scripts/check.mjs` 通过
|
||||
- [ ] `node scripts/test-integration.mjs` 通过(涉及行为变更时补了断言)
|
||||
- [ ] 服务端保持零 npm 依赖
|
||||
- [ ] schema 变更兼容旧库平滑迁移
|
||||
- [ ] UI 改动适配亮/暗主题
|
||||
@@ -0,0 +1,30 @@
|
||||
# 更新日志
|
||||
|
||||
本项目的所有显著变更都记录在此文件中。
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
||||
版本遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
## [0.1.0] - 2026-10-16
|
||||
|
||||
首个公开版本。
|
||||
|
||||
### Added
|
||||
- 云优先多用户架构:所有数据存服务器,按用户独立 SQLite 档案库;浏览器 / PWA / Windows 桌面三端同源
|
||||
- 留痕本体:自定义记录类型 + 动态表单、维度、指标、全文检索(FTS5 trigram 中文)、时间线、统计总览
|
||||
- 学业成绩:学期 GPA/排名、课程成绩、绩点梯度自定义与趋势图
|
||||
- 附件:SHA-256 内容寻址去重存储
|
||||
- 管理后台:邀请码全生命周期管理(自定义码、备注、启用/停用、删除、批量生成)、用户列表、注册配额
|
||||
- 演示账号 demo/demo1234:启动自动播种 16 条足迹 + 4 学期成绩(幂等、失败自愈)
|
||||
- PWA(sw v3:接口永不缓存)与 Tauri 桌面安装包
|
||||
- 质量设施:pre-push 钩子、静态检查套件、35 条集成断言、部署冒烟脚本、Gitea Actions CI
|
||||
|
||||
### Fixed
|
||||
- 登录持久化与刷新丢会话
|
||||
- Service Worker 缓存 /auth/me 导致切换账号后仍显示旧用户
|
||||
- 静态兜底邀请码(INVITE_CODE)注册路径不可达
|
||||
- 容器内命令层挂载方式不可靠导致的「未知命令」
|
||||
- 桌面构建可能嵌入过期前端(beforeBuildCommand 缺失)
|
||||
|
||||
### Security
|
||||
- scrypt 口令散列 + timingSafeEqual 校验
|
||||
- Bearer Token(365 天过期)、按用户数据隔离、邀请码注册门控
|
||||
@@ -0,0 +1,37 @@
|
||||
# 贡献指南
|
||||
|
||||
欢迎 Issue 与 PR!开始之前:
|
||||
|
||||
## 环境要求
|
||||
|
||||
- Node.js ≥ 22.5(推荐 24,`node:sqlite` 依赖)
|
||||
- 前端构建:npm 或 pnpm
|
||||
- 桌面端构建(可选):Rust stable + MSVC Build Tools(Windows)
|
||||
|
||||
## 开发流程
|
||||
|
||||
1. Fork / 建分支:`git checkout -b feat/your-feature`
|
||||
2. 提交信息用约定式前缀:`feat: / fix: / docs: / chore: / ci: / refactor:`
|
||||
3. 本地跑绿再推:
|
||||
|
||||
```bash
|
||||
git config core.hooksPath .githooks # 每个克隆只需一次
|
||||
node scripts/check.mjs
|
||||
node scripts/test-integration.mjs
|
||||
```
|
||||
|
||||
启用钩子后,push 会自动跑同一套检查;工作区有未提交变更或测试失败时 push 会被拒绝。
|
||||
|
||||
## 约定
|
||||
|
||||
- 服务端保持**零 npm 依赖**(只用 Node 内置模块);确需引入依赖请先开 Issue 讨论
|
||||
- 改动 `app/server/db.mjs`(命令层)时注意:Web / 桌面 / 播种三处共用它,测试必须全绿
|
||||
- 涉及 schema 变更:保证老库能平滑迁移(参考 `preMigrateColumns` 的加列模式),并在
|
||||
`scripts/test-integration.mjs` 补断言
|
||||
- 涉及 Service Worker:接口类请求(/api /auth /admin /sync)永远不得缓存
|
||||
- UI 改动请同时适配亮/暗两套主题(令牌见 `app/src/styles/theme.css`)
|
||||
|
||||
## Issue
|
||||
|
||||
- Bug 报告请附:复现步骤、期望/实际行为、服务端日志(`docker logs footprints-sync`)
|
||||
- 功能建议请说明使用场景,最好附上你期望的记录/检索形态
|
||||
@@ -1,5 +1,8 @@
|
||||
# 个人留痕系统(Footprints)设计方案
|
||||
|
||||
> ⚠️ 历史底稿:本文写于单人桌面阶段(v0.5),核心数据模型思想仍然有效;
|
||||
> 现产品已演进为**云优先多用户架构**(见 README)。设计原则与本体模型可继续作为参考。
|
||||
>
|
||||
> 版本 v0.5 · 足迹本体是核心;分类、表单、统计、导出、评分全部用户可自定义
|
||||
> 形态:单人使用 · Windows 桌面应用(MVP 已实现)· 预留多端同步
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 linyux (footpr.linyux.cn)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,154 @@
|
||||
# 足迹 Footprints
|
||||
|
||||
> 个人成长档案馆 —— 面向大学生的留痕、检索、量化与多端同步系统。
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
平时随手留痕,需要时秒级检索:**大二上学期做过什么?拿过哪些省级奖?志愿时长总共多少?**
|
||||
评奖评优、综测、简历、入党材料的素材库,也是一台记录成长的时光机。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **留痕本体** —— 自定义记录类型 + 动态表单模板;竞赛、志愿、学生工作、荣誉、证书、科研、实习皆可配;正面/负面、进行中、草稿全留痕
|
||||
- **秒级检索** —— FTS5 trigram 中文全文搜索 + 多条件筛选 + 保存视图(同一查询一键复用)
|
||||
- **时间线** —— 按学年/月分组的完整回顾
|
||||
- **学业成绩** —— 学期 GPA/排名、课程成绩、可自定义绩点梯度(grade band)与趋势图
|
||||
- **成长量化** —— 自定义维度与指标(如志愿时长),统计总览与年度对比
|
||||
- **附件佐证** —— 图片/文档上传,SHA-256 内容寻址去重
|
||||
- **多用户云优先** —— 所有数据存服务器,按用户独立 SQLite 档案库;浏览器 / PWA / Windows 桌面三端同源同步
|
||||
- **管理后台** —— 邀请码全生命周期管理(自定义码、备注、启用/停用、删除、批量生成)、用户列表、注册配额
|
||||
- **演示模式** —— 内置演示账号 `demo / demo1234`,自动播种 16 条足迹 + 4 学期成绩,开箱即看
|
||||
- **PWA + 桌面** —— 可安装到桌面/手机;Windows Tauri 安装包;亮/暗双主题
|
||||
|
||||
## 架构
|
||||
|
||||
```
|
||||
浏览器 PWA ─┐
|
||||
Windows 桌面 ─┤ HTTPS + Bearer Token(365 天)
|
||||
移动端 PWA ─┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────┐
|
||||
│ sync-server(零依赖 Node ≥ 22.5)│
|
||||
│ node:http + node:sqlite │
|
||||
│ scrypt 认证 · 邀请码 · LWW 同步 │
|
||||
└───────────────┬────────────────┘
|
||||
▼
|
||||
data/users/<uid>.db 每用户独立 SQLite 档案库
|
||||
data/blobs/<uid>/ 内容寻址附件存储
|
||||
```
|
||||
|
||||
设计取向:
|
||||
|
||||
- **服务器零 npm 依赖**:仅用 Node 内置模块(`node:http` / `node:sqlite` / `node:crypto`),攻击面与供应链风险极小
|
||||
- **命令层同源**:Web、桌面、数据播种共用同一份 `app/server/db.mjs` 命令层,同一业务逻辑多处不漂移
|
||||
- **同步元数据内建**:所有表带 uuid/hlc/origin 列 + oplog,为多端增量同步而生
|
||||
|
||||
## 快速开始(Docker 部署)
|
||||
|
||||
```bash
|
||||
git clone https://gitea.linyux.cn/root/FootPrint.git footprints
|
||||
cd footprints/sync-server
|
||||
|
||||
# 构建 + 启动(数据持久化在 ./data)
|
||||
docker compose -f docker-compose.caddy.yml up -d --build
|
||||
|
||||
# 国内拉取 node:24-alpine 超时时,换镜像源构建:
|
||||
docker compose -f docker-compose.caddy.yml build \
|
||||
--build-arg NODE_IMAGE=docker.1ms.run/library/node:24-alpine
|
||||
```
|
||||
|
||||
反向代理(Caddy 示例,容器网络需与 Caddy 同网):
|
||||
|
||||
```caddyfile
|
||||
footprints.example.com {
|
||||
reverse_proxy footprints-sync:8788
|
||||
}
|
||||
```
|
||||
|
||||
> compose 默认加入名为 `mynet` 的外部网络;没有就先 `docker network create mynet`,或把 compose 里的 networks 段改成你自己的。
|
||||
|
||||
首次使用:
|
||||
|
||||
1. 打开站点 → 注册 —— **第一个注册的账号自动成为管理员**
|
||||
2. 管理员登录 → 侧边栏「管理」→ 新建/批量生成邀请码,发给需要注册的用户
|
||||
3. 人齐之后建议收紧注册:compose 里 `REGISTER_ENABLED=false`(或改掉 `INVITE_CODE` 默认值)再 `up -d`
|
||||
4. 想先看看界面?用演示账号 **demo / demo1234** 登录,数据管够
|
||||
|
||||
## 本地开发
|
||||
|
||||
```bash
|
||||
# 1) 启动同步服务器(Node ≥ 22.5,推荐 24;零依赖,无需 npm install)
|
||||
cd sync-server
|
||||
PORT=8788 DATA_DIR=./data node src/index.mjs
|
||||
|
||||
# 2) 前端开发服务
|
||||
npm install --prefix app # 或 pnpm -C app install
|
||||
npm run dev --prefix app
|
||||
|
||||
# 3) 让网页版指向本地服务器(浏览器控制台执行一次)
|
||||
localStorage.setItem('fp-server-url', 'http://127.0.0.1:8788')
|
||||
|
||||
# 4) Windows 桌面安装包(需 Rust + MSVC)
|
||||
pnpm -C app install && pnpm -C app tauri build
|
||||
```
|
||||
|
||||
## 测试与质量
|
||||
|
||||
```bash
|
||||
node scripts/check.mjs # 语法 + 类型 + 构建 + 关键标记 tripwire
|
||||
node scripts/test-integration.mjs # 35 条集成断言(播种/登录/邀请码全矩阵/角色规则/幂等)
|
||||
node scripts/smoke.mjs <url> <user> <pass> # 部署后冒烟
|
||||
git config core.hooksPath .githooks # 启用 pre-push 钩子:工作区不干净或测试红,push 直接拒绝
|
||||
```
|
||||
|
||||
CI:push 自动跑 check + 集成测试(见 `.gitea/workflows/ci.yml`,需在 Gitea 配置 act_runner)。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
├─ app/ # 前端 + 桌面端
|
||||
│ ├─ src/ # React 19 + Vite + Tailwind v4 UI(三端共用)
|
||||
│ ├─ public/ # PWA:sw.js v3(接口绝不缓存)/ manifest / icons
|
||||
│ ├─ server/ # ★ 命令层 db.mjs:零依赖数据层(37 个命令)
|
||||
│ └─ src-tauri/ # Tauri 2 桌面壳
|
||||
├─ sync-server/ # 自建同步服务器
|
||||
│ ├─ src/ # index/auth/db/sync/attachments(零依赖)
|
||||
│ ├─ www/ # 构建产物(部署时以卷挂载,git pull 即更新)
|
||||
│ └─ docker-compose.caddy.yml
|
||||
├─ scripts/ # check / test-integration / smoke
|
||||
├─ .gitea/workflows/ # CI
|
||||
├─ .githooks/ # pre-push 钩子
|
||||
└─ docs/api.md # HTTP API 参考
|
||||
```
|
||||
|
||||
## 环境变量(sync-server)
|
||||
|
||||
| 变量 | 默认 | 说明 |
|
||||
|---|---|---|
|
||||
| `PORT` | `8788` | 监听端口 |
|
||||
| `DATA_DIR` | `./data` | 数据目录(用户库/附件/同步账本) |
|
||||
| `REGISTER_ENABLED` | `true` | 是否开放注册 |
|
||||
| `INVITE_CODE` | 空 | 静态兜底邀请码(动态码由管理员在管理页生成) |
|
||||
| `MAX_USERS` | `0` | 用户数上限,0 = 不限 |
|
||||
| `WWW_DIR` | `../www` | 前端静态目录 |
|
||||
|
||||
## 文档
|
||||
|
||||
- [HTTP API 参考](docs/api.md)
|
||||
- [设计方案(v0.5 底稿)](DESIGN.md) —— 项目的原始设计思想;现产品已演进为云优先多用户架构
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [ ] 附件缩略图 / 上传前压缩 / 大文件分片
|
||||
- [ ] 评奖评优材料包一键导出
|
||||
- [ ] 对象存储(S3)适配
|
||||
- [ ] 端到端加密存储
|
||||
- [ ] 移动端体验优化(手势、离线编辑队列)
|
||||
- [ ] 英文界面
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# HTTP API 参考
|
||||
|
||||
Base URL:部署域名(如 `https://footpr.example.com`)。除 `/health` 与 `/auth/register|login` 外,
|
||||
所有接口都需要 `Authorization: Bearer <token>`。
|
||||
|
||||
统一响应格式:
|
||||
|
||||
```json
|
||||
{ "ok": true, "data": { ... } }
|
||||
{ "ok": false, "error": "错误原因" }
|
||||
```
|
||||
|
||||
## 健康检查
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/health` | 存活探针,无需鉴权 |
|
||||
|
||||
## 认证
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| POST | `/auth/register` | 注册(`REGISTER_ENABLED`/`INVITE_CODE`/`MAX_USERS` 门控;首位用户自动成为管理员) |
|
||||
| POST | `/auth/login` | 登录,返回 Bearer Token(365 天) |
|
||||
| GET | `/auth/me` | 当前用户信息(`user_id` / `username` / `is_admin` / `device_id`) |
|
||||
|
||||
```bash
|
||||
curl -s https://footpr.example.com/auth/login \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"username":"demo","password":"demo1234","device_name":"cli"}'
|
||||
# => {"ok":true,"data":{"token":"...","user_id":"...","device_id":"...","expires_at":"..."}}
|
||||
```
|
||||
|
||||
## 管理(仅 is_admin 会话)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/admin/users` | 用户列表(设备数/记录数/附件用量) |
|
||||
| GET | `/admin/invites` | 邀请码列表(含 remark、创建者、使用者) |
|
||||
| POST | `/admin/invites/generate` | 批量生成随机码 `{"count": 5}`(1-50) |
|
||||
| POST | `/admin/invites/create` | 新建自定义码 `{"code":"XIONG-2025","remark":"备注"}`(4-32 位字母数字-\_) |
|
||||
| POST | `/admin/invites/update` | 改备注 / 启停 `{"id":1,"remark":"...","valid":false}`(已使用的码不可再启用) |
|
||||
| POST | `/admin/invites/delete` | 删除 `{"id":1}` |
|
||||
| POST | `/admin/invites/revoke` | 作废(等价 update valid=false,兼容保留) |
|
||||
| POST | `/admin/demo-seed` | 给 demo 账号播种演示数据(幂等;档案库非空时返回 seeded:false) |
|
||||
|
||||
## 同步
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/sync/status` | 当前用户同步账本统计 |
|
||||
| POST | `/sync/push` | 推送 wire 变更(LWW 上/删除,立即生效) |
|
||||
| GET | `/sync/pull?cursor=...&limit=...` | 按 seq 游标增量拉取 |
|
||||
| POST | `/sync/attachment` | 上传附件 `{"sha256","size","mime","file_name","data_b64"}`(内容寻址去重) |
|
||||
| GET | `/sync/attachment/<sha256>` | 下载附件 |
|
||||
|
||||
## 业务命令层 `POST /api/<command>`
|
||||
|
||||
与桌面端共用同一命令层(`app/server/db.mjs`),按用户隔离。37 个命令:
|
||||
|
||||
| 分组 | 命令 |
|
||||
|---|---|
|
||||
| 应用 | `app_info` · `sync_status` |
|
||||
| 记录类型 | `type_list` · `type_upsert` · `type_delete` |
|
||||
| 字典/维度 | `taxonomy_list` · `taxonomy_upsert` · `taxonomy_delete` · `dimension_list` · `dimension_upsert` · `dimension_delete` |
|
||||
| 足迹 | `footprint_list` · `footprint_get` · `footprint_upsert` · `footprint_delete` · `timeline` |
|
||||
| 统计 | `stats_overview` · `metric_list` · `metric_upsert` · `metric_delete` |
|
||||
| 成绩 | `grades_overview` · `semester_upsert` · `semester_delete` · `course_upsert` · `course_delete` · `band_upsert` · `band_delete` |
|
||||
| 附件 | `attachment_add` · `attachment_list` · `attachment_delete` · `attachment_read` |
|
||||
| 保存视图 | `view_list` · `view_upsert` · `view_delete` |
|
||||
| 播种/同步内核 | `demo_seed` · `sync_apply_wire` · `sync_pull_wire` |
|
||||
|
||||
示例(检索记录):
|
||||
|
||||
```bash
|
||||
curl -s https://footpr.example.com/api/footprint_list \
|
||||
-H 'content-type: application/json' -H "authorization: Bearer $TOKEN" \
|
||||
-d '{"query":{"page":1,"page_size":20,"year":2025}}'
|
||||
```
|
||||
|
||||
`footprint_list` 的 `query` 支持:`year`、`type_id`、`level`、`status`、`q`(全文检索)、
|
||||
`dimension_id`、`sort`(date_desc/date_asc/updated_desc/weight_desc)、分页 `page`/`page_size`。
|
||||
@@ -21,7 +21,6 @@ services:
|
||||
- REGISTER_ENABLED=true
|
||||
- INVITE_CODE=please-change-me # 多用户:注册须携带此邀请码(留空则不校验)
|
||||
- MAX_USERS=20 # 用户数上限,0=不限
|
||||
# - ADMIN_TOKEN=please-change-me # 设置后可用 GET /admin/users(请求头 X-Admin-Token)
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
Reference in New Issue
Block a user