chore: 清理敏感与开发文档,仅同步代码

- 永久忽略并从仓库移除 开发文档/
- 移除并忽略 .env 与小程序私有配置
- 同步小程序/管理端/API与脚本改动

Made-with: Cursor
This commit is contained in:
卡若
2026-03-17 17:50:12 +08:00
parent 868b0a10d9
commit 76965adb23
443 changed files with 24175 additions and 64154 deletions

View File

@@ -0,0 +1,62 @@
# 文章 base64 图片迁移脚本
`chapters` 表中 `content` 字段内嵌的 base64 图片提取为独立文件,并替换为 `/uploads/book-images/xxx` 的 URL减小文章体积。
## 适用场景
- 历史文章中有大量粘贴的 base64 图片
- 保存时因 content 过大导致超时或失败
- 需要将 base64 转为文件存储
## 执行方式
### 1. 测试环境(建议先执行)
```bash
cd soul-api
# 加载测试环境配置(.env.development
$env:APP_ENV="development"
# 先 dry-run 预览,不写入
go run ./cmd/migrate-base64-images --dry-run
# 确认无误后正式执行
go run ./cmd/migrate-base64-images
```
### 2. 生产环境
```bash
cd soul-api
$env:APP_ENV="production"
go run ./cmd/migrate-base64-images --dry-run # 先预览
go run ./cmd/migrate-base64-images # 正式执行
```
### 3. 指定 DSN覆盖 .env
```bash
$env:DB_DSN="user:pass@tcp(host:port)/db?charset=utf8mb4&parseTime=True"
go run ./cmd/migrate-base64-images --dry-run
```
## 参数
| 参数 | 说明 |
|------|------|
| `--dry-run` | 仅统计和预览,不写入文件与数据库 |
## 行为说明
1. 查询 `content LIKE '%data:image%'` 的章节
2. 用正则提取 `src="data:image/xxx;base64,..."``src='...'`
3. 解码 base64保存到 `uploads/book-images/{timestamp}_{random}.{ext}`
4. 将 content 中的 base64 src 替换为 `/uploads/book-images/xxx`
5. 更新数据库
## 注意事项
- **务必先在测试环境验证**,确认无误后再跑生产
- 脚本依赖 `UPLOAD_DIR` 或默认 `uploads` 目录
- 图片格式支持png、jpeg、jpg、gif、webp

View File

@@ -0,0 +1,96 @@
# 数据库与 Go Model 字段对照检查报告
> 后端工程师对照 `soul-api/internal/model` 与 `soul_miniprogram.sql` 建表结构,列出**数据库表里可能缺失、但代码里在用**的字段。
> 若当前库是由旧版 SQL 导入或从未执行过迁移脚本,按本报告执行 `sync-users-vip-and-schema.sql` 或依赖 AutoMigrate 即可补全。
---
## 一、结论摘要
| 表名 | 是否缺字段 | 缺失字段Model 有、SQL 无) | 影响 |
|------|------------|-----------------------------|------|
| **users** | 是(旧库可能缺) | is_vip, vip_expire_date, vip_activated_at, vip_sort, vip_role | 订单列表、用户列表、VIP 设置、提现、匹配记录等接口报错(不含 vip_name/vip_avatar 等,小程序已改为直接读用户资料) |
| **chapters** | 是SQL 导出无此列) | hot_score | 文章排名、热门章节等依赖热度分的接口报错 |
| 其他业务表 | 否 | - | 与当前 SQL 一致 |
---
## 二、users 表
- **Model 文件**`internal/model/user.go`
- **SQL 表**`soul_miniprogram.sql``CREATE TABLE users` 已包含 VIP 相关列;若你的库是**更早的备份**或**未导入最新 SQL**,可能缺少以下列。
| 列名(蛇形) | 类型 | 说明 |
|-------------|------|------|
| is_vip | TINYINT(1) NULL DEFAULT 0 | 是否 VIP |
| vip_expire_date | DATETIME(3) NULL | VIP 到期时间 |
| vip_activated_at | DATETIME(3) NULL | 成为 VIP 时间,排序用 |
| vip_sort | INT NULL | 手动排序,越小越前 |
| vip_role | VARCHAR(50) NULL | 角色:从 vip_roles 选或手动填写 |
vip_name、vip_avatar、vip_project、vip_contact、vip_bio 不再在迁移中新增,小程序已改为直接读用户资料 nickname/avatar/projectIntro/phone 等;已有库可保留该五列作兼容。)
**修复**:执行 `scripts/sync-users-vip-and-schema.sql` 中 users 部分,或重启 soul-api未设 `SKIP_AUTO_MIGRATE` 时 AutoMigrate 会补列)。
---
## 三、chapters 表
- **Model 文件**`internal/model/chapter.go`
- **SQL 表**:当前 `soul_miniprogram.sql``chapters` 仅有 `hot_score_override`decimal**没有** `hot_score`int
Model 使用的是 `hot_score`(热度分,用于排名算法),因此仅按该 SQL 建表时,数据库**缺少** `hot_score`
| 列名(蛇形) | 类型 | 说明 |
|-------------|------|------|
| hot_score | INT NOT NULL DEFAULT 0 | 热度分,用于排名算法 |
**修复**:执行 `scripts/sync-users-vip-and-schema.sql` 中 chapters 部分,或执行 `scripts/add-hot-score.sql`,或依赖 soul-api 启动时对 Chapter 的 AutoMigrate。
---
## 四、已核对无缺列的表
以下表在 `soul_miniprogram.sql` 中的列与对应 Model 一致,**无需补列**(仅列名与类型一致即可,顺序可不同):
- **orders**:与 `model.Order` 一致
- **withdrawals**:与 `model.Withdrawal` 一致(库中多出的 transaction_id、error_message 不影响)
- **admin_users**:与 `model.AdminUser` 一致
- **system_config**:与 `model.SystemConfig` 一致
- **referral_bindings**Model 字段在表中均存在
- **referral_visits**:与 `model.ReferralVisit` 一致
- **user_rules**:与 `model.UserRule` 一致
- **user_tracks**:与 `model.UserTrack` 一致
- **reading_progress**:与 `model.ReadingProgress` 一致(表为 section_idModel 为 section_id
- **match_records**:与 `model.MatchRecord` 一致
- **mentor_consultations**:与 `model.MentorConsultation` 一致
- **mentors**:与 `model.Mentor` 一致
- **link_tags**:与 `model.LinkTag` 一致
- **persons**:与 `model.Person` 一致
- **author_config**:与 `model.AuthorConfig` 一致
- **ckb_lead_records**:与 `model.CkbLeadRecord` 一致
- **ckb_submit_records**:与 `model.CkbSubmitRecord` 一致
- **user_addresses**:与 `model.UserAddress` 一致
- **vip_roles**:与 `model.VipRole` 一致
- **wechat_callback_logs**:与 `model.WechatCallbackLog` 一致
---
## 五、推荐操作
1. **一次性补全(推荐)**
在备份后执行:
```bash
mysql -u 用户 -p 数据库名 < soul-api/scripts/sync-users-vip-and-schema.sql
```
若某条报 `Duplicate column name`,表示该列已存在,可跳过。
2. **依赖 AutoMigrate**
确保 soul-api 的 `database.Init` 中已对 `User`、`SystemConfig`、`Chapter` 执行 `AutoMigrate`,且未设置 `SKIP_AUTO_MIGRATE`,重启服务后会自动补全缺失列。
3. **新建库**
若从零建库,建议用**最新**的 `soul_miniprogram.sql` 导入后,再执行一次 `sync-users-vip-and-schema.sql`,确保 users 与 chapters 与 Model 完全一致。
---
**检查日期**:按代码与 SQL 导出时点生成
**检查范围**soul-api 全部 `internal/model` 与 soul_miniprogram.sql 中对应表结构

View File

@@ -0,0 +1,28 @@
-- 余额相关表(新版迁移)
-- 执行mysql -u user -p database < soul-api/scripts/add-balance-tables.sql
-- user_balances
CREATE TABLE IF NOT EXISTS user_balances (
user_id VARCHAR(50) PRIMARY KEY,
balance DECIMAL(10,2) DEFAULT 0,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- balance_transactions
CREATE TABLE IF NOT EXISTS balance_transactions (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
type VARCHAR(20) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
order_id VARCHAR(50) DEFAULT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- orders 增加 payment_method
SET @col_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE table_schema = DATABASE() AND table_name = 'orders' AND column_name = 'payment_method');
SET @sql = IF(@col_exists = 0, 'ALTER TABLE orders ADD COLUMN payment_method VARCHAR(20) DEFAULT NULL AFTER referrer_id', 'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,5 @@
-- 为 all-chapters 接口加速sort_order + id 排序索引
-- 执行node .cursor/scripts/db-exec/run.js -f soul-api/scripts/add-chapters-index-for-all-chapters.sql
-- 若索引已存在会报错,可忽略
CREATE INDEX idx_chapters_sort_id ON chapters(sort_order, id);

View File

@@ -0,0 +1,4 @@
-- 为 chapters 表添加 preview_percent 列章节级预览比例NULL 表示使用全局 unpaid_preview_percent
-- 执行: mysql -u user -p db < soul-api/scripts/add-chapters-preview-percent.sql
ALTER TABLE chapters ADD COLUMN IF NOT EXISTS preview_percent INT NULL COMMENT '章节级预览比例(%)NULL 表示使用全局设置' AFTER hot_score;

View File

@@ -0,0 +1,2 @@
-- 仅添加 ckb_plan_id若 add-persons-ckb-fields.sql 已部分执行或需单独补列)
ALTER TABLE `persons` ADD COLUMN `ckb_plan_id` BIGINT NOT NULL DEFAULT 0 COMMENT '存客宝获客计划ID';

View File

@@ -0,0 +1,25 @@
-- 代付请求表 + 订单表代付字段
-- 执行mysql -u user -p db < soul-api/scripts/add-gift-pay-requests.sql
-- 注orders 表新增字段由 GORM AutoMigrate 自动添加;若需手动执行:
-- ALTER TABLE orders ADD COLUMN gift_pay_request_id VARCHAR(50) DEFAULT NULL;
-- ALTER TABLE orders ADD COLUMN payer_user_id VARCHAR(50) DEFAULT NULL;
CREATE TABLE IF NOT EXISTS gift_pay_requests (
id VARCHAR(50) PRIMARY KEY,
request_sn VARCHAR(32) NOT NULL UNIQUE,
initiator_user_id VARCHAR(50) NOT NULL,
product_type VARCHAR(30) NOT NULL,
product_id VARCHAR(50) NOT NULL DEFAULT '',
amount DECIMAL(10,2) NOT NULL,
description VARCHAR(200) NOT NULL DEFAULT '',
status VARCHAR(20) NOT NULL DEFAULT 'pending',
payer_user_id VARCHAR(50) DEFAULT NULL,
order_id VARCHAR(50) DEFAULT NULL,
expire_at DATETIME NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_initiator (initiator_user_id),
INDEX idx_payer (payer_user_id),
INDEX idx_status (status),
INDEX idx_request_sn (request_sn)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -0,0 +1,2 @@
-- 为 chapters 表新增 hot_score 字段(热度分,用于排名算法)
ALTER TABLE chapters ADD COLUMN hot_score INT NOT NULL DEFAULT 0;

View File

@@ -0,0 +1,6 @@
-- persons 表新增 ckb_api_key 字段
-- 作用:存储该 @人物 在存客宝的接入密钥,点击加好友时用该 Key 推线索;留空则 fallback 全局 CKB_LEAD_API_KEY
-- 执行mysql -u user -p db < soul-api/scripts/add-persons-ckb-api-key.sql
ALTER TABLE persons
ADD COLUMN ckb_api_key VARCHAR(100) NOT NULL DEFAULT '' AFTER label;

View File

@@ -0,0 +1,12 @@
-- 为 persons 表增加存客宝 API 获客相关字段,便于管理端回显与二次编辑
ALTER TABLE `persons`
ADD COLUMN `greeting` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '存客宝打招呼语' AFTER `ckb_api_key`,
ADD COLUMN `tips` TEXT NULL COMMENT '获客成功提示' AFTER `greeting`,
ADD COLUMN `remark_type` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '备注类型phone/nickname/source' AFTER `tips`,
ADD COLUMN `remark_format` VARCHAR(200) NOT NULL DEFAULT '' COMMENT '备注格式' AFTER `remark_type`,
ADD COLUMN `add_friend_interval` INT NOT NULL DEFAULT 1 COMMENT '添加好友间隔(分钟)' AFTER `remark_format`,
ADD COLUMN `start_time` VARCHAR(10) NOT NULL DEFAULT '09:00' COMMENT '允许加人开始时间 HH:MM' AFTER `add_friend_interval`,
ADD COLUMN `end_time` VARCHAR(10) NOT NULL DEFAULT '18:00' COMMENT '允许加人结束时间 HH:MM' AFTER `start_time`,
ADD COLUMN `device_groups` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '参与计划的设备ID列表逗号分隔' AFTER `end_time`,
ADD COLUMN `ckb_plan_id` BIGINT NOT NULL DEFAULT 0 COMMENT '存客宝获客计划ID' AFTER `device_groups`;

View File

@@ -0,0 +1,23 @@
-- persons、link_tags 表,供 ContentPage @提及人物与链接标签配置
-- 执行mysql -u user -p db < soul-api/scripts/add-persons-link-tags.sql
CREATE TABLE IF NOT EXISTS persons (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
person_id VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL DEFAULT '',
label VARCHAR(200) NOT NULL DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS link_tags (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tag_id VARCHAR(50) NOT NULL UNIQUE,
label VARCHAR(200) NOT NULL DEFAULT '',
url VARCHAR(500) NOT NULL DEFAULT '',
type VARCHAR(20) NOT NULL DEFAULT 'url',
app_id VARCHAR(100) NOT NULL DEFAULT '',
page_path VARCHAR(500) NOT NULL DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -0,0 +1,6 @@
-- persons 表新增 token 字段32 位唯一,@ 时存此值,小程序用此兑换 ckb_api_key
-- 执行cd 项目根目录 && node .cursor/scripts/db-exec/run.js -f soul-api/scripts/add-persons-token.sql
-- 或mysql -u user -p db < soul-api/scripts/add-persons-token.sql
ALTER TABLE persons ADD COLUMN token VARCHAR(36) NOT NULL DEFAULT '' AFTER person_id;
ALTER TABLE persons ADD UNIQUE INDEX idx_persons_token (token);

View File

@@ -0,0 +1,8 @@
-- 规则引擎默认数据:插入「注册」规则,供登录后完善头像引导
-- 执行mysql -u user -p db < soul-api/scripts/add-user-rules-default.sql
-- 幂等:若已存在 trigger='注册' 则跳过
INSERT INTO user_rules (title, description, `trigger`, sort, enabled, created_at, updated_at)
SELECT '完善个人信息', '设置头像和昵称,让其他创业者更容易认识你', '注册', 1, 1, NOW(), NOW()
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM user_rules WHERE `trigger` = '注册' LIMIT 1);

View File

@@ -0,0 +1,9 @@
# 补全 persons.ckb_api_key
若存在 ckb_plan_id 但 ckb_api_key 为空的 Person可手动调用 plan/detail 补全。
**执行前**:确保 soul-api 可连接存客宝CKB_OPEN_API_KEY、CKB_OPEN_ACCOUNT 已配置)。
**方式一**:管理端逐个编辑保存(会触发存客宝同步,若 Person 无 ckb_api_key 需在编辑弹窗填写或重新创建)。
**方式二**:写一次性脚本,遍历 `ckb_plan_id > 0 AND (ckb_api_key IS NULL OR ckb_api_key = '')` 的 Person调 ckbOpenGetPlanDetail 获取 apiKey 并 UPDATE。

View File

@@ -0,0 +1,16 @@
-- ============================================================
-- 同步 users 表与 Go Model仅 VIP 身份/状态字段,不含单独 VIP 资料列)
-- 小程序已改为直接读用户资料nickname/avatar/projectIntro/phone不再单独存 vip_name/vip_avatar 等。
-- 若某条 ALTER 报 Duplicate column name说明该列已存在跳过即可。
-- 也可直接重启 soul-api未设 SKIP_AUTO_MIGRATE 时会自动补列)。
-- ============================================================
-- users 表VIP 身份与状态(与 internal/model/user.go 一致)
ALTER TABLE users ADD COLUMN is_vip TINYINT(1) NULL DEFAULT 0 COMMENT '是否 VIP';
ALTER TABLE users ADD COLUMN vip_expire_date DATETIME(3) NULL DEFAULT NULL COMMENT 'VIP 到期时间';
ALTER TABLE users ADD COLUMN vip_activated_at DATETIME(3) NULL DEFAULT NULL COMMENT '成为 VIP 时间,排序用';
ALTER TABLE users ADD COLUMN vip_sort INT NULL DEFAULT NULL COMMENT '手动排序,越小越前';
ALTER TABLE users ADD COLUMN vip_role VARCHAR(50) NULL DEFAULT NULL COMMENT '角色:从 vip_roles 选或手动填写';
-- chapters 表Model 使用 hot_score热度分SQL 导出里只有 hot_score_override缺则排名等接口报错
ALTER TABLE chapters ADD COLUMN hot_score INT NOT NULL DEFAULT 0 COMMENT '热度分,用于排名算法';