[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81543":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":16,"stars90d":14,"forks30d":14,"starsTrendScore":17,"compositeScore":18,"rankGlobal":8,"rankLanguage":8,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":20,"hasPages":20,"topics":22,"createdAt":8,"pushedAt":8,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":14,"starSnapshotCount":14,"syncStatus":15,"lastSyncTime":26,"discoverSource":27},81543,"ovh","gokele\u002Fovh","gokele",null,"TypeScript",29,18,26,1,0,2,4,6,47.24,"GNU Affero General Public License v3.0",false,"main",[],"2026-06-12 04:01:34","# OVH 控制台\n\nOVH 独立服务器 \u002F VPS \u002F Eco 系列**抢购 + 监控 + 管理**控制台。\n\n实时检测 OVH 各数据中心库存,发现可购买的服务器时按用户配置(机房、内存、存储、带宽、vRack)自动下单。后台同时管理已购买服务器的全生命周期(重启 \u002F 重装 \u002F IPMI \u002F BIOS \u002F 启动模式 \u002F 维护工单 \u002F 联系人变更 \u002F 带宽 \u002F 防火墙 \u002F FTP 备份 \u002F vRack \u002F Secondary DNS 等)。支持**多 OVH 账户**同时管理,抢购 \u002F 监控按账户隔离。\n\n> 本项目灵感来自 [coolci\u002FOVH-BUY](https:\u002F\u002Fgithub.com\u002Fcoolci\u002FOVH-BUY)。\n> 技术栈与架构全部重新设计:Go (Gin) + SQLite 后端、Vite\u002FReact + TanStack + shadcn-ui 前端、`\u002F\u002Fgo:embed` 单二进制部署(自带 SQLite, 跨平台无依赖)、强制 OvhCredsGate、多账户支持、双 SQLite driver(`modernc.org\u002Fsqlite` 纯 Go \u002F `mattn\u002Fgo-sqlite3` cgo, build tag 自动选)、自动检测 GitHub Releases 更新等。\n\n## 技术栈\n\n| 层 | 技术 |\n|---|---|\n| 前端 | Vite 5 + React 18 + TypeScript + TanStack Router + TanStack Query + shadcn-ui + Tailwind + recharts |\n| 后端 | Go 1.21+ + Gin + 官方 [go-ovh](https:\u002F\u002Fgithub.com\u002Fovh\u002Fgo-ovh) SDK |\n| 持久化 | SQLite(`modernc.org\u002Fsqlite` 纯 Go \u002F `mattn\u002Fgo-sqlite3` cgo 双 driver, build tag 自动选) |\n| 通知 | Telegram Bot Webhook |\n| 部署 | 单二进制(前端 \u002F\u002Fgo:embed 进 Go 二进制) 或前后端分开跑 |\n\n## 项目结构\n\n```\n.\n├── server\u002F   # Go 后端 (Gin, 默认 :19998)\n│   ├── main.go\n│   ├── webembed_ui.go    # build tag=ui 时把 web\u002F 整目录 embed 进二进制\n│   ├── webembed_noui.go  # 默认 build,无前端\n│   └── internal\u002F\n│       ├── app\u002F          # State 聚合\n│       ├── db\u002F           # SQLite 层 (schema.sql + 各表 CRUD)\n│       ├── handlers\u002F     # Gin handler\n│       ├── monitor\u002F      # 服务器补货监控\n│       ├── vps\u002F          # VPS 补货监控\n│       ├── purchase\u002F     # 下单流程\n│       ├── price\u002F        # OVH cart 询价\n│       ├── ovh\u002F          # 按 account_id 路由的多账户 client 工厂\n│       └── ...\n└── web\u002F      # 前端 (Vite + TanStack, dev 默认 :19997)\n    └── src\u002F\n        ├── routes\u002F       # 文件路由\n        ├── components\u002F   # 共享组件 + AuthGate \u002F OvhCredsGate\n        ├── hooks\u002F        # TanStack Query hooks\n        └── lib\u002F          # 子公司表 \u002F OVH 数据中心常量 \u002F utils\n```\n\n后端详细文档见 [server\u002FREADME.md](server\u002FREADME.md)。\n\n## 部署方式\n\n### 方式 A:单二进制(推荐生产)\n\n前端 build → Vite 输出到 `server\u002Fweb\u002F` → Go `-tags ui` 触发 `\u002F\u002Fgo:embed` 把整目录嵌入二进制 → 单文件部署、双击即用。\n\n```powershell\n# Windows PowerShell\ncd web\nnpm install\nnpm run build\n\ncd ..\\server\ngo build -tags ui -trimpath -ldflags \"-s -w\" -o ovh-server.exe\n.\\ovh-server.exe\n```\n\nLinux 一样,把 `.exe` 去掉。**不需要外部 SQLite 库,二进制自带。** 默认监听 `:19998`,浏览器打开 `http:\u002F\u002Flocalhost:19998` 即用,数据库自动建在 `.\u002Fdata\u002Fsniper.db`。\n\n### 方式 B:开发(前后端分开跑)\n\n```bash\n# 后端\ncd server\ngo run .                # 默认 :19998\n\n# 前端(另一个终端)\ncd web\nnpm install\nnpm run dev             # 默认 :19997, \u002Fapi\u002F* 自动反代到 19998\n```\n\n浏览器打开 `http:\u002F\u002Flocalhost:19997`。\n\n\n## 首次访问\n\n打开浏览器后会依次出现两层全屏遮罩,都过了才能进主界面:\n\n1. **AuthGate**:输入 `.env` 里设置的 `API_SECRET_KEY`(没设的话用默认值,见下)\n2. **OvhCredsGate**:无任何 OVH 账户时强制弹出。填**账户名称** + OVH 子公司(Zone) + `APP KEY \u002F APP SECRET \u002F CONSUMER KEY`,`Endpoint` \u002F `IAM` 自动派生。后端 `POST \u002Fapi\u002Faccounts` 落 `ovh_accounts` 表并真去 OVH 验一次,通过才放行。\n\n凭据通过后,前端立刻在后台 prefetch 三件套(服务器目录 \u002F catalog \u002F 可用性),用户切到服务器列表页**直接出数据,不会再走\"加载中\"**。\n\n后续可在\"设置 → OVH 账户\"加更多账户。每个账户独立的 endpoint \u002F 凭据 \u002F Zone,**抢购队列、监控订阅、自动下单全部按账户隔离**。服务器控制 tab 顶部有账户切换器,可在已登录账户之间切换查看。\n\n## 配置\n\n`server\u002F.env.example` → 复制成 `server\u002F.env` 改:\n\n```bash\nAPI_SECRET_KEY=...               # 前端访问后端的密钥, 必须改\nPORT=19998                       # 后端监听端口\nLISTEN_HOST=                     # 空 = 所有网卡(IPv4+IPv6); 127.0.0.1 锁回环; 0.0.0.0 公网\nENABLE_API_KEY_AUTH=true         # 关掉的话所有 \u002Fapi\u002F* 不验证密钥, 仅本地调试用\nGIN_MODE=release                 # debug | release\nDEBUG=false                      # true 时启用 debug 日志\n```\n\nOVH 凭据**不放 env**,通过前端 OvhCredsGate \u002F 设置页\"OVH 账户\" tab 录入,落 SQLite `ovh_accounts` 表(每个账户一行,独立 endpoint \u002F AppKey \u002F Secret \u002F ConsumerKey \u002F Zone)。`.gitignore` 默认拒绝所有 `.env` 入库。\n\n## 主要功能\n\n### 多账户\n- **账户管理**:设置页\"OVH 账户\" tab 增删改查,每条记录有独立**名称 + Zone + endpoint + AppKey\u002FSecret\u002FConsumerKey**\n- **账户隔离**:抢购队列、抢购历史、监控订阅都标 `account_id`,后端 goroutine 按 account_id 取对应 OVH client 下单\n- **级联清理**:删账户时关联 history \u002F queue 自动删除,监控订阅的\"自动下单账户\"字段清空(订阅本身保留,只通知不下单)\n- **默认账户**:其中一个标 `is_default`,新建对话框不选时自动用默认账户\n- **凭据校验**:新建 \u002F 更新账户都会真去 OVH 调一次 `\u002Fme`,失败不入库\n\n### 抢购\n- **服务器列表**:卡片网格 + 实时 DC 库存灯(绿可用 \u002F 红缺货),点击直接选配置下单\n- **配置选择器**:按 OVH `addonFamilies`(CPU \u002F 内存 \u002F 系统盘 \u002F 数据盘 \u002F 带宽 \u002F vRack)分组单选,默认值预选\n- **抢购队列**:每台服务器 × 每个 DC × 数量 独立任务,**每个任务绑定到一个 OVH 账户**,可暂停 \u002F 恢复 \u002F 删除,按 retry interval 轮询 OVH 库存\n- **fail-fast**:用户选的配置匹配不上 OVH 当前可订购的 addon → 整单失败,绝不退化到默认 HDD\n- **价格预览**:18 个 OVH subsidiary 切换比价(EUR \u002F USD \u002F CAD \u002F GBP \u002F SGD \u002F AUD \u002F INR \u002F PLN ...),前端用本地 catalog 算,不走 cart 流程\n\n### 监控\n- **服务器补货**:订阅 planCode + DC 组合,状态变化推 Telegram。**自动下单可选指定账户**;不选只通知不下单\n- **VPS 补货**:同上,针对 OVH VPS 产品线(区分 Linux \u002F Windows 镜像)\n- **历史时间线**:每个订阅完整变化记录\n\n### 已购服务器管理\n- **顶部账户切换器**:服务器控制 tab 头单独有账户下拉,切换后所有 `\u002Fserver-control\u002F*` 请求由 axios 拦截器自动追加 `?account=\u003Cid>`,无需逐 hook 改造\n- **概览**:硬件信息 + 服务到期 + IP \u002F 网卡 + MRTG 流量图\n- **电源 \u002F 系统**:重启 \u002F 重装(含 ZFS \u002F 软 RAID \u002F 自定义分区)\u002F IPMI 控制台 \u002F 启动模式 \u002F SPLA Windows 解锁 \u002F 任务列表 \u002F BIOS \u002F 安装进度。重装接口加了 per-service `TryLock`,防双击重复提交\n- **维护**:维护记录 + 硬件更换工单(硬盘 \u002F 内存 \u002F 散热)+ 联系人变更(Token 邮件确认)\n- **高级**(9 个 sub-tab):Burst \u002F 防火墙 \u002F Backup FTP \u002F Secondary DNS \u002F 虚拟 MAC \u002F vRack \u002F 可订购升级 \u002F 附加选项 \u002F IP 规格\n- **隐私模式**:一键打码所有 IP \u002F MAC \u002F 反向 DNS 主机名\n\n### 其它\n- **账户管理**:余额 \u002F 退款记录 \u002F 邮件历史(按当前账户切换)\n- **抢购历史**:订单 + 价格 + 倒计时 + OVH 订单链接直跳,每行带账户标识 chip\n- **详细日志**:实时刷新,按级别 \u002F 关键字筛选\n- **自动检测更新**:仪表盘 mount 时调一次 `GET \u002Fapi\u002Fversion\u002Fcheck-update` 拉 GitHub releases 比版本号,有新版在版本号旁显示 ✨ chip 跳 release 页;后端纯被动响应,无 goroutine \u002F 无定时\n\n## 持久化\n\n全部业务数据在 SQLite(`data\u002Fsniper.db`),8 张表:\n\n| 表 | 用途 |\n|---|---|\n| `kv` | 单例配置(TG token \u002F VPS 检查间隔等非账户级配置) |\n| `ovh_accounts` | OVH 账户(独立 endpoint \u002F AppKey \u002F Secret \u002F ConsumerKey \u002F Zone \u002F is_default) |\n| `queue` | 抢购队列(`account_id` 关联) |\n| `history` | 抢购历史(`account_id` 关联) |\n| `servers` | OVH 服务器目录缓存(刷新一次写一次,2h TTL) |\n| `catalogs` | OVH 公共 catalog 每个 subsidiary 一份(2h TTL),浏览页价格走它 |\n| `monitor_subscriptions` | 服务器补货订阅(`auto_order_account_id` 关联) |\n| `vps_subscriptions` | VPS 补货订阅(同上) |\n\n日志仍走 JSON 文件(`data\u002Flogs\u002Fapp.log.json`),不进 SQLite。\n\n## 缓存策略\n\n| 数据 | 后端 TTL | 前端 staleTime | 后台轮询 | 触发刷新 |\n|---|---|---|---|---|\n| 服务器目录 | 2h(SQLite + 内存 ServerCache) | 2h | ❌ 完全访问触发 | 缓存过期时下一次访问 \u002F 手动刷新按钮 |\n| OVH catalog(价格) | 2h(SQLite `catalogs` 表) | 2h | ❌ | 同上 |\n| 实时可用性 | — | 1 分钟 | ❌(原每 60 秒轮询已关) | 同上 |\n\n启动时不主动调 OVH,只把 SQLite 现有数据加载到内存。`ServerCache` 用 SQLite 真实 `updated_at` 重建时间戳,旧数据不会被当成\"刚刷过的\"。\n\n## 安全 \u002F 鉴权\n\n- 后端所有 `\u002Fapi\u002F*`(除少数白名单如 `\u002Fhealth` \u002F `\u002Ftelegram\u002Fwebhook` \u002F `\u002Fversion` \u002F `\u002Fversion\u002Fcheck-update`)都要求 `X-API-Key` 请求头\n- 两层全屏 gate:AuthGate(API 密钥) + OvhCredsGate(至少一个 OVH 账户)\n- API Key 存浏览器 localStorage,失效自动清除并要求重新输入\n- OVH 凭据落 SQLite `ovh_accounts` 表,前端通过 OvhCredsGate \u002F 设置页\"OVH 账户\" tab 录入\n- `.gitignore` 默认拒绝所有 `.env` 文件入库(只允许 `*.env.example`)\n\n## OVH API 对接\n\n下单流程严格对齐 OVH 官方 [order-cart-examples](https:\u002F\u002Fgithub.com\u002Fovh\u002Forder-cart-examples):\n\n```\nPOST \u002Forder\u002Fcart                         → cartId\nPOST \u002Forder\u002Fcart\u002F{id}\u002Fassign\nPOST \u002Forder\u002Fcart\u002F{id}\u002Feco                → itemId\nPOST \u002Forder\u002Fcart\u002F{id}\u002Fitem\u002F{itemId}\u002Fconfiguration × 3  (datacenter \u002F os \u002F region)\nPOST \u002Forder\u002Fcart\u002F{id}\u002Feco\u002Foptions × N\nGET  \u002Forder\u002Fcart\u002F{id}\u002Fsummary\nPOST \u002Forder\u002Fcart\u002F{id}\u002Fcheckout\n```\n\n价格计算 = 基础 plan 月费 + 各 addon family 选中 addon 月费累加(`ovhjk\u002Fparser\u002Fprice.go` 1:1 移植到前端 `web\u002Fsrc\u002Fhooks\u002Fuse-availability.ts`)。\n\n## 端口\n\n| 服务 | 端口 |\n|---|---|\n| Go 后端(生产单二进制 \u002F 开发) | **19998** |\n| Vite dev server(仅开发) | 19997 |\n| OVH Telegram webhook 入口 | `\u002Fapi\u002Ftelegram\u002Fwebhook`(无需鉴权,IP 白名单) |\n","该项目是一个用于OVH独立服务器、VPS和Eco系列的抢购、监控及管理控制台。其核心功能包括实时检测库存并在发现可购买资源时按用户配置自动下单，以及全面管理已购服务器的各项设置如重启、重装系统等。技术上采用Go (Gin) + SQLite构建后端，Vite\u002FReact + TanStack + shadcn-ui搭建前端，并支持单二进制跨平台部署。适合需要自动化获取并维护OVH云服务资源的企业或个人开发者使用。","2026-06-11 04:05:26","CREATED_QUERY"]