feat(membership): enforce tenant subscription plans with blocked UI

Add configurable membership plans (free/plus/pro) synced to DB on boot, a
subscription guard middleware that blocks tenant endpoints on expired or
missing plans, and a MembershipBlockedView that surfaces the reason so
the admin can contact the tenant owner. Quota and brand-library reads now
honor the active plan's policy JSON and expired subscriptions.
This commit is contained in:
2026-04-18 20:56:05 +08:00
parent 9ec9314aea
commit 63667ed2d1
28 changed files with 1738 additions and 80 deletions
+16
View File
@@ -95,6 +95,22 @@ const enUS = {
defaultTestAccount: "Default account",
defaultTestPassword: "Default password",
},
membershipBlocked: {
eyebrow: "Access Paused",
title: "This tenant plan is unavailable",
reasonTrialExpired: "The free trial's 3-day page access window has ended. All business pages are now locked. Please contact an administrator to reactivate trial access.",
reasonRequired: "This tenant does not have an active plan. All business pages are now locked. Please contact an administrator.",
reasonInactive: "This tenant plan has expired or been disabled. All business pages are now locked. Please contact an administrator to restore access.",
plan: "Current Plan",
expiredAt: "Expired At",
articleLimit: "Article Limit",
companyLimit: "Company Limit",
contactAdmin: "Once the administrator reactivates access, refresh this page to continue.",
logout: "Log out",
refresh: "Check again",
refreshing: "Checking…",
stillBlocked: "Access is still blocked. Please contact your administrator before checking again.",
},
shell: {
localeLabel: "Language",
quotaTitle: "Plan & Quota",
+16
View File
@@ -95,6 +95,22 @@ const zhCN = {
defaultTestAccount: "默认测试账号",
defaultTestPassword: "默认测试密码",
},
membershipBlocked: {
eyebrow: "访问已暂停",
title: "当前租户套餐不可用",
reasonTrialExpired: "免费试用的 3 天页面可访问期已经结束,当前业务页面已全部关闭,请联系管理员重新开通试用权限。",
reasonRequired: "当前租户尚未开通有效套餐,业务页面已全部关闭,请联系管理员处理。",
reasonInactive: "当前租户套餐已失效或已停用,业务页面已全部关闭,请联系管理员恢复访问。",
plan: "当前套餐",
expiredAt: "到期时间",
articleLimit: "文章额度",
companyLimit: "公司数量",
contactAdmin: "管理员重新开通后,刷新页面即可恢复访问。",
logout: "退出登录",
refresh: "重新检查",
refreshing: "检查中…",
stillBlocked: "账户仍处于受限状态,请先联系管理员后再重试。",
},
shell: {
localeLabel: "语言",
quotaTitle: "套餐与额度",