refactor(fulfillment): 移除飞飞/乐玩通道,仅保留 affiliate_dash

新单只路由 affiliate_dash(未命中走 manual_dispatch);历史飞飞/乐玩任务保留只读 stub,避免订单重同步失败。同步清理 cloudtentacles 调度、Admin 写路径与相关 env。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-09-14 17:29:47 +08:00
co-authored by Cursor
parent 0cbcb89dd8
commit b3aad0044c
155 changed files with 661 additions and 23351 deletions
@@ -8,10 +8,6 @@ export const APP_CONFIG_KEYS = {
workerAnnouncement: 'worker_announcement',
workerHall: 'worker_hall',
workerMockShops: 'worker_mock_shops',
cloudtentaclesSources: 'cloudtentacles_sources',
cloudtentaclesSession: 'cloudtentacles_session',
cloudtentaclesOverrideRules: 'cloudtentacles_override_rules',
kuaishouFeifei: 'kuaishou_feifei',
kuaishouIndustrySource: 'kuaishou_industry_source',
affiliateDash: 'affiliate_dash',
pddSource: 'pdd_source',
-55
View File
@@ -91,15 +91,6 @@ export function createDefaultRuntimeConfig(projectRoot: string): RuntimeConfig {
shopName: '快手行业电子凭证',
version: '1',
},
kuaishouFeifei: {
enabled: true,
baseUrl: 'http://skin-exchange.yiquyou.icu',
appKey: '',
appSecret: '',
timeoutMs: 10000,
notifyUrl: '',
productRules: [],
},
affiliateDash: {
enabled: true,
baseUrl: '',
@@ -112,52 +103,6 @@ export function createDefaultRuntimeConfig(projectRoot: string): RuntimeConfig {
preferredMatchEnabled: true,
skuMapping: {},
},
cloudtentacles: {
baseUrl: 'https://123.207.217.176',
timeoutMs: 5000,
sendSmsPath: '/public/verif_code',
loginPath: '/public/login',
userInfoPath: '/user/info',
assetPath: '/user/get_asset',
permissionPath: '/user/get_permission',
categoriesPath: '/categories/get',
skuListPath: '/sku/list',
skuBuyPath: '/sku/buy',
skuUsePath: '/sku/use',
knapsackPath: '/user/get_knapsack',
vnListPath: '/vn/list',
vnAppointPath: '/vn/appoint',
vnGenerateLoginCodePath: '/vn/generate_login_code',
vnVerifCodePath: '/public/vn_verif_code',
vnVerifyLoginCodePath: '/vn/verify_login_code',
vnBindUrlPath: '/vn/bind_url',
vnBindInfoPath: '/vn/bind_info',
vnBackPath: '/vn/back',
bindUrlTtlSeconds: 600,
bindUrlProbeIntervalSeconds: 30,
bindUrlProbeTimeoutMs: 5000,
bindUrlProbeUserAgent:
'Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/98.0.4758.102 MQQBrowser/6.2 TBS/046141 Mobile Safari/537.36 V1_AND_SQ_8.8.85_2674_YYB_D QQ/8.8.85.7685 NetType/WIFI WebP/0.3.0 Pixel/1080 StatusBarHeight/108 SimpleUISwitch/0 QQTheme/1000',
bindUrlProbeEndpoint: 'https://comm.ams.game.qq.com/ide/',
bindUrlProbeChartId: '323794',
bindUrlProbeSubChartId: '323794',
bindUrlProbeIdeToken: 'z90Syo',
bindUrlProbeActivityUrl: 'http%3A%2F%2Fgp.qq.com%2Fcp%2Fa20240828cmcc%2F',
bindUrlProbeReferer: 'https://gp.qq.com/',
bindUrlProbeExtraCookie: '',
clientSource: 'ct-client',
deviceId: '08bc9d8c-fd15-48ea-bc00-8d754076cafc',
deviceType: 1,
publicKeyPem: `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsSzjk+9st2f8IpYqYaM5
F7K27ZR2IvzxTr2w4zgZAS2+BRdgMvXUOITdFQT+ytYF/r3pIgTkL7MF9UQuylmb
S57DiqGBLNBS7FzKyYzWTOc9yYA3+KrarbvpUn/Bm3UK+KKB17viPy+0pnNAHysJ
pzqadmAtQhI1ZDujJ2sW+FkV/pC8KIFahiyPIHjncy1ZG/BbRF3BDhvDcr6O7scO
GsHstGf9XsZBIITS5LYmlai7OdY4ZIVxUtQbfWzibihO+YDJJzFgt47drX0Ajo85
PfQTPNA++KsXtwRX9M6Re3vkTDRsutIIWKtj8jqhUbbYS3vzS8GJnAWavUFVkR15
0wIDAQAB
-----END PUBLIC KEY-----`,
},
},
cors: {
+60 -38
View File
@@ -18,7 +18,6 @@ test('applyEnvOverrides maps typed environment values without mutating base conf
ADMIN_DEFAULT_USERS_JSON: '[{"username":"admin","password":"secret","role":"admin"}]',
KAQUAN91_USER_ID: 'kaquan-user',
KAQUAN91_SECRET: 'kaquan-secret',
CLOUDTENTACLES_DEVICE_TYPE: '3',
})
assert.equal(config.server.port, 4000)
@@ -32,7 +31,6 @@ test('applyEnvOverrides maps typed environment values without mutating base conf
])
assert.equal(config.platforms.ninetyone.userId, 'kaquan-user')
assert.equal(config.platforms.ninetyone.secret, 'kaquan-secret')
assert.equal(config.platforms.cloudtentacles.deviceType, 3)
assert.equal(baseConfig.server.port, 3000)
assert.deepEqual(baseConfig.admin.defaultUsers, [])
@@ -97,11 +95,33 @@ function createRuntimeConfig(): RuntimeConfig {
integrationLevel: 'warn',
retentionDays: 30,
},
retention: {
rawPayloadDays: 180,
taskEventDays: 180,
webhookEventDays: 180,
auditLogDays: 365,
},
database: {
url: 'postgres://postgres:postgres@127.0.0.1:5432/order_site',
ssl: false,
maxConnections: 10,
},
storage: {
mode: 'minio',
endpoint: 'http://127.0.0.1:9000',
bucket: 'order-site',
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
region: 'us-east-1',
maxUploadSizeMb: 10,
oss: {
endpoint: '',
bucket: '',
accessKeyId: '',
secretAccessKey: '',
region: 'oss-cn-hangzhou',
},
},
orders: {
claimBaseUrl: 'http://127.0.0.1:5173/#/claim',
tokenTtlHours: 24,
@@ -121,43 +141,45 @@ function createRuntimeConfig(): RuntimeConfig {
timestampToleranceSeconds: 600,
cardsEncoding: 'aes-256-ecb-base64',
},
cloudtentacles: {
baseUrl: 'https://123.207.217.176',
timeoutMs: 5000,
sendSmsPath: '/public/verif_code',
loginPath: '/public/login',
userInfoPath: '/user/info',
assetPath: '/user/get_asset',
permissionPath: '/user/get_permission',
categoriesPath: '/categories/get',
skuListPath: '/sku/list',
skuBuyPath: '/sku/buy',
skuUsePath: '/sku/use',
knapsackPath: '/user/get_knapsack',
vnListPath: '/vn/list',
vnAppointPath: '/vn/appoint',
vnGenerateLoginCodePath: '/vn/generate_login_code',
vnVerifCodePath: '/public/vn_verif_code',
vnVerifyLoginCodePath: '/vn/verify_login_code',
vnBindUrlPath: '/vn/bind_url',
vnBindInfoPath: '/vn/bind_info',
vnBackPath: '/vn/back',
bindUrlTtlSeconds: 600,
bindUrlProbeIntervalSeconds: 30,
bindUrlProbeTimeoutMs: 5000,
bindUrlProbeUserAgent: '',
bindUrlProbeEndpoint: 'https://comm.ams.game.qq.com/ide/',
bindUrlProbeChartId: '323794',
bindUrlProbeSubChartId: '323794',
bindUrlProbeIdeToken: 'z90Syo',
bindUrlProbeActivityUrl: '',
bindUrlProbeReferer: 'https://gp.qq.com/',
bindUrlProbeExtraCookie: '',
publicKeyPem: '',
clientSource: 'ct-client',
deviceId: '08bc9d8c-fd15-48ea-bc00-8d754076cafc',
deviceType: 1,
kuaishouIndustry: {
appKey: '',
appSecret: '',
signSecret: '',
messageSecret: '',
provider: 'kuaishou-industry',
platform: 'kuaishou',
shopId: 'kuaishou-industry',
shopName: '快手行业电子凭证',
version: '1',
},
affiliateDash: {
enabled: true,
baseUrl: '',
appKey: '',
appSecret: '',
callbackSecret: '',
timeoutMs: 10000,
notifyUrl: '',
timestampToleranceSeconds: 300,
preferredMatchEnabled: true,
skuMapping: {},
},
},
worker: {
sms: {
provider: 'mock',
accessKeyId: '',
accessKeySecret: '',
signName: '',
templateCode: '',
codeTtlSeconds: 300,
cooldownSeconds: 60,
dailyLimit: 10,
},
orderTimelineVisible: false,
},
cors: {
allowedOrigins: ['*'],
},
}
}
-112
View File
@@ -3,7 +3,6 @@ import process from 'node:process'
import type {
AdminDefaultUser,
KuaishouFeifeiProductRule,
RuntimeConfig,
} from '../types/runtime-config.js'
import { parseBoolean, parseInteger, parseJsonArray } from './runtime-env.js'
@@ -15,7 +14,6 @@ type RuntimeConfigValue =
| number
| boolean
| AdminDefaultUser[]
| KuaishouFeifeiProductRule[]
| string[]
| Record<string, string>
type RuntimeEnv = Record<string, string | undefined>
@@ -73,96 +71,6 @@ export const ENV_OVERRIDES: readonly EnvOverride[] = [
'timestampToleranceSeconds',
]),
stringEnv('KAQUAN91_CARDS_ENCODING', ['platforms', 'ninetyone', 'cardsEncoding']),
stringEnv('CLOUDTENTACLES_BASE_URL', ['platforms', 'cloudtentacles', 'baseUrl']),
integerEnv('CLOUDTENTACLES_TIMEOUT_MS', ['platforms', 'cloudtentacles', 'timeoutMs']),
stringEnv('CLOUDTENTACLES_SEND_SMS_PATH', ['platforms', 'cloudtentacles', 'sendSmsPath']),
stringEnv('CLOUDTENTACLES_LOGIN_PATH', ['platforms', 'cloudtentacles', 'loginPath']),
stringEnv('CLOUDTENTACLES_USER_INFO_PATH', ['platforms', 'cloudtentacles', 'userInfoPath']),
stringEnv('CLOUDTENTACLES_ASSET_PATH', ['platforms', 'cloudtentacles', 'assetPath']),
stringEnv('CLOUDTENTACLES_PERMISSION_PATH', ['platforms', 'cloudtentacles', 'permissionPath']),
stringEnv('CLOUDTENTACLES_CATEGORIES_PATH', ['platforms', 'cloudtentacles', 'categoriesPath']),
stringEnv('CLOUDTENTACLES_SKU_LIST_PATH', ['platforms', 'cloudtentacles', 'skuListPath']),
stringEnv('CLOUDTENTACLES_SKU_BUY_PATH', ['platforms', 'cloudtentacles', 'skuBuyPath']),
stringEnv('CLOUDTENTACLES_KNAPSACK_PATH', ['platforms', 'cloudtentacles', 'knapsackPath']),
stringEnv('CLOUDTENTACLES_VN_LIST_PATH', ['platforms', 'cloudtentacles', 'vnListPath']),
stringEnv('CLOUDTENTACLES_VN_APPOINT_PATH', ['platforms', 'cloudtentacles', 'vnAppointPath']),
stringEnv('CLOUDTENTACLES_VN_GENERATE_LOGIN_CODE_PATH', [
'platforms',
'cloudtentacles',
'vnGenerateLoginCodePath',
]),
stringEnv('CLOUDTENTACLES_VN_VERIF_CODE_PATH', [
'platforms',
'cloudtentacles',
'vnVerifCodePath',
]),
stringEnv('CLOUDTENTACLES_VN_VERIFY_LOGIN_CODE_PATH', [
'platforms',
'cloudtentacles',
'vnVerifyLoginCodePath',
]),
stringEnv('CLOUDTENTACLES_VN_BIND_URL_PATH', ['platforms', 'cloudtentacles', 'vnBindUrlPath']),
stringEnv('CLOUDTENTACLES_VN_BIND_INFO_PATH', ['platforms', 'cloudtentacles', 'vnBindInfoPath']),
stringEnv('CLOUDTENTACLES_VN_BACK_PATH', ['platforms', 'cloudtentacles', 'vnBackPath']),
integerEnv('CLOUDTENTACLES_BIND_URL_TTL_SECONDS', [
'platforms',
'cloudtentacles',
'bindUrlTtlSeconds',
]),
integerEnv('CLOUDTENTACLES_BIND_URL_PROBE_INTERVAL_SECONDS', [
'platforms',
'cloudtentacles',
'bindUrlProbeIntervalSeconds',
]),
integerEnv('CLOUDTENTACLES_BIND_URL_PROBE_TIMEOUT_MS', [
'platforms',
'cloudtentacles',
'bindUrlProbeTimeoutMs',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_USER_AGENT', [
'platforms',
'cloudtentacles',
'bindUrlProbeUserAgent',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_ENDPOINT', [
'platforms',
'cloudtentacles',
'bindUrlProbeEndpoint',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_CHART_ID', [
'platforms',
'cloudtentacles',
'bindUrlProbeChartId',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_SUB_CHART_ID', [
'platforms',
'cloudtentacles',
'bindUrlProbeSubChartId',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_IDE_TOKEN', [
'platforms',
'cloudtentacles',
'bindUrlProbeIdeToken',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_ACTIVITY_URL', [
'platforms',
'cloudtentacles',
'bindUrlProbeActivityUrl',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_REFERER', [
'platforms',
'cloudtentacles',
'bindUrlProbeReferer',
]),
stringEnv('CLOUDTENTACLES_BIND_URL_PROBE_EXTRA_COOKIE', [
'platforms',
'cloudtentacles',
'bindUrlProbeExtraCookie',
]),
stringEnv('CLOUDTENTACLES_PUBLIC_KEY_PEM', ['platforms', 'cloudtentacles', 'publicKeyPem']),
stringEnv('CLOUDTENTACLES_CLIENT_SOURCE', ['platforms', 'cloudtentacles', 'clientSource']),
stringEnv('CLOUDTENTACLES_DEVICE_ID', ['platforms', 'cloudtentacles', 'deviceId']),
integerEnv('CLOUDTENTACLES_DEVICE_TYPE', ['platforms', 'cloudtentacles', 'deviceType']),
stringEnv('KUASHOU_INDUSTRY_APP_KEY', ['platforms', 'kuaishouIndustry', 'appKey']),
stringEnv('KUASHOU_INDUSTRY_APP_SECRET', ['platforms', 'kuaishouIndustry', 'appSecret']),
stringEnv('KUASHOU_INDUSTRY_SIGN_SECRET', ['platforms', 'kuaishouIndustry', 'signSecret']),
@@ -171,9 +79,6 @@ export const ENV_OVERRIDES: readonly EnvOverride[] = [
stringEnv('KUASHOU_INDUSTRY_SHOP_ID', ['platforms', 'kuaishouIndustry', 'shopId']),
stringEnv('KUASHOU_INDUSTRY_SHOP_NAME', ['platforms', 'kuaishouIndustry', 'shopName']),
stringEnv('KUASHOU_INDUSTRY_VERSION', ['platforms', 'kuaishouIndustry', 'version']),
stringEnv('KUAISHOU_FEIFEI_BASE_URL', ['platforms', 'kuaishouFeifei', 'baseUrl']),
stringEnv('KUAISHOU_FEIFEI_APP_KEY', ['platforms', 'kuaishouFeifei', 'appKey']),
stringEnv('KUAISHOU_FEIFEI_APP_SECRET', ['platforms', 'kuaishouFeifei', 'appSecret']),
stringEnv('WORKER_SMS_PROVIDER', ['worker', 'sms', 'provider']),
stringEnv('WORKER_SMS_ACCESS_KEY_ID', ['worker', 'sms', 'accessKeyId']),
stringEnv('WORKER_SMS_ACCESS_KEY_SECRET', ['worker', 'sms', 'accessKeySecret']),
@@ -183,13 +88,6 @@ export const ENV_OVERRIDES: readonly EnvOverride[] = [
integerEnv('WORKER_SMS_COOLDOWN_SECONDS', ['worker', 'sms', 'cooldownSeconds']),
integerEnv('WORKER_SMS_DAILY_LIMIT', ['worker', 'sms', 'dailyLimit']),
booleanEnv('WORKER_ORDER_TIMELINE_VISIBLE', ['worker', 'orderTimelineVisible']),
integerEnv('KUAISHOU_FEIFEI_TIMEOUT_MS', ['platforms', 'kuaishouFeifei', 'timeoutMs']),
stringEnv('KUAISHOU_FEIFEI_NOTIFY_URL', ['platforms', 'kuaishouFeifei', 'notifyUrl']),
kuaishouFeifeiProductRulesEnv('KUAISHOU_FEIFEI_PRODUCT_RULES_JSON', [
'platforms',
'kuaishouFeifei',
'productRules',
]),
stringEnv('AFFILIATE_DASH_BASE_URL', ['platforms', 'affiliateDash', 'baseUrl']),
stringEnv('AFFILIATE_DASH_APP_KEY', ['platforms', 'affiliateDash', 'appKey']),
stringEnv('AFFILIATE_DASH_APP_SECRET', ['platforms', 'affiliateDash', 'appSecret']),
@@ -306,16 +204,6 @@ function adminUsersJsonEnv(env: string, configPath: RuntimeConfigPath): EnvOverr
}
}
function kuaishouFeifeiProductRulesEnv(env: string, configPath: RuntimeConfigPath): EnvOverride {
return {
env,
path: configPath,
read(rawValue) {
const parsed = parseJsonArray<KuaishouFeifeiProductRule>(rawValue)
return parsed === null ? null : parsed
},
}
}
function affiliateDashSkuMappingEnv(env: string, configPath: RuntimeConfigPath): EnvOverride {
return {
@@ -159,18 +159,32 @@ function createRuntimeConfig(overrides: Record<string, unknown> = {}): RuntimeCo
level: 'info',
integrationLevel: 'warn',
},
retention: {
rawPayloadDays: 180,
taskEventDays: 180,
webhookEventDays: 180,
auditLogDays: 365,
},
database: {
url: 'postgres://postgres:postgres@postgres:5432/order_site',
ssl: false,
maxConnections: 10,
},
storage: {
mode: 'minio',
endpoint: 'http://minio:9000',
bucket: 'order-site',
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
region: 'us-east-1',
maxUploadSizeMb: 10,
oss: {
endpoint: '',
bucket: '',
accessKeyId: '',
secretAccessKey: '',
region: 'oss-cn-hangzhou',
},
},
orders: {
claimBaseUrl: 'https://order.example.test/#/claim',
@@ -197,43 +211,42 @@ function createRuntimeConfig(overrides: Record<string, unknown> = {}): RuntimeCo
timestampToleranceSeconds: 600,
cardsEncoding: 'aes-256-ecb-base64',
},
cloudtentacles: {
baseUrl: 'https://123.207.217.176',
timeoutMs: 5000,
sendSmsPath: '/public/verif_code',
loginPath: '/public/login',
userInfoPath: '/user/info',
assetPath: '/user/get_asset',
permissionPath: '/user/get_permission',
categoriesPath: '/categories/get',
skuListPath: '/sku/list',
skuBuyPath: '/sku/buy',
skuUsePath: '/sku/use',
knapsackPath: '/user/get_knapsack',
vnListPath: '/vn/list',
vnAppointPath: '/vn/appoint',
vnGenerateLoginCodePath: '/vn/generate_login_code',
vnVerifCodePath: '/public/vn_verif_code',
vnVerifyLoginCodePath: '/vn/verify_login_code',
vnBindUrlPath: '/vn/bind_url',
vnBindInfoPath: '/vn/bind_info',
vnBackPath: '/vn/back',
bindUrlTtlSeconds: 600,
bindUrlProbeIntervalSeconds: 30,
bindUrlProbeTimeoutMs: 5000,
bindUrlProbeUserAgent: '',
bindUrlProbeEndpoint: 'https://comm.ams.game.qq.com/ide/',
bindUrlProbeChartId: '323794',
bindUrlProbeSubChartId: '323794',
bindUrlProbeIdeToken: 'z90Syo',
bindUrlProbeActivityUrl: '',
bindUrlProbeReferer: 'https://gp.qq.com/',
bindUrlProbeExtraCookie: '',
publicKeyPem: '',
clientSource: 'ct-client',
deviceId: '08bc9d8c-fd15-48ea-bc00-8d754076cafc',
deviceType: 1,
kuaishouIndustry: {
appKey: '',
appSecret: '',
signSecret: '',
messageSecret: '',
provider: 'kuaishou-industry',
platform: 'kuaishou',
shopId: 'kuaishou-industry',
shopName: '快手行业电子凭证',
version: '1',
},
affiliateDash: {
enabled: true,
baseUrl: '',
appKey: '',
appSecret: '',
callbackSecret: '',
timeoutMs: 10000,
notifyUrl: '',
timestampToleranceSeconds: 300,
preferredMatchEnabled: true,
skuMapping: {},
},
},
worker: {
sms: {
provider: 'mock',
accessKeyId: '',
accessKeySecret: '',
signName: '',
templateCode: '',
codeTtlSeconds: 300,
cooldownSeconds: 60,
dailyLimit: 10,
},
orderTimelineVisible: false,
},
},
overrides,
@@ -98,38 +98,6 @@ export function validateRuntimeConfig(
}
requireInteger(issues, 'orders.tokenTtlHours', config.orders?.tokenTtlHours, { min: 0 })
requireInteger(issues, 'admin.sessionTtlHours', config.admin?.sessionTtlHours, { min: 1 })
requireInteger(
issues,
'platforms.cloudtentacles.timeoutMs',
config.platforms?.cloudtentacles?.timeoutMs,
{ min: 1 },
)
if (config.platforms?.kuaishouFeifei) {
requireInteger(
issues,
'platforms.kuaishouFeifei.timeoutMs',
config.platforms.kuaishouFeifei.timeoutMs,
{ min: 1 },
)
}
requireInteger(
issues,
'platforms.cloudtentacles.bindUrlTtlSeconds',
config.platforms?.cloudtentacles?.bindUrlTtlSeconds,
{ min: 1 },
)
requireInteger(
issues,
'platforms.cloudtentacles.bindUrlProbeIntervalSeconds',
config.platforms?.cloudtentacles?.bindUrlProbeIntervalSeconds,
{ min: 1 },
)
requireInteger(
issues,
'platforms.cloudtentacles.bindUrlProbeTimeoutMs',
config.platforms?.cloudtentacles?.bindUrlProbeTimeoutMs,
{ min: 1 },
)
validateOptionalHttpUrl(issues, 'orders.claimBaseUrl', config.orders?.claimBaseUrl)
validateOptionalStorageEndpoint(issues, 'storage.endpoint', config.storage?.endpoint)