feat: 联盟返佣系统规范化并打通技能广场(无 ICP 证合规变现主路径)

- 新增 AffiliateProgram / AffiliateLink / AffiliateClick 规范化 Prisma 模型
  取代原手写裸表 affiliate_stats / affiliate_clicks
- 新增迁移 prisma/migrations/20260711000000_add_affiliate_models
- 重构 affiliate.service.ts 改用 Prisma ORM,消除 $queryRawUnsafe SQL 注入
- 重构 affiliate.controller.ts 接口:programs / links(?skillId,?toolId) / stats / click
- 前端 affiliate 页接入真实接口,移除硬编码 demo 数据
- 技能详情页新增「学此技能推荐使用的工具」联盟链接区块
- 新增 affiliate.service.spec.ts(4 用例通过)与幂等种子 seed-affiliate.ts
- 更新 docs/progress/current.md,明确无 ICP 经营许可证下以联盟返佣为合规变现主路径
- 含此前工作区未提交改动(工具 slug 路由、支付/订单、SEO 等)

Co-Authored-By: opencode <opencode@anthropic.com>
This commit is contained in:
TradeMate Dev
2026-07-11 14:47:41 +08:00
parent 05bf267d09
commit 31cc1e02ce
46 changed files with 3565 additions and 1201 deletions
+70
View File
@@ -0,0 +1,70 @@
import 'dotenv/config';
import { PrismaClient, ContentStatus } from '@prisma/client';
const prisma = new PrismaClient();
interface LinkInfo {
url: string;
title: string;
description?: string;
}
const links: LinkInfo[] = [
{ url: 'https://www.aliyun.com/minisite/goods?userCode=kap6n5tc', title: '云小站_专享特惠_云产品推荐-阿里云' },
{ url: 'https://www.aliyun.com/benefit/client/cross?userCode=kap6n5tc', title: '云聚 AI 长效权益' },
{ url: 'https://www.aliyun.com/activity/hub/ai-innovation?userCode=kap6n5tc', title: 'AI 加速季,智惠生产力' },
{ url: 'https://opc.aliyun.com/products?utm_content=g_1000413977&userCode=kap6n5tc', title: 'OPCOne Person Company一人公司)创业装备库' },
{ url: 'https://www.aliyun.com/activity/ecs/clawdbot?userCode=kap6n5tc', title: '稳定不贵,不写代码,分钟级部署Hermes/OpenClaw' },
{ url: 'https://dashi.aliyun.com/activity/aigc?userCode=kap6n5tc', title: '一键轻松打造你的专属AI应用' },
{ url: 'https://dashi.aliyun.com/activity/aiagent?userCode=kap6n5tc', title: '一站式轻松搭建企业级 AI Agent' },
{ url: 'https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=kap6n5tc', title: '开年焕新,限时特惠' },
{ url: 'https://wanwang.aliyun.com/website/index?userCode=kap6n5tc', title: '阿里云建站_AI建站_设计师定制建站_系统定制开发-阿里云' },
{ url: 'https://www.aliyun.com/daily-act/ecs/ecs25srdeepseek?userCode=kap6n5tc', title: 'DeepSeek 个人站点-快速部署方案' },
{ url: 'https://www.aliyun.com/activity?userCode=kap6n5tc', title: '活动中心' },
{ url: 'https://dashi.aliyun.com/activity/oss?userCode=kap6n5tc', title: '阿里云存储产品云大使征集令' },
];
function slugFromUrl(urlStr: string): string {
try {
const url = new URL(urlStr);
let path = url.pathname.replace(/^\/|\/$/g, '').replace(/\//g, '-');
if (!path) path = 'home';
return `aliyun-${path}`;
} catch {
return `aliyun-${Math.random().toString(36).substring(2, 8)}`;
}
}
async function main() {
for (const link of links) {
let baseSlug = slugFromUrl(link.url);
let slug = baseSlug;
let counter = 1;
while (true) {
const existing = await prisma.tool.findUnique({ where: { slug } });
if (!existing) break;
slug = `${baseSlug}-${counter++}`;
}
await prisma.tool.create({
data: {
name: link.title,
slug,
url: link.url,
description: '',
status: ContentStatus.PUBLISHED,
tags: '阿里云,云大使',
isFeatured: true,
},
});
console.log(`✅ Created tool: ${slug} -> ${link.title}`);
}
}
main()
.catch((e) => {
console.error('❌ Seed failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});