feat: multi-tenant workspace isolation, RBAC, sidebar nav, billing, and Android enhancements

- Backend: workspace_id isolation for 14 model tables + safe migration/backfill
- Backend: RBAC system with 4 roles and 23 permissions, seeded on startup
- Backend: workspace admin endpoints (list/manage all workspaces)
- Backend: admin user management API (CRUD, reset password)
- Backend: billing API with subscription plans, usage tracking, rate limiting
- Backend: fix system_logs.py UNION query and wrong column references
- Backend: WebSocket JWT auth and workspace enforcement
- Frontend: sidebar navigation replacing top dropdown menu
- Frontend: user management page (Users.vue) for admins
- Frontend: enhanced Workspaces.vue with admin table view
- Frontend: workspace RBAC computed properties in user store
- Android: agent marketplace, billing/subscription UI, onboarding wizard
- Android: phone login, analytics tracker, crash handler, network diagnostics
- Android: splash screen, encrypted token storage, app update enhancements
- Docs: multi-tenant RBAC guide with 8 sections and role-permission matrix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 01:00:22 +08:00
parent 51eafb23f3
commit 876789fac1
93 changed files with 8803 additions and 669 deletions

View File

@@ -0,0 +1,112 @@
"""
种子数据:初始化 3 个默认付费套餐
用法: cd backend && ./venv/Scripts/python.exe scripts/seed_billing_plans.py
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.core.database import SessionLocal, init_db
from app.models.billing import BillingPlan
import uuid
PLANS = [
{
"id": "a0000000-0000-0000-0000-000000000001",
"name": "免费版",
"tier": "free",
"price_monthly": 0,
"price_yearly": 0,
"daily_quota": 50,
"agent_limit": 3,
"knowledge_limit": 10,
"file_upload_mb": 5,
"models": ["deepseek-v4-pro"],
"features": [
"每日 50 次对话",
"3 个自建智能体",
"基础模型 DeepSeek-V3",
"10 条全局知识",
"5 MB 文件上传",
"社区支持",
],
"is_active": True,
"sort_order": 0,
},
{
"id": "a0000000-0000-0000-0000-000000000002",
"name": "专业版",
"tier": "pro",
"price_monthly": 29,
"price_yearly": 198,
"daily_quota": 500,
"agent_limit": 20,
"knowledge_limit": 500,
"file_upload_mb": 50,
"models": ["deepseek-v4-pro", "gpt-4o", "claude-sonnet-4-6", "gemini-2.5-pro"],
"features": [
"每日 500 次对话",
"20 个自建智能体",
"全部高级模型",
"500 条全局知识",
"50 MB 文件上传",
"优先响应队列",
"对话历史云端同步",
"对话导出 Markdown/PDF",
"专属客服通道",
],
"is_active": True,
"sort_order": 1,
},
{
"id": "a0000000-0000-0000-0000-000000000003",
"name": "企业版",
"tier": "enterprise",
"price_monthly": 99,
"price_yearly": 899,
"daily_quota": 0,
"agent_limit": 0,
"knowledge_limit": 0,
"file_upload_mb": 200,
"models": ["deepseek-v4-pro", "gpt-4o", "claude-sonnet-4-6", "gemini-2.5-pro"],
"features": [
"无限对话次数",
"无限智能体",
"团队协作10 人)",
"全部知识库功能",
"200 MB 文件上传",
"最高优先响应",
"API 调用额度 ¥50/月",
"管理员面板",
"专属成功经理 + 电话支持",
],
"is_active": True,
"sort_order": 2,
},
]
def seed():
init_db()
db = SessionLocal()
try:
for plan_data in PLANS:
existing = db.query(BillingPlan).filter(BillingPlan.id == plan_data["id"]).first()
if existing:
print(f"跳过已存在: {plan_data['name']}")
continue
plan = BillingPlan(**plan_data)
db.add(plan)
print(f"创建套餐: {plan_data['name']} (tier={plan_data['tier']})")
db.commit()
print("种子数据初始化完成")
except Exception as e:
db.rollback()
print(f"错误: {e}")
raise
finally:
db.close()
if __name__ == "__main__":
seed()