commit 6eec416149e47afe5801e52180dd740e2a0d4f22 Author: chengongfei Date: Wed Jul 29 20:08:09 2026 +0800 init fragmemo (memo SPA + go backend) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec4d0f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +dist/ +.env +*.local +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6f12cc --- /dev/null +++ b/README.md @@ -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 | +| 认证 | JWT(access_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:3001,API 请求自动代理到后端。 + +## 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 diff --git a/docs/方案文档.md b/docs/方案文档.md new file mode 100644 index 0000000..2a1414d --- /dev/null +++ b/docs/方案文档.md @@ -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. diff --git a/docs/架构方案.md b/docs/架构方案.md new file mode 100644 index 0000000..1093d32 --- /dev/null +++ b/docs/架构方案.md @@ -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 回退数据库 diff --git a/docs/部署指南.md b/docs/部署指南.md new file mode 100644 index 0000000..4476fbc --- /dev/null +++ b/docs/部署指南.md @@ -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 +``` diff --git a/memo.fragford.cn b/memo.fragford.cn new file mode 160000 index 0000000..dba088d --- /dev/null +++ b/memo.fragford.cn @@ -0,0 +1 @@ +Subproject commit dba088d742085404bda75a8a43695ec6ed16f9ca diff --git a/memo_server b/memo_server new file mode 160000 index 0000000..a5ae6a6 --- /dev/null +++ b/memo_server @@ -0,0 +1 @@ +Subproject commit a5ae6a6431ddf9fab7ea13a6696dfd1c19e08d26