Spaces:
Running
Running
File size: 15,302 Bytes
c8e5eaa 2411edd c8e5eaa 2411edd c8e5eaa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | # models_sql.py
# ==========================================
# 🗄️ SQL 数据库模型定义
# ==========================================
# 🚀 P1性能优化:添加复合索引加速查询
# ==========================================
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Index, func, Text, DDL, event
from sqlalchemy.orm import declarative_base
import datetime
Base = declarative_base()
class OpenApiOperation(Base):
__tablename__ = "open_api_operations"
request_key = Column(String(64), primary_key=True)
request_hash = Column(String(64), nullable=False)
transaction_id = Column(String(100), nullable=False, unique=True)
response_payload = Column(Text, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
event.listen(OpenApiOperation.__table__, "after_create",
DDL("ALTER TABLE %(fullname)s ENABLE ROW LEVEL SECURITY").execute_if(dialect="postgresql"))
event.listen(OpenApiOperation.__table__, "after_create",
DDL("REVOKE ALL ON TABLE %(fullname)s FROM PUBLIC").execute_if(dialect="postgresql"))
event.listen(OpenApiOperation.__table__, "after_create", DDL("""
DO $$ BEGIN
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN
REVOKE ALL ON TABLE %(fullname)s FROM anon;
END IF;
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN
REVOKE ALL ON TABLE %(fullname)s FROM authenticated;
END IF;
END; $$
""").execute_if(dialect="postgresql"))
class ResourcePublication(Base):
"""同次资源发布的持久原始请求和恢复内容;不参与资金变更。"""
__tablename__ = "resource_publications"
request_key = Column(String(64), primary_key=True)
item_id = Column(String(100), nullable=False, unique=True)
author = Column(String, nullable=False)
request_payload = Column(Text, nullable=False)
payload = Column(Text, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
class TaskPublication(Base):
"""与任务资金冻结同提交的待发布记录;保留原始内容供失败恢复。"""
__tablename__ = "task_publications"
task_id = Column(String(64), primary_key=True)
publisher = Column(String, nullable=False)
payload = Column(Text, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
class TaskRevision(Base):
"""任务编辑的持久字段投影,与改价资金同事务;版本按钱包锁串行递增。"""
__tablename__ = "task_revisions"
task_id = Column(String(64), primary_key=True)
revision = Column(Integer, primary_key=True)
publisher = Column(String, nullable=False)
payload = Column(Text, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
class TaskAssignment(Base):
"""指派和订金SQL提交后的状态投影,不能因JSON失败再次扣订金。"""
__tablename__ = "task_assignments"
task_id = Column(String(64), primary_key=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
deposit = Column(Integer, nullable=False)
assigned_at = Column(Integer, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
class TaskDelivery(Base):
"""交付/退回最新版本先持久保存,JSON失败不能丢失成果或恢复旧验收。"""
__tablename__ = "task_deliveries"
task_id = Column(String(64), primary_key=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
revision = Column(Integer, nullable=False)
payload = Column(Text, nullable=False)
updated_at = Column(Integer, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
class TaskSettlement(Base):
"""验收付款和待完成状态同事务;一任务只结算一次。"""
__tablename__ = "task_settlements"
task_id = Column(String(64), primary_key=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
amount = Column(Integer, nullable=False)
deposit = Column(Integer, nullable=False)
payment_tx_id = Column(String, nullable=False)
income_tx_id = Column(String, nullable=False)
completed_at = Column(Integer, nullable=False)
feedback = Column(Text, nullable=True)
projected = Column(Boolean, nullable=False, default=False, index=True)
class TaskResolution(Base):
"""仲裁资金和裁决同提交;一任务只允许一次最终分配。"""
__tablename__ = "task_resolutions"
task_id = Column(String(64), primary_key=True)
dispute_id = Column(String(64), nullable=False, unique=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
amount = Column(Integer, nullable=False)
deposit = Column(Integer, nullable=False)
publisher_refund = Column(Integer, nullable=False)
assignee_income = Column(Integer, nullable=False)
initiator_role = Column(String(16), nullable=False)
resolution = Column(String(32), nullable=False)
ratio = Column(Integer, nullable=True)
note = Column(Text, nullable=True)
resolved_by = Column(String, nullable=False)
resolved_at = Column(Integer, nullable=False)
payment_tx_id = Column(String, nullable=False)
refund_tx_id = Column(String, nullable=False)
income_tx_id = Column(String, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
class TaskDisputeRecord(Base):
"""申诉先持久保存;JSON同步期间也禁止普通验收结算。"""
__tablename__ = "task_dispute_records"
task_id = Column(String(64), primary_key=True)
dispute_id = Column(String(64), nullable=False, unique=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
payload = Column(Text, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
created_at = Column(Integer, nullable=False)
class TaskDisputeResponseRecord(Base):
"""首次申诉回应持久记录;一个任务只保存一份原始回应。"""
__tablename__ = "task_dispute_responses"
task_id = Column(String(64), primary_key=True)
dispute_id = Column(String(64), nullable=False, unique=True)
publisher = Column(String, nullable=False)
assignee = Column(String, nullable=False)
respondent = Column(String, nullable=False)
payload = Column(Text, nullable=False)
projected = Column(Boolean, nullable=False, default=False, index=True)
class Wallet(Base):
"""用户钱包表"""
__tablename__ = "wallets"
account = Column(String, primary_key=True, index=True)
balance = Column(Integer, default=0, nullable=False) # 用于消费的余额 (充值获得)
earn_balance = Column(Integer, default=0, nullable=False) # 创作者销售收益余额 (别人购买获得)
tip_balance = Column(Integer, default=0, nullable=False) # 【新增】创作者打赏收益余额 (粉丝赞助获得)
task_balance = Column(Integer, default=0, nullable=False) # 【新增】任务相关余额
frozen_balance = Column(Integer, default=0, nullable=False) # 提现审核冻结中的余额
# 预留版本列;未配置 version_id_col,不提供 ORM 乐观锁保护
version = Column(Integer, default=1)
class Ownership(Base):
"""资源所有权表"""
__tablename__ = "ownerships"
id = Column(Integer, primary_key=True, autoincrement=True)
account = Column(String, index=True)
item_id = Column(String, index=True)
purchased_at = Column(DateTime, default=datetime.datetime.utcnow)
# 🔄 P7后悔模式增强
price_paid = Column(Integer, default=0) # 购买时支付的价格
is_refunded = Column(Boolean, default=False) # 是否已退款
refunded_at = Column(DateTime, nullable=True) # 退款时间
# 🚀 P1性能优化:复合索引
__table_args__ = (
Index('ix_ownerships_account_item', 'account', 'item_id'),
Index('ix_ownerships_account_refunded', 'account', 'is_refunded'),
)
class Refund(Base):
"""🔄 P7后悔模式:退款记录表"""
__tablename__ = "refunds"
id = Column(Integer, primary_key=True, autoincrement=True)
account = Column(String, index=True) # 退款用户
item_id = Column(String, index=True) # 退款商品
amount = Column(Integer) # 退款金额
refunded_at = Column(DateTime, default=datetime.datetime.utcnow)
ban_until = Column(DateTime) # 禁止购买截止时间(30天后)
class RechargeOrder(Base):
"""💰 充值订单预存表(订单号→账号映射持久化,防止实例重启导致回调找不到订单)"""
__tablename__ = "recharge_orders"
order_id = Column(String, primary_key=True) # 商户订单号 PAY_xxx
account = Column(String, index=True) # 充值用户
amount = Column(Integer) # 充值金额
status = Column(String, default="pending") # pending/paid
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class Transaction(Base):
"""交易流水表"""
__tablename__ = "transactions"
tx_id = Column(String, primary_key=True)
account = Column(String, index=True)
tx_type = Column(String) # 枚举: RECHARGE, PURCHASE, SALE, TIP_OUT, TIP_IN, WITHDRAW, WITHDRAW_FEE, REFUND, SALE_REFUND, TASK_FREEZE, TASK_PRICE_ADJUST, TASK_DEPOSIT, TASK_PAYMENT, TASK_INCOME, TASK_REFUND, TASK_CANCEL_REFUND
amount = Column(Integer)
related_account = Column(String, nullable=True)
item_id = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow, index=True) # 🚀 P1: 添加时间索引
prev_hash = Column(String) # 上一笔订单的哈希
tx_hash = Column(String) # 本笔订单的哈希 (防篡改)
# 💰 提现相关字段 (仅 WITHDRAW_APPLY 类型交易使用)
alipay_account = Column(String, nullable=True) # 收款支付宝账号
real_name = Column(String, nullable=True) # 收款人姓名
withdraw_status = Column(String, nullable=True) # pending / completed
payment_order_id = Column(String, nullable=True) # 管理员填写的打款订单号
net_amount = Column(Integer, nullable=True) # 实际到账金额(用于解冻时准确扣减)
# 交易详情增强字段
description = Column(String, nullable=True) # 交易自描述文本
item_title = Column(String, nullable=True) # 资源/任务标题
item_type = Column(String, nullable=True) # 资源类型 (tool/skill/app/recommend/post/task/prompt)
related_user_name = Column(String, nullable=True) # 对方用户名
# 🌐 开放API:来源插件标识(如 "nodecraft_ai"),用于按工具结构化追踪消费
source_plugin = Column(String(50), nullable=True, index=True)
# 🚀 P1性能优化:复合索引
__table_args__ = (
Index('ix_transactions_account_type', 'account', 'tx_type'),
Index('ix_transactions_account_created', 'account', 'created_at'),
Index('ix_transactions_source_plugin_created', 'source_plugin', 'created_at'),
)
class SystemConfig(Base):
"""系统配置表 - 持久化存储,替代 /tmp/system_config.json"""
__tablename__ = "system_configs"
config_key = Column(String, primary_key=True)
config_value = Column(String, nullable=False, default="{}")
updated_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_by = Column(String, nullable=True)
class RegisteredPlugin(Base):
"""🌐 开放API:第三方插件注册信息表"""
__tablename__ = "registered_plugins"
plugin_id = Column(String(50), primary_key=True) # 英文标识如 "nodecraft_ai"
plugin_key = Column(String(100), unique=True, nullable=False, index=True)
name = Column(String(100), nullable=False) # 显示名
description = Column(String(500), nullable=True)
enabled = Column(Boolean, default=True, nullable=False)
rate_limit = Column(Integer, default=100) # 每分钟最大请求数
max_deduct_per_tx = Column(Integer, default=100) # 单笔扣款上限
max_deduct_per_day = Column(Integer, default=1000) # 日扣款上限
permissions = Column(String(200), default='["verify","balance","deduct","refund"]') # JSON数组
created_at = Column(DateTime, default=func.now())
created_by = Column(String(50)) # 创建者管理员账号
updated_at = Column(DateTime, onupdate=func.now())
last_rotated_at = Column(DateTime, nullable=True) # 上次轮换key时间
class OpenApiRateLimitBucket(Base):
"""跨 worker 持久化的开放 API 插件分钟窗口计数。"""
__tablename__ = "open_api_rate_limit_buckets"
plugin_id = Column(String(50), primary_key=True)
window_start = Column(Integer, nullable=False)
request_count = Column(Integer, nullable=False, default=0)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
class ApiRateLimitBucket(Base):
"""跨 worker 共享的常规 API 限流分钟窗口。"""
__tablename__ = "api_rate_limit_buckets"
bucket_key = Column(String(64), primary_key=True)
window_start = Column(Integer, nullable=False)
request_count = Column(Integer, nullable=False, default=0)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
class VerificationContactCooldown(Base):
"""验证码联系方式发送冷却;只持久化脱敏哈希键,不保存原始邮箱/手机号。"""
__tablename__ = "verification_contact_cooldowns"
contact_key = Column(String(64), primary_key=True)
last_sent_at = Column(Integer, nullable=False)
claim_id = Column(String(32), nullable=False)
class VerificationCode(Base):
"""跨 worker 一次性验证码;仅保存联系方式哈希和带密钥的验证码摘要。"""
__tablename__ = "verification_codes"
contact_key = Column(String(64), primary_key=True)
code_digest = Column(String(64), nullable=False)
expires_at = Column(Integer, nullable=False, index=True)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|