init fragmemo (memo SPA + go backend)

This commit is contained in:
chengongfei
2026-07-29 20:08:09 +08:00
commit 6eec416149
7 changed files with 516 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
node_modules/
dist/
.env
*.local
.DS_Store
+91
View File
@@ -0,0 +1,91 @@
# fragmemo - 碎片笔记
轻量级、自托管的笔记 Web 应用。Markdown 快速记录、标签分类、全文搜索、图片上传、私密/公开模式。
## 项目结构
```
fragmemo/
├── memo.fragford.cn/ # React 前端(独立 Git 仓库)
├── memo_server/ # Python 后端(独立 Git 仓库)
├── frag_memo_app/ # 预留:鸿蒙 ArkTS App(独立 Git 仓库)
└── docs/ # 物料文档
```
## 技术栈
| 模块 | 技术 |
|------|------|
| 前端 | React 19 + TypeScript + Vite + Tailwind CSS |
| 后端 | Python 3.11+ + FastAPI + SQLAlchemy async |
| 数据库 | MySQL 8.0 |
| 认证 | JWTaccess_token + refresh_token |
## 本地开发
### 后端
```bash
cd memo_server
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # 修改数据库连接配置
uvicorn app.main:app --reload
```
访问 http://localhost:8000/docs 查看 Swagger API 文档
### 前端
```bash
cd memo.fragford.cn
npm install
npm run dev
```
前端开发服务器运行在 http://localhost:3001API 请求自动代理到后端。
## API 接口
所有接口以 `/api/v1/` 开头,认证接口使用 JWT Bearer Token。
### 认证
- `POST /api/v1/auth/register` - 注册
- `POST /api/v1/auth/login` - 登录
- `POST /api/v1/auth/refresh` - 刷新 Token
- `GET /api/v1/auth/me` - 获取当前用户
- `PUT /api/v1/auth/me` - 更新个人信息
- `GET /api/v1/auth/me/stats` - 获取用户统计
### 笔记
- `GET /api/v1/memos` - 笔记列表(支持 cursor/limit/search/tag/visibility
- `POST /api/v1/memos` - 创建笔记
- `GET /api/v1/memos/{id}` - 笔记详情
- `PUT /api/v1/memos/{id}` - 更新笔记
- `DELETE /api/v1/memos/{id}` - 删除笔记
### 标签
- `GET /api/v1/tags` - 标签列表
- `POST /api/v1/tags` - 创建标签
- `PUT /api/v1/tags/{id}` - 更新标签
- `DELETE /api/v1/tags/{id}` - 删除标签
### 文件
- `POST /api/v1/files/upload` - 上传文件
- `GET /api/v1/files/{id}` - 获取文件
## 部署到服务器
### 你需要做的事情(部署时)
1. 在宝塔面板创建 MySQL 数据库 `fragmemo`
2. 在宝塔 → 软件商店 → Python 项目管理器 添加 `memo_server` 项目
3. 在宝塔 → 网站 添加站点(端口自定),配置 Nginx 反向代理
4. 配置 Nginx`/api/*` 转发到 `127.0.0.1:8000``/*` 指向前端 dist/
部署脚本见各子项目的 `deploy.sh`
## License
MIT
+125
View File
@@ -0,0 +1,125 @@
# AGENTS.md
Repository instructions for AI coding agents. Keep this file short, concrete, and tied to commands that actually work in this
repo. If a fact here conflicts with source files or CI config, trust the source file and update this guide.
## Project Snapshot
Memos is a self-hosted note-taking app.
- Backend: Go 1.26.2, Echo v5, Connect RPC, gRPC-Gateway, Protocol Buffers.
- Frontend: React 19, TypeScript 6, Vite 8, Tailwind CSS v4, React Query v5.
- Storage: SQLite, MySQL, PostgreSQL.
- Generated API outputs: `proto/gen/` for Go/OpenAPI, `web/src/types/proto/` for TypeScript.
## Working Rules
- Read relevant code before editing; prefer local patterns over new abstractions.
- Keep diffs scoped. Do not do repo-wide cleanup, dependency churn, or generated-file rewrites unless the task requires it.
- Do not hand-edit generated proto outputs. Change `.proto` files, then run `buf generate`.
- Add migrations for all database drivers when schema changes, and update each driver's `LATEST.sql`.
- Add public API endpoints to `server/router/api/v1/acl_config.go`.
- Ask before adding heavy dependencies, changing auth/token behavior, or altering Docker/release workflows.
## Commands
Run from the repository root unless a command starts with `cd`.
```bash
# Backend
go run ./cmd/memos --port 8081 # Start backend dev server
go test ./... # Run all Go tests
go test -v ./store/... # Store tests, including DB drivers via TestContainers
go test -v -race ./server/... # Server tests with race detector
go test -v -race ./internal/... # Internal package tests with race detector
go test -v -run TestFoo ./pkg/... # Run matching Go tests
go mod tidy -go=1.26.2 # Match CI tidy check
golangci-lint run # Go lint, config: .golangci.yaml
golangci-lint run --fix # Auto-fix lint, including goimports
# Frontend
cd web && pnpm install # Install dependencies
cd web && pnpm dev # Dev server on :3001, proxying API to :8081
cd web && pnpm lint # Type check + Biome lint
cd web && pnpm test # Vitest unit tests
cd web && pnpm build # Production build
cd web && pnpm release # Build SPA into server/router/frontend/dist
# Protocol Buffers
cd proto && buf generate # Regenerate Go + TypeScript + OpenAPI
cd proto && buf lint # Lint proto files
cd proto && buf format -w # Format proto files
```
## Code Map
| Path | Purpose |
| --- | --- |
| `cmd/memos/main.go` | Cobra/Viper CLI setup and server startup |
| `server/server.go` | Echo HTTP server and background runner wiring |
| `server/auth/` | JWT access tokens, refresh tokens, PAT handling |
| `server/router/api/v1/` | Connect/gRPC-Gateway services, ACL config, SSE hub |
| `server/router/frontend/` | Static SPA serving |
| `server/router/fileserver/` | Native HTTP file serving, thumbnails, range requests |
| `server/runner/` | Background memo processing and S3 presign refresh |
| `store/` | Store facade, cache, migrations, driver interface |
| `store/db/{sqlite,mysql,postgres}/` | Database-specific drivers and SQL |
| `proto/api/v1/` | Public API service definitions |
| `proto/store/` | Internal storage proto messages |
| `internal/` | App-private packages: scheduler, cron, email, CEL filter, markdown, idp, S3 |
| `web/src/connect.ts` | Connect RPC clients, auth interceptor, access-token refresh |
| `web/src/auth-state.ts` | Token storage and BroadcastChannel cross-tab sync |
| `web/src/hooks/` | React Query hooks for server state |
| `web/src/contexts/` | React context for client/UI state |
| `web/src/components/` | Radix/Tailwind UI components and feature components |
| `web/src/themes/` | CSS themes using OKLch color tokens |
## Change Routing
| Change | Update | Verify |
| --- | --- | --- |
| Go service or router behavior | Service code under `server/`, tests near package | `go test -v -race ./server/...` |
| Store or migration behavior | `store/`, all three DB driver migrations, `LATEST.sql` | `go test -v ./store/...` |
| Internal package logic | Relevant `internal/` package tests | `go test -v -race ./internal/...` |
| Frontend behavior | Components/hooks/contexts under `web/src/` | `cd web && pnpm lint && pnpm test` |
| Frontend production output | Vite config or release-sensitive UI | `cd web && pnpm build` or `pnpm release` |
| Proto API | `.proto` source plus generated outputs | `cd proto && buf generate && buf lint` |
| Public unauthenticated route | `server/router/api/v1/acl_config.go` | Targeted server test or manual route check |
## Go Conventions
- Wrap errors with `errors.Wrap(err, "context")` from `github.com/pkg/errors`; do not use `fmt.Errorf`.
- Return service errors with `status.Errorf(codes.X, "message")`.
- Keep imports grouped as stdlib, third-party, then `github.com/usememos/memos`; goimports is run by golangci-lint.
- Add doc comments for exported identifiers; godot enforces exported comment punctuation.
- Avoid package-level mutable state unless the surrounding package already uses that pattern.
## Frontend Conventions
- Use `@/` for absolute imports.
- Follow Biome formatting: 2-space indent, double quotes, semicolons, 140-character line width.
- Put server data in React Query hooks under `web/src/hooks/`; keep UI-only state in contexts or component state.
- Use Tailwind CSS v4 utilities, `cn()` for class merging, and CVA for variants.
- Reuse Radix primitives and existing components before adding new UI primitives.
- Keep generated proto TypeScript under `web/src/types/proto/` out of manual edits and Biome rewrites.
## Database And Proto Rules
- Schema changes require SQLite, MySQL, and PostgreSQL migrations plus `LATEST.sql` updates.
- Fresh-install SQL and incremental migrations must stay equivalent.
- Proto field changes must preserve compatibility unless the task explicitly allows a breaking API change.
- Regenerate after proto edits and include both Go/OpenAPI and TypeScript generated outputs.
## Verification Policy
- Run the narrowest relevant checks while iterating.
- Before finishing, run the checks that match the changed surface from "Change Routing".
- For docs-only changes, `git diff --check` is sufficient unless the docs include runnable examples that should be tested.
- If a required check cannot run locally, report the reason and the exact command that remains.
## CI Reference
- Backend CI: Go 1.26.2, `go mod tidy -go=1.26.2`, golangci-lint v2.11.3, test groups `store`, `server`, `internal`, `other`.
- Frontend CI: Node 24, pnpm 11.0.1, `pnpm lint`, `pnpm test`, `pnpm build`.
- Proto CI: `buf lint` and `buf format` check.
- Docker: `scripts/Dockerfile`, Alpine 3.21 runtime, non-root user, port 5230, multi-arch amd64/arm64/arm/v7.
+115
View File
@@ -0,0 +1,115 @@
---
name: fragmemo-plan
overview: "在 fragmemo 总目录下分三个独立仓库 + docs 构建笔记应用"
todos:
- content: "Phase 1 - 脚手架:memo_server 后端骨架 + memo.fragford.cn 前端骨架"
status: pending
priority: high
- content: "Phase 2 - 用户认证系统:JWT 注册/登录 + 前端登录注册页"
status: pending
priority: high
- content: "Phase 3 - 笔记核心 CRUD:创建/列表/详情/编辑/删除 + Markdown"
status: pending
priority: high
- content: "Phase 4 - 标签系统:标签 CRUD + 笔记打标 + 筛选"
status: pending
priority: high
- content: "Phase 5 - 搜索功能:关键词搜索笔记"
status: pending
priority: medium
- content: "Phase 6 - 图片/文件上传:支持笔记中插入图片"
status: pending
priority: medium
- content: "Phase 7 - 个人主页:用户信息 + 统计"
status: pending
priority: low
- content: "Phase 8 - 部署配套:deploy.sh + 服务器操作清单"
status: pending
priority: high
---
# fragmemo 笔记应用 · 实现计划
## Goal
构建 **fragmemo** 笔记 Web 应用:Markdown 快速记录、标签分类、搜索、图片上传、私密/公开模式。后期扩展鸿蒙 ArkTS App。
## 目录结构
```
/Users/a58/Documents/fragfordspace/
└── fragmemo/ # 总项目目录
├── docs/ # 📚 物料文档
│ ├── memos-main/ # 原版 memos 参考源码
│ └── 方案文档/ # 架构方案、API 设计等
├── memo.fragford.cn/ # 🌐 前端 React 项目(独立 Git 仓库)
│ ├── public/
│ ├── src/
│ │ ├── api/ # API 调用
│ │ ├── hooks/ # React Query
│ │ ├── contexts/ # 状态管理
│ │ ├── components/ # 通用组件
│ │ ├── pages/ # 页面
│ │ └── styles/ # 样式
│ ├── deploy.sh
│ ├── package.json
│ ├── vite.config.ts
│ └── tsconfig.json
├── memo_server/ # ⚙️ 后端 Python 项目(独立 Git 仓库)
│ ├── app/
│ │ ├── main.py # FastAPI 入口
│ │ ├── config.py # 配置
│ │ ├── database.py # 数据库
│ │ ├── exceptions.py # 异常处理
│ │ ├── models/ # ORM 模型
│ │ ├── schemas/ # 数据校验
│ │ ├── routers/ # API 路由
│ │ ├── services/ # 业务逻辑
│ │ └── auth/ # JWT 认证
│ ├── uploads/
│ ├── deploy.sh
│ ├── requirements.txt
│ └── .env
└── frag_memo_app/ # 📱 预留鸿蒙 App(独立 Git 仓库)
└── README.md
```
## 技术栈
| 层 | 技术 |
|----|------|
| 后端 | Python 3.11+ / FastAPI / SQLAlchemy async / PyJWT / bcrypt |
| 前端 | React 18+ / TypeScript / Vite / Tailwind CSS / React Query |
| 数据库 | MySQL 8.0(服务器已有,Phase 8 时你操作) |
## 分工
| 我负责(本地代码) | 你负责(Phase 8 时在服务器操作) |
|-----------------|-----------------------------|
| 全部 Python 后端代码 | 宝塔 Python 项目管理器添加项目 |
| 全部 React 前端代码 | 创建 MySQL 数据库和用户 |
| 部署脚本(deploy.sh | 配置 Nginx 反向代理 |
| 项目文档(README) | 设置环境变量 |
## 设计概要
- **数据库**5 张表(users, memos, tags, memo_tags, files
- **API**RESTful`/api/v1/` 前缀,JWT Bearer 认证
- **前端**:8 个页面(首页、登录、注册、笔记列表、新建/编辑、详情、标签管理、个人主页)
- **部署**:后端用宝塔 Python 项目管理器 + 前端 rsync 静态文件 + Nginx 反代
## 执行顺序
1. **Phase 1**:脚手架搭建(server/ 骨架 + web/ 骨架)
2. **Phase 2**:用户认证(JWT + 登录注册)
3. **Phase 3**:笔记 CRUD(核心功能)
4. **Phase 4**:标签系统
5. **Phase 5**:搜索功能
6. **Phase 6**:图片上传
7. **Phase 7**:个人主页
8. **Phase 8**:部署配套(deploy.sh + 服务器操作指南)
## Verification
每个 Phase 完成后:后端 Swagger UI 测试 + 前端功能走通
## Rollback
- Git revert 回退代码
- Alembic downgrade 回退数据库
+178
View File
@@ -0,0 +1,178 @@
# fragmemo 部署指南
> 部署到华为云服务器(宝塔面板 + Ubuntu 22.04
---
## 一、前置信息
| 项目 | 值 |
|------|-----|
| 服务器 IP | `113.44.249.175` |
| 操作系统 | Ubuntu 22.04 |
| 宝塔面板 | `https://113.44.249.175:2026/527378` |
| MySQL | 已安装(宝塔管理) |
| Nginx | 已安装(宝塔管理) |
| Gitea | `http://113.44.249.175:4000` |
| 项目目录 | `/www/wwwroot/memo_server/`(后端) |
| 前端目录 | `/www/wwwroot/memo.fragford.cn/`(前端静态文件) |
| 对外端口 | **82**(与 echo.fragford.cn 共用) |
| 访问方式 | `http://113.44.249.175:82` |
| 备案通过后 | `https://memo.fragford.cn` |
---
## 二、服务器操作步骤
### 2.1 创建 MySQL 数据库(可选,目前使用 SQLite)
打开宝塔面板 → 数据库 → 添加数据库:
| 项目 | 值 |
|------|-----|
| 数据库名 | `fragmemo` |
| 用户名 | `fragmemo` |
| 密码 | 自己设一个(记住它后面要用) |
| 访问权限 | `127.0.0.1`(本地,不要对外开放) |
创建后修改 `/www/wwwroot/memo_server/.env` 中的 `DATABASE_URL`
```
DATABASE_URL=mysql+asyncmy://fragmemo:密码@127.0.0.1:3306/fragmemo
```
然后重启后端:`systemctl restart memo-server`
### 2.2 部署前端
本地 Mac 上,一键构建并同步到服务器:
```bash
cd /Users/a58/Documents/fragfordspace/fragmemo/memo.fragford.cn
npm run deploy
```
### 2.3 部署后端
本地 Mac 上,一键同步并重启:
```bash
cd /Users/a58/Documents/fragfordspace/fragmemo/memo_server
bash deploy.sh
```
或者手动操作:
```bash
# SSH 到服务器
ssh root@113.44.249.175
# 拉取最新代码
cd /www/wwwroot/memo_server
git pull
# 激活虚拟环境 & 安装依赖
source venv/bin/activate
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 重启
systemctl restart memo-server
```
### 2.4 查看日志
```bash
journalctl -u memo-server -f
```
### 2.5 验证部署
浏览器访问 `http://113.44.249.175:82`,你应该能看到 fragmemo 首页。
验证 API 是否正常:
```bash
curl http://113.44.249.175:82/api/v1/auth/health
```
---
## 三、本地开发日常流程
以后你改了代码,部署流程就是:
```bash
# 前端部署(一键)
cd /Users/a58/Documents/fragfordspace/fragmemo/memo.fragford.cn
bash deploy.sh
# 后端部署(一键)
cd /Users/a58/Documents/fragfordspace/fragmemo/memo_server
bash deploy.sh
```
两个脚本都是**独立的 shell 脚本**(不是 npm script),都有:
- ✅ 分支检查(只能在 main 部署)
- ✅ 工作区干净检查
- ✅ 版本信息展示(提交哈希、作者、时间)
- ✅ 构建/同步过程
- ✅ 服务器端发布日志记录(DEPLOY_LOG.md
- ✅ 部署结果汇总
---
## 四、ICP 备案通过后(HTTPS + 域名)
备案通过后,把 Nginx 配置改为:
```nginx
server {
listen 443 ssl;
server_name memo.fragford.cn;
ssl_certificate /www/server/panel/vhost/cert/memo.fragford.cn/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/memo.fragford.cn/privkey.pem;
root /www/wwwroot/memo.fragford.cn;
index index.html;
location /api/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
try_files $uri $uri/ /index.html;
}
}
server {
listen 80;
server_name memo.fragford.cn;
return 301 https://$host$request_uri;
}
```
在宝塔面板可以直接申请 Let's Encrypt 免费 SSL 证书。
---
## 五、常见问题
### Q:端口 8000 被占用了?
在宝塔 Python 项目管理器里改监听端口,或先 `pkill -f uvicorn` 杀掉旧进程。
### Q:前端页面空白、接口报错?
检查 Nginx 配置里 `/api/` 的 proxy_pass 是否正确指向了后端的地址和端口。
### Q:数据库连不上?
确认 `.env` 里的 DATABASE_URL 中的密码、用户名、数据库名都正确。可以先在服务器上用命令行测试:
```bash
mysql -u fragmemo -p -h 127.0.0.1
```
### Q:后端启动了但访问 502?
检查后端是否真的在运行:`curl http://127.0.0.1:8000/health`。如果没运行,去宝塔 Python 项目管理器启动它。
### Q:部署后端时 pip install 很慢?
可以临时换国内镜像:
```bash
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
```
+1
Submodule memo.fragford.cn added at dba088d742
Submodule
+1
Submodule memo_server added at a5ae6a6431