初始提交: ScriptForge 脚本快速转运行链接服务
Some checks failed
Release / build-and-release (push) Failing after 1m31s
Some checks failed
Release / build-and-release (push) Failing after 1m31s
- Go 后端 (Gin + GORM + SQLite) 提供 API 和纯文本脚本服务 - Vite + React + TypeScript + Tailwind 前端 - 单二进制部署 (Go embed 前端静态文件) - Gitea Actions CI/CD: 打标签自动构建多平台 Release - 支持 bash/zsh/sh/fish/python3/node/ruby/php 8种运行环境 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
194
DESIGN.md
Normal file
194
DESIGN.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# ScriptForge 设计文档
|
||||
|
||||
## 概述
|
||||
|
||||
脚本快速转运行链接服务。用户粘贴脚本内容,选择运行环境,生成一个短链。在终端执行 `curl URL | <runtime>` 即可运行脚本。
|
||||
|
||||
- 前端:Next.js (App Router + Tailwind CSS + TypeScript)
|
||||
- 后端:Go (Gin + GORM + SQLite)
|
||||
- 部署:Go embed 前端静态文件,单二进制部署
|
||||
- CI/CD:Gitea Actions
|
||||
|
||||
## 核心流程
|
||||
|
||||
1. 用户打开首页 `/`
|
||||
2. 粘贴脚本内容(上限 16KB)
|
||||
3. 选择运行环境(bash / zsh / sh / fish / python3 / node / ruby / php)
|
||||
4. 选择过期时间(1小时 / 24小时 / 7天 / 30天)
|
||||
5. 提交 → 后端存入 SQLite → 返回短链 ID
|
||||
6. 页面展示生成的命令:`curl https://example.com/raw/xK8mPq | bash`
|
||||
7. 用户可以复制命令到终端执行
|
||||
|
||||
## API 设计
|
||||
|
||||
### POST /api/scripts — 创建脚本
|
||||
|
||||
请求体:
|
||||
```json
|
||||
{
|
||||
"content": "#!/bin/bash\necho hello",
|
||||
"runtime": "bash",
|
||||
"expires_in": "24h"
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"id": "xK8mPq",
|
||||
"admin_token": "dGhpcyBpcyBhIHRva2Vu",
|
||||
"url": "https://example.com/raw/xK8mPq",
|
||||
"command": "curl https://example.com/raw/xK8mPq | bash",
|
||||
"runtime": "bash",
|
||||
"expires_at": "2026-05-29T16:27:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/scripts/:id — 获取脚本元数据
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"id": "xK8mPq",
|
||||
"runtime": "bash",
|
||||
"content_length": 25,
|
||||
"created_at": "2026-05-28T16:27:00Z",
|
||||
"expires_at": "2026-05-29T16:27:00Z",
|
||||
"expired": false
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:此接口不返回脚本原始内容(内容通过 `/raw/:id` 获取),避免前端二次暴露。
|
||||
|
||||
### GET /raw/:id — 获取脚本纯文本内容
|
||||
|
||||
- 响应头 `Content-Type`: 根据 runtime 设置对应 MIME(见运行时配置表)
|
||||
- 响应头 `Content-Disposition`: `attachment; filename="script.<ext>"`(根据 runtime 设置扩展名)
|
||||
- 响应体:脚本纯文本内容
|
||||
- 如脚本已过期,返回 404
|
||||
|
||||
### DELETE /api/scripts/:id?token=xxx — 删除脚本
|
||||
|
||||
- 需要 `admin_token` 参数
|
||||
- 成功返回 204
|
||||
|
||||
## 数据模型
|
||||
|
||||
```go
|
||||
type Script struct {
|
||||
ID string `gorm:"primaryKey;size:8"`
|
||||
Content string `gorm:"type:text;not null"`
|
||||
Runtime string `gorm:"size:16;not null;index"`
|
||||
AdminToken string `gorm:"size:64;not null"`
|
||||
ExpiresAt time.Time `gorm:"not null;index"`
|
||||
CreatedAt time.Time `gorm:"not null"`
|
||||
}
|
||||
```
|
||||
|
||||
## 运行时配置
|
||||
|
||||
| Runtime | 扩展名 | MIME 类型 | 命令模板 |
|
||||
|---------|--------|-----------|----------|
|
||||
| bash | `.sh` | `text/x-shellscript` | `curl {url} \| bash` |
|
||||
| zsh | `.zsh` | `text/x-shellscript` | `curl {url} \| zsh` |
|
||||
| sh | `.sh` | `text/x-shellscript` | `curl {url} \| sh` |
|
||||
| fish | `.fish` | `text/x-shellscript` | `curl {url} \| fish` |
|
||||
| python3 | `.py` | `text/x-python` | `curl {url} \| python3` |
|
||||
| node | `.js` | `text/javascript` | `curl {url} \| node` |
|
||||
| ruby | `.rb` | `text/x-ruby` | `curl {url} \| ruby` |
|
||||
| php | `.php` | `text/x-php` | `curl {url} \| php` |
|
||||
|
||||
运行环境列表在 Go 后端定义为常量数组,用于校验请求中的 runtime 字段。
|
||||
|
||||
## 过期策略
|
||||
|
||||
- 用户保存时选择:1小时 / 24小时 / 7天 / 30天
|
||||
- 后端定时任务(每分钟扫描一次),删除过期记录
|
||||
- 过期后 `/raw/:id` 返回 404,详情页标记为已过期
|
||||
|
||||
## 限流策略
|
||||
|
||||
- 创建接口:10 次/分钟/IP
|
||||
- 其他接口:60 次/分钟/IP
|
||||
- 请求体上限:17KB
|
||||
|
||||
## 安全设计
|
||||
|
||||
- 完全公开,无需注册/登录
|
||||
- 创建时返回 `admin_token`(随机 64 位字符串),持有者可删除脚本
|
||||
- 无内容过滤,靠过期机制和限流控制风险
|
||||
- 编辑功能:无(`admin_token` 仅用于删除,不能改内容。设计上 script 是一次性的,编辑会带来版本管理等复杂问题)
|
||||
|
||||
## 前端路由
|
||||
|
||||
| 路由 | 页面 | 说明 |
|
||||
|------|------|------|
|
||||
| `/` | 首页 | 粘贴脚本 + 选择运行环境/过期时间 + 提交 + 结果展示 |
|
||||
| `/s/[id]` | 脚本详情页 | 展示脚本内容(语法高亮)、元数据、curl 命令卡片 |
|
||||
| `/s/[id]/delete` | 删除确认页 | 输入 admin_token 确认删除 |
|
||||
|
||||
## 项目目录结构
|
||||
|
||||
```
|
||||
scriptforge/
|
||||
├── frontend/ # Next.js 项目
|
||||
│ ├── src/
|
||||
│ │ ├── app/
|
||||
│ │ │ ├── page.tsx # 首页
|
||||
│ │ │ ├── layout.tsx # 根布局
|
||||
│ │ │ └── s/[id]/
|
||||
│ │ │ ├── page.tsx # 脚本详情页
|
||||
│ │ │ └── delete/
|
||||
│ │ │ └── page.tsx # 删除确认页
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── ScriptForm.tsx # 脚本提交表单
|
||||
│ │ │ ├── ResultCard.tsx # 结果展示卡(含复制按钮)
|
||||
│ │ │ ├── ScriptViewer.tsx # 脚本内容展示(语法高亮)
|
||||
│ │ │ └── CommandCard.tsx # curl 命令展示卡
|
||||
│ │ └── lib/
|
||||
│ │ └── api.ts # API 调用封装
|
||||
│ ├── package.json
|
||||
│ └── next.config.js
|
||||
├── backend/ # Go 项目
|
||||
│ ├── cmd/
|
||||
│ │ └── server/
|
||||
│ │ └── main.go # 入口
|
||||
│ ├── internal/
|
||||
│ │ ├── handler/
|
||||
│ │ │ ├── script.go # 脚本 CRUD handlers
|
||||
│ │ │ └── raw.go # 原始内容 handler
|
||||
│ │ ├── model/
|
||||
│ │ │ └── script.go # GORM model
|
||||
│ │ ├── service/
|
||||
│ │ │ └── script.go # 业务逻辑
|
||||
│ │ ├── middleware/
|
||||
│ │ │ └── ratelimit.go # 限流中间件
|
||||
│ │ └── config/
|
||||
│ │ └── runtime.go # 运行时配置列表
|
||||
│ ├── go.mod
|
||||
│ └── go.sum
|
||||
├── .gitea/
|
||||
│ └── workflows/
|
||||
│ └── deploy.yml # Gitea Actions 部署流程
|
||||
├── Makefile # 统一构建命令
|
||||
├── DESIGN.md # 本设计文档
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## CI/CD 部署流程(Gitea Actions)
|
||||
|
||||
1. 触发条件:push 到 `main` 分支
|
||||
2. 构建步骤:
|
||||
- `cd frontend && npm ci && npm run build` → 输出 `out/`
|
||||
- `cd backend && cp -r ../frontend/out ./internal/embed && go build -o server ./cmd/server`
|
||||
3. 部署步骤:
|
||||
- `scp` 二进制到服务器
|
||||
- `ssh` 执行 `systemctl restart scriptforge`
|
||||
|
||||
## 后续可扩展方向
|
||||
|
||||
- 大模型集成:根据脚本内容自动推荐运行环境
|
||||
- 更多运行时:dockerfile、powershell、deno、bun 等
|
||||
- 脚本版本管理(不基于 admin_token,需要真正的用户系统)
|
||||
- 统计数据:脚本执行次数、来源 IP 等(需要跟踪 curl 请求)
|
||||
- WebSocket 实时执行输出流
|
||||
Reference in New Issue
Block a user