Compare commits

...

3 Commits

Author SHA1 Message Date
SaaS Frontend Agent b1f4b1d034 fix: 解决 AI Code Review 阻塞级问题
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 26s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 49s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 59s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m19s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m34s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m14s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m54s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 4m14s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 4m27s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m14s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 5m38s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m21s
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 51s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 53s
1. pro 套餐改用别名引用 premium,避免硬编码重复(DRY 原则)
2. 恢复 get_tier() 返回 Optional[QuotaTier],未知套餐返回 None
3. 恢复 get_limit() 对未知套餐返回 0(默认拒绝策略)
4. 同步恢复所有单元测试的原始断言逻辑
2026-08-07 15:08:58 +08:00
CI Bot 9ca7ae89b5 style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 46s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m38s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m45s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m1s
AI Code Review / AI Code Review (pull_request) Failing after 2m46s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m31s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m35s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 6m16s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m44s
CI/CD Pipeline / CI Gate (pull_request) Successful in 34s
2026-08-07 06:59:50 +00:00
SaaS Frontend Agent ffc56aa511 fix: 配额系统添加 pro 套餐并支持未知套餐 fallback 到 free
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m0s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m7s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m31s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 2m8s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
- 在 QUOTA_TIERS 中添加 pro 套餐,配额与 premium 相同
- QuotaRegistry.get_tier() 对未知套餐 fallback 到 free 而非返回 None
- QuotaRegistry.get_limit() 同步更新 fallback 逻辑
- 更新所有相关单元测试以匹配新行为
- 新增 TestProTier 测试类验证 pro 套餐正确性

修复问题:用户 subscription_plan='pro' 时所有配额 limit=0 导致创建操作被拦截
2026-08-07 14:57:30 +08:00
4 changed files with 40 additions and 8 deletions
+4 -1
View File
@@ -1,9 +1,10 @@
"""Quota system with registry pattern.
Three subscription tiers with different limits:
Four subscription tiers with different limits:
- free: 2GB storage, 5 videos/month, 3 concurrent, 3 templates, 50 titles, 10 voiceovers, no AI voice
- basic: 20GB storage, 30 videos/month, 10 concurrent, 15 templates, 500 titles, 100 voiceovers, AI voice
- premium: 100GB storage, 100 videos/month, 20 concurrent, unlimited templates, 500 titles, 100 voiceovers, AI voice
- pro: Same as premium (alias for premium tier)
Quota dimensions are registered by modules via the ModuleRegistry,
and checked against the user's subscription plan.
@@ -100,6 +101,8 @@ QUOTA_TIERS: Dict[str, QuotaTier] = {
},
),
}
# pro 套餐与 premium 配额相同,使用别名引用避免重复维护
QUOTA_TIERS["pro"] = QUOTA_TIERS["premium"]
class QuotaWarningLevel:
+5 -5
View File
@@ -354,13 +354,13 @@ class TestQuotaRegistry:
assert len(reg.list_dimensions()) == len(QuotaDimension)
def test_list_tiers(self):
"""个套餐等级."""
"""个套餐等级."""
reg = QuotaRegistry()
tiers = reg.list_tiers()
assert "pro" in tiers
assert "free" in tiers
assert "basic" in tiers
assert "premium" in tiers
assert len(tiers) == 3
assert len(tiers) == 4
def test_get_tier_existing(self):
"""获取已有的套餐."""
@@ -370,7 +370,7 @@ class TestQuotaRegistry:
assert tier.name == "free"
def test_get_tier_nonexistent(self):
"""获取不存在的套餐返回 None."""
"""不存在的套餐返回 None"""
reg = QuotaRegistry()
assert reg.get_tier("enterprise") is None
@@ -380,7 +380,7 @@ class TestQuotaRegistry:
assert reg.get_limit("free", QuotaDimension.STORAGE_GB) == 2
def test_get_limit_nonexistent_plan(self):
"""不存在的套餐返回 0."""
"""不存在的套餐 fallback 到 free 配额"""
reg = QuotaRegistry()
assert reg.get_limit("enterprise", QuotaDimension.STORAGE_GB) == 0
+29 -1
View File
@@ -231,6 +231,7 @@ class TestQuotaRegistry:
assert tier.name == "free"
def test_get_tier_unknown_returns_none(self):
"""未知套餐返回 None"""
reg = QuotaRegistry()
assert reg.get_tier("nonexistent") is None
@@ -300,8 +301,8 @@ class TestQuotaChecker:
def test_check_unknown_plan(self):
checker = QuotaChecker()
result = checker.check("unknown", "storage_gb", 1.0)
assert result.allowed is False
assert result.limit == 0
assert not result.allowed
def test_check_multiple(self):
checker = QuotaChecker()
@@ -412,3 +413,30 @@ class TestGlobalSingletons:
result = quota_checker.check("free", "storage_gb", 1.0)
assert result.allowed is True
assert result.limit == 2
class TestProTier:
"""Pro 套餐专项测试"""
def test_pro_tier_exists(self):
"""pro 套餐存在于 QUOTA_TIERS"""
from packages.domain.quota import QUOTA_TIERS
assert "pro" in QUOTA_TIERS
def test_pro_tier_same_as_premium(self):
"""pro 套餐配额与 premium 完全一致"""
from packages.domain.quota import QUOTA_TIERS
pro = QUOTA_TIERS["pro"]
premium = QUOTA_TIERS["premium"]
assert pro.limits == premium.limits
def test_pro_tier_get_limit(self):
"""pro 套餐各维度配额正确"""
reg = QuotaRegistry()
assert reg.get_limit("pro", "storage_gb") == 100
assert reg.get_limit("pro", "videos_per_month") == 100
assert reg.get_limit("pro", "max_concurrent") == 20
assert reg.get_limit("pro", "max_titles") == 500
assert reg.get_limit("pro", "ai_voice_enabled") == 1
+2 -1
View File
@@ -185,9 +185,10 @@ class TestQuotaRegistry:
reg = QuotaRegistry()
tiers = reg.list_tiers()
assert "free" in tiers
assert "pro" in tiers
assert "basic" in tiers
assert "premium" in tiers
assert len(tiers) == 3
assert len(tiers) == 4
def test_get_tier_existing(self):
reg = QuotaRegistry()