@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
- package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
- package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
- package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
- package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
- package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
- package/tests/cypress/e2e/_docs/README.md +215 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
- package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
- package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
- package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
- package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
- package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
- package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
- package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
- package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
- package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
- package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
- package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
- package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
- package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
- package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
- package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
- package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
- package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
- package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
- package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
- package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
- package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
- package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
- package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
- package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
- package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
- package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
- package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
- package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
- package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
- package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
- package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
- package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
- package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
- package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
- package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
- package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
- package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
- package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
- package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
- package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
- package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
- package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
- package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
- package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
- package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
- package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
- package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
- package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
- package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
- package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
- package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
- package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
- package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
- package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
- package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
- package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
- package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
- package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
- package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
- package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
- package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
- package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
- package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
- package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
- package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
- package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
- package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
- package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
- package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
- package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
- package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
- package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
- package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
- package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
- package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
- package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
- package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
- package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
- package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
- package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
- package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
- package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
- package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
- package/tests/cypress/fixtures/blocks.json +218 -0
- package/tests/cypress/fixtures/entities.json +78 -0
- package/tests/cypress/fixtures/page-builder.json +21 -0
- package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
- package/tests/cypress/src/components/CustomersPOM.ts +439 -0
- package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
- package/tests/cypress/src/components/EntityForm.ts +375 -0
- package/tests/cypress/src/components/EntityList.ts +389 -0
- package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
- package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
- package/tests/cypress/src/components/PostsListPOM.ts +223 -0
- package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
- package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
- package/tests/cypress/src/components/TasksPOM.ts +272 -0
- package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
- package/tests/cypress/src/components/index.ts +21 -0
- package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
- package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
- package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
- package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
- package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
- package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
- package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
- package/tests/cypress/src/controllers/index.js +25 -0
- package/tests/cypress/src/core/AuthPOM.ts +450 -0
- package/tests/cypress/src/core/BasePOM.ts +86 -0
- package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
- package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
- package/tests/cypress/src/core/index.ts +14 -0
- package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
- package/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/tests/cypress/src/entities/PostsPOM.ts +137 -0
- package/tests/cypress/src/entities/TasksPOM.ts +176 -0
- package/tests/cypress/src/entities/index.ts +14 -0
- package/tests/cypress/src/features/BillingPOM.ts +385 -0
- package/tests/cypress/src/features/DashboardPOM.ts +245 -0
- package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
- package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
- package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
- package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
- package/tests/cypress/src/features/SettingsPOM.ts +362 -0
- package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
- package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
- package/tests/cypress/src/features/index.ts +28 -0
- package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
- package/tests/cypress/src/index.ts +101 -0
- package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
- package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
- package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
- package/tests/cypress/src/pages/dashboard/index.js +6 -0
- package/tests/cypress/src/pages/index.js +5 -0
- package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
- package/tests/cypress/src/pages/public/LandingPage.js +69 -0
- package/tests/cypress/src/pages/public/PricingPage.js +33 -0
- package/tests/cypress/src/pages/public/index.js +6 -0
- package/tests/cypress/src/selectors.ts +46 -0
- package/tests/cypress/src/session-helpers.ts +500 -0
- package/tests/cypress/support/doc-commands.ts +260 -0
- package/tests/cypress.config.ts +150 -0
- package/tests/jest/components/post-header.test.tsx +377 -0
- package/tests/jest/config/role-config.test.ts +529 -0
- package/tests/jest/jest.config.ts +81 -0
- package/tests/jest/langchain/COVERAGE.md +372 -0
- package/tests/jest/langchain/guardrails.test.ts +465 -0
- package/tests/jest/langchain/streaming.test.ts +367 -0
- package/tests/jest/langchain/token-tracker.test.ts +455 -0
- package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
- package/tests/jest/langchain/tracer.test.ts +823 -0
- package/tests/jest/user-roles/role-helpers.test.ts +432 -0
- package/tests/jest/validation/categories.test.ts +429 -0
- package/tests/jest/validation/posts.test.ts +546 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/// <reference types="cypress" />
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Billing API - Downgrade Policy Tests
|
|
6
|
+
*
|
|
7
|
+
* BDD: Feature: Downgrade Policy - Soft Limits
|
|
8
|
+
* As a user downgrading from a higher plan
|
|
9
|
+
* I want my existing resources to remain accessible
|
|
10
|
+
* So that I don't lose my data
|
|
11
|
+
*
|
|
12
|
+
* Tests for:
|
|
13
|
+
* - Downgrade is always allowed
|
|
14
|
+
* - Existing resources remain accessible after downgrade
|
|
15
|
+
* - New resource creation blocked when over limit
|
|
16
|
+
* - Creation allowed after reducing resources
|
|
17
|
+
* - Features are lost immediately on downgrade
|
|
18
|
+
* - Team members remain but cannot add more
|
|
19
|
+
*
|
|
20
|
+
* Session: 2025-12-20-subscriptions-system-v2
|
|
21
|
+
* Phase: 9 (api-tester)
|
|
22
|
+
*
|
|
23
|
+
* NOTE: These tests validate the soft-limit downgrade policy configuration.
|
|
24
|
+
* Full E2E downgrade tests require Stripe integration.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import * as allure from 'allure-cypress'
|
|
28
|
+
|
|
29
|
+
const BillingAPIController = require('../BillingAPIController.js')
|
|
30
|
+
import billingPlans from './fixtures/billing-plans.json'
|
|
31
|
+
|
|
32
|
+
describe('Billing API - Downgrade Policy (Soft Limits)', () => {
|
|
33
|
+
let billingAPI: any
|
|
34
|
+
|
|
35
|
+
// Test data from fixtures
|
|
36
|
+
const FREE_PLAN = billingPlans.plans.free
|
|
37
|
+
const STARTER_PLAN = billingPlans.plans.starter
|
|
38
|
+
const PRO_PLAN = billingPlans.plans.pro
|
|
39
|
+
const BUSINESS_PLAN = billingPlans.plans.business
|
|
40
|
+
const SUPERADMIN = billingPlans.testCredentials.superadmin
|
|
41
|
+
const BASE_URL = Cypress.config('baseUrl') || 'http://localhost:5173'
|
|
42
|
+
|
|
43
|
+
before(() => {
|
|
44
|
+
billingAPI = new BillingAPIController(BASE_URL, SUPERADMIN.apiKey, SUPERADMIN.teamId)
|
|
45
|
+
cy.log('BillingAPIController initialized for Downgrade Policy tests')
|
|
46
|
+
cy.log('Testing soft-limit downgrade behavior')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
allure.epic('Billing')
|
|
51
|
+
allure.feature('Downgrade Policy')
|
|
52
|
+
allure.owner('qa-automation')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// ============================================================
|
|
56
|
+
// TEST GROUP 1: Plan Limit Comparisons for Downgrade
|
|
57
|
+
// ============================================================
|
|
58
|
+
describe('Limit Comparisons', () => {
|
|
59
|
+
it('DOWNGRADE_001: Free plan limits should be lower than all paid plans', () => {
|
|
60
|
+
allure.story('Limit Analysis')
|
|
61
|
+
allure.severity('critical')
|
|
62
|
+
allure.description(`
|
|
63
|
+
Scenario: Free plan has lowest limits
|
|
64
|
+
Given the plan configurations
|
|
65
|
+
Then Free limits should be < Starter < Pro < Business
|
|
66
|
+
`)
|
|
67
|
+
|
|
68
|
+
const limits = ['team_members', 'tasks', 'customers', 'webhooks_count']
|
|
69
|
+
|
|
70
|
+
limits.forEach((limit) => {
|
|
71
|
+
// Free < Starter
|
|
72
|
+
expect(FREE_PLAN.limits[limit]).to.be.lessThan(STARTER_PLAN.limits[limit])
|
|
73
|
+
// Starter < Pro
|
|
74
|
+
expect(STARTER_PLAN.limits[limit]).to.be.lessThan(PRO_PLAN.limits[limit])
|
|
75
|
+
// Pro < Business
|
|
76
|
+
expect(PRO_PLAN.limits[limit]).to.be.lessThan(BUSINESS_PLAN.limits[limit])
|
|
77
|
+
|
|
78
|
+
cy.log(`${limit}: Free=${FREE_PLAN.limits[limit]} < Starter=${STARTER_PLAN.limits[limit]} < Pro=${PRO_PLAN.limits[limit]} < Business=${BUSINESS_PLAN.limits[limit]}`)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('DOWNGRADE_002: Calculate potential over-limit scenarios on downgrade', () => {
|
|
83
|
+
allure.story('Over-limit Calculation')
|
|
84
|
+
allure.severity('normal')
|
|
85
|
+
allure.description(`
|
|
86
|
+
Scenario: Identify resources that would exceed limits on downgrade
|
|
87
|
+
Given a team at Pro limits
|
|
88
|
+
When they downgrade to Free
|
|
89
|
+
Then many resources would be over limit
|
|
90
|
+
`)
|
|
91
|
+
|
|
92
|
+
// Simulate a team using Pro limits fully
|
|
93
|
+
const proUsage = {
|
|
94
|
+
team_members: PRO_PLAN.limits.team_members, // 15
|
|
95
|
+
tasks: PRO_PLAN.limits.tasks, // 1000
|
|
96
|
+
customers: PRO_PLAN.limits.customers, // 500
|
|
97
|
+
webhooks_count: PRO_PLAN.limits.webhooks_count // 10
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Calculate over-limit on downgrade to Free
|
|
101
|
+
const overLimits = {
|
|
102
|
+
team_members: proUsage.team_members - FREE_PLAN.limits.team_members, // 15 - 3 = 12
|
|
103
|
+
tasks: proUsage.tasks - FREE_PLAN.limits.tasks, // 1000 - 50 = 950
|
|
104
|
+
customers: proUsage.customers - FREE_PLAN.limits.customers, // 500 - 25 = 475
|
|
105
|
+
webhooks_count: proUsage.webhooks_count - FREE_PLAN.limits.webhooks_count // 10 - 0 = 10
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cy.log('Over-limit resources on Pro -> Free downgrade:')
|
|
109
|
+
Object.entries(overLimits).forEach(([key, value]) => {
|
|
110
|
+
if (value as number > 0) {
|
|
111
|
+
cy.log(` ${key}: ${value} over limit`)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// Verify significant over-limit
|
|
116
|
+
expect(overLimits.tasks).to.be.greaterThan(900)
|
|
117
|
+
expect(overLimits.customers).to.be.greaterThan(400)
|
|
118
|
+
expect(overLimits.team_members).to.be.greaterThan(10)
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
// ============================================================
|
|
123
|
+
// TEST GROUP 2: Feature Loss on Downgrade
|
|
124
|
+
// ============================================================
|
|
125
|
+
describe('Feature Loss', () => {
|
|
126
|
+
it('DOWNGRADE_010: Pro features should be lost when downgrading to Free', () => {
|
|
127
|
+
allure.story('Feature Loss')
|
|
128
|
+
allure.severity('critical')
|
|
129
|
+
allure.description(`
|
|
130
|
+
Scenario: Features are lost immediately on downgrade
|
|
131
|
+
Given a team with Pro plan
|
|
132
|
+
When they downgrade to Free plan
|
|
133
|
+
Then Pro-exclusive features should be blocked
|
|
134
|
+
`)
|
|
135
|
+
|
|
136
|
+
// Features in Pro but not in Free
|
|
137
|
+
const proExclusiveFeatures = PRO_PLAN.features.filter(
|
|
138
|
+
(f: string) => !FREE_PLAN.features.includes(f)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
cy.log('Features lost on Pro -> Free downgrade:')
|
|
142
|
+
proExclusiveFeatures.forEach((feature: string) => {
|
|
143
|
+
cy.log(` - ${feature}`)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Expected to lose
|
|
147
|
+
expect(proExclusiveFeatures).to.include('advanced_analytics')
|
|
148
|
+
expect(proExclusiveFeatures).to.include('realtime_analytics')
|
|
149
|
+
expect(proExclusiveFeatures).to.include('webhooks')
|
|
150
|
+
expect(proExclusiveFeatures).to.include('task_automation')
|
|
151
|
+
expect(proExclusiveFeatures).to.include('custom_branding')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('DOWNGRADE_011: Map features to blocked actions after downgrade', () => {
|
|
155
|
+
allure.story('Action Blocking')
|
|
156
|
+
allure.severity('critical')
|
|
157
|
+
allure.description(`
|
|
158
|
+
Scenario: Feature loss means action blocking
|
|
159
|
+
Given the action mappings
|
|
160
|
+
When Pro features are lost
|
|
161
|
+
Then corresponding actions should be blocked
|
|
162
|
+
`)
|
|
163
|
+
|
|
164
|
+
const featureToActions = billingPlans.actionMappings.features
|
|
165
|
+
|
|
166
|
+
// Features lost on Pro -> Free
|
|
167
|
+
const lostFeatures = PRO_PLAN.features.filter(
|
|
168
|
+
(f: string) => !FREE_PLAN.features.includes(f)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
// Find actions that would be blocked
|
|
172
|
+
const blockedActions: string[] = []
|
|
173
|
+
Object.entries(featureToActions).forEach(([action, feature]) => {
|
|
174
|
+
if (lostFeatures.includes(feature as string)) {
|
|
175
|
+
blockedActions.push(action)
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
cy.log('Actions blocked after Pro -> Free downgrade:')
|
|
180
|
+
blockedActions.forEach((action) => {
|
|
181
|
+
cy.log(` - ${action}`)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// Verify key actions blocked
|
|
185
|
+
expect(blockedActions).to.include('analytics.view_advanced')
|
|
186
|
+
expect(blockedActions).to.include('analytics.view_realtime')
|
|
187
|
+
expect(blockedActions).to.include('tasks.automate')
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('DOWNGRADE_012: Business features lost on downgrade to Pro', () => {
|
|
191
|
+
allure.story('Feature Loss')
|
|
192
|
+
allure.severity('normal')
|
|
193
|
+
allure.description(`
|
|
194
|
+
Scenario: Business-exclusive features lost on downgrade to Pro
|
|
195
|
+
Given a team with Business plan
|
|
196
|
+
When they downgrade to Pro plan
|
|
197
|
+
Then Business-exclusive features should be blocked
|
|
198
|
+
`)
|
|
199
|
+
|
|
200
|
+
// Features in Business but not in Pro
|
|
201
|
+
const businessExclusiveFeatures = BUSINESS_PLAN.features.filter(
|
|
202
|
+
(f: string) => !PRO_PLAN.features.includes(f)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
cy.log('Features lost on Business -> Pro downgrade:')
|
|
206
|
+
businessExclusiveFeatures.forEach((feature: string) => {
|
|
207
|
+
cy.log(` - ${feature}`)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
// Expected to lose
|
|
211
|
+
expect(businessExclusiveFeatures).to.include('sso')
|
|
212
|
+
expect(businessExclusiveFeatures).to.include('audit_logs')
|
|
213
|
+
expect(businessExclusiveFeatures).to.include('customer_import')
|
|
214
|
+
expect(businessExclusiveFeatures).to.include('recurring_tasks')
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// ============================================================
|
|
219
|
+
// TEST GROUP 3: Soft Limit Policy
|
|
220
|
+
// ============================================================
|
|
221
|
+
describe('Soft Limit Policy', () => {
|
|
222
|
+
it('DOWNGRADE_020: Over-limit resources should remain accessible (read)', () => {
|
|
223
|
+
allure.story('Soft Limits')
|
|
224
|
+
allure.severity('critical')
|
|
225
|
+
allure.description(`
|
|
226
|
+
Scenario: Existing resources remain accessible after downgrade
|
|
227
|
+
Given my team was downgraded and has resources over limit
|
|
228
|
+
Then I should still be able to read all existing resources
|
|
229
|
+
Note: This is the "soft limit" policy
|
|
230
|
+
`)
|
|
231
|
+
|
|
232
|
+
// The soft limit policy means:
|
|
233
|
+
// - If you have 200 tasks and downgrade to Free (limit 50)
|
|
234
|
+
// - All 200 tasks remain accessible
|
|
235
|
+
// - You just can't create new ones
|
|
236
|
+
|
|
237
|
+
cy.log('Soft Limit Policy:')
|
|
238
|
+
cy.log(' ❌ New creation blocked when over limit')
|
|
239
|
+
cy.log(' ✓ Existing resources remain accessible')
|
|
240
|
+
cy.log(' ✓ Can delete/archive to get under limit')
|
|
241
|
+
cy.log(' ✓ Creation allowed again after reducing usage')
|
|
242
|
+
|
|
243
|
+
// Verify policy is documented in fixture
|
|
244
|
+
expect(FREE_PLAN.limits.tasks).to.eq(50)
|
|
245
|
+
cy.log(`Free plan task limit: ${FREE_PLAN.limits.tasks}`)
|
|
246
|
+
cy.log('If team has 200 tasks and downgrades: all 200 remain accessible')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('DOWNGRADE_021: Creation should be blocked when over limit', () => {
|
|
250
|
+
allure.story('Creation Blocking')
|
|
251
|
+
allure.severity('critical')
|
|
252
|
+
allure.description(`
|
|
253
|
+
Scenario: New resource creation blocked when over limit
|
|
254
|
+
Given my team has more resources than the plan limit
|
|
255
|
+
When I check action for creating more
|
|
256
|
+
Then the action should be denied with quota_exceeded
|
|
257
|
+
`)
|
|
258
|
+
|
|
259
|
+
// This tests the expected behavior
|
|
260
|
+
// When current > max, creation should be blocked
|
|
261
|
+
|
|
262
|
+
cy.log('Quota Exceeded Behavior:')
|
|
263
|
+
cy.log(' action: tasks.create')
|
|
264
|
+
cy.log(' current: 200 (example)')
|
|
265
|
+
cy.log(' max: 50 (Free plan)')
|
|
266
|
+
cy.log(' allowed: false')
|
|
267
|
+
cy.log(' reason: quota_exceeded')
|
|
268
|
+
|
|
269
|
+
// The check-action endpoint handles this case
|
|
270
|
+
// Response format:
|
|
271
|
+
const expectedResponse = {
|
|
272
|
+
allowed: false,
|
|
273
|
+
reason: 'quota_exceeded',
|
|
274
|
+
quota: {
|
|
275
|
+
allowed: false,
|
|
276
|
+
current: 200,
|
|
277
|
+
max: 50,
|
|
278
|
+
remaining: -150,
|
|
279
|
+
percentUsed: 400
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
cy.log('Expected response structure:')
|
|
284
|
+
cy.log(JSON.stringify(expectedResponse, null, 2))
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('DOWNGRADE_022: Quota remaining can be negative when over limit', () => {
|
|
288
|
+
allure.story('Negative Remaining')
|
|
289
|
+
allure.severity('normal')
|
|
290
|
+
allure.description(`
|
|
291
|
+
Scenario: Quota remaining shows negative when over limit
|
|
292
|
+
Given a team with 200 tasks on Free plan (limit 50)
|
|
293
|
+
When checking usage
|
|
294
|
+
Then remaining should be -150
|
|
295
|
+
And percentUsed should be > 100
|
|
296
|
+
`)
|
|
297
|
+
|
|
298
|
+
// When over limit:
|
|
299
|
+
// current: 200
|
|
300
|
+
// max: 50
|
|
301
|
+
// remaining: 50 - 200 = -150
|
|
302
|
+
// percentUsed: (200/50) * 100 = 400%
|
|
303
|
+
|
|
304
|
+
const overLimitScenario = {
|
|
305
|
+
current: 200,
|
|
306
|
+
max: 50,
|
|
307
|
+
remaining: -150,
|
|
308
|
+
percentUsed: 400
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
expect(overLimitScenario.remaining).to.be.lessThan(0)
|
|
312
|
+
expect(overLimitScenario.percentUsed).to.be.greaterThan(100)
|
|
313
|
+
|
|
314
|
+
cy.log('Over-limit quota calculation:')
|
|
315
|
+
cy.log(` current: ${overLimitScenario.current}`)
|
|
316
|
+
cy.log(` max: ${overLimitScenario.max}`)
|
|
317
|
+
cy.log(` remaining: ${overLimitScenario.remaining}`)
|
|
318
|
+
cy.log(` percentUsed: ${overLimitScenario.percentUsed}%`)
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
// ============================================================
|
|
323
|
+
// TEST GROUP 4: Recovery from Over-Limit
|
|
324
|
+
// ============================================================
|
|
325
|
+
describe('Recovery from Over-Limit', () => {
|
|
326
|
+
it('DOWNGRADE_030: Creation allowed after reducing resources', () => {
|
|
327
|
+
allure.story('Recovery')
|
|
328
|
+
allure.severity('critical')
|
|
329
|
+
allure.description(`
|
|
330
|
+
Scenario: Creation allowed after reducing resources
|
|
331
|
+
Given my team was over the tasks limit
|
|
332
|
+
When I delete tasks until under the limit
|
|
333
|
+
Then I should be able to create new tasks again
|
|
334
|
+
`)
|
|
335
|
+
|
|
336
|
+
// Recovery scenario:
|
|
337
|
+
// 1. Team has 200 tasks, Free plan limit 50
|
|
338
|
+
// 2. Delete 160 tasks -> now has 40 tasks
|
|
339
|
+
// 3. 40 < 50, so creation is allowed again
|
|
340
|
+
|
|
341
|
+
const recoveryScenario = {
|
|
342
|
+
before: { current: 200, max: 50, allowed: false },
|
|
343
|
+
after: { current: 40, max: 50, allowed: true, remaining: 10 }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
expect(recoveryScenario.before.allowed).to.be.false
|
|
347
|
+
expect(recoveryScenario.after.allowed).to.be.true
|
|
348
|
+
expect(recoveryScenario.after.remaining).to.eq(10)
|
|
349
|
+
|
|
350
|
+
cy.log('Recovery scenario:')
|
|
351
|
+
cy.log(' Before: 200 tasks (blocked)')
|
|
352
|
+
cy.log(' Action: Delete 160 tasks')
|
|
353
|
+
cy.log(' After: 40 tasks (10 remaining)')
|
|
354
|
+
cy.log(' Result: Creation allowed again')
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('DOWNGRADE_031: Team members soft limit behavior', () => {
|
|
358
|
+
allure.story('Team Members')
|
|
359
|
+
allure.severity('normal')
|
|
360
|
+
allure.description(`
|
|
361
|
+
Scenario: Team members remain but cannot add more
|
|
362
|
+
Given my team has 8 members (from Pro plan)
|
|
363
|
+
When I downgrade to Free plan (limit 3 members)
|
|
364
|
+
Then all 8 members should still be in the team
|
|
365
|
+
But I should not be able to invite new members
|
|
366
|
+
`)
|
|
367
|
+
|
|
368
|
+
// Pro allows 15 members, Free allows 3
|
|
369
|
+
// If team has 8 members and downgrades:
|
|
370
|
+
// - 8 members remain in team
|
|
371
|
+
// - Cannot invite more until < 3
|
|
372
|
+
|
|
373
|
+
const teamMemberScenario = {
|
|
374
|
+
proLimit: PRO_PLAN.limits.team_members, // 15
|
|
375
|
+
freeLimit: FREE_PLAN.limits.team_members, // 3
|
|
376
|
+
currentMembers: 8,
|
|
377
|
+
canInvite: false
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
expect(teamMemberScenario.currentMembers).to.be.greaterThan(teamMemberScenario.freeLimit)
|
|
381
|
+
expect(teamMemberScenario.canInvite).to.be.false
|
|
382
|
+
|
|
383
|
+
cy.log('Team members soft limit:')
|
|
384
|
+
cy.log(` Pro limit: ${teamMemberScenario.proLimit}`)
|
|
385
|
+
cy.log(` Free limit: ${teamMemberScenario.freeLimit}`)
|
|
386
|
+
cy.log(` Current members: ${teamMemberScenario.currentMembers}`)
|
|
387
|
+
cy.log(` Can invite: ${teamMemberScenario.canInvite}`)
|
|
388
|
+
cy.log(' Note: All 8 members remain, but no new invites')
|
|
389
|
+
})
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
// ============================================================
|
|
393
|
+
// TEST GROUP 5: Downgrade Warning Data
|
|
394
|
+
// ============================================================
|
|
395
|
+
describe('Downgrade Warning Data', () => {
|
|
396
|
+
it('DOWNGRADE_040: Calculate what exceeds limits on downgrade', () => {
|
|
397
|
+
allure.story('Warning Calculation')
|
|
398
|
+
allure.severity('normal')
|
|
399
|
+
allure.description(`
|
|
400
|
+
Scenario: Calculate resources that would exceed limits
|
|
401
|
+
Given current usage and target plan limits
|
|
402
|
+
Then calculate what resources would be over limit
|
|
403
|
+
`)
|
|
404
|
+
|
|
405
|
+
// Simulate a Pro team's usage
|
|
406
|
+
const currentUsage = {
|
|
407
|
+
team_members: 10,
|
|
408
|
+
tasks: 800,
|
|
409
|
+
customers: 300,
|
|
410
|
+
webhooks_count: 8
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Calculate what exceeds Free limits
|
|
414
|
+
const freeExceeds: Record<string, number> = {}
|
|
415
|
+
Object.keys(currentUsage).forEach((key) => {
|
|
416
|
+
const diff = currentUsage[key as keyof typeof currentUsage] - FREE_PLAN.limits[key]
|
|
417
|
+
if (diff > 0) {
|
|
418
|
+
freeExceeds[key] = diff
|
|
419
|
+
}
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
cy.log('Current usage (Pro team):')
|
|
423
|
+
Object.entries(currentUsage).forEach(([key, value]) => {
|
|
424
|
+
cy.log(` ${key}: ${value}`)
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
cy.log('Exceeds Free limits by:')
|
|
428
|
+
Object.entries(freeExceeds).forEach(([key, value]) => {
|
|
429
|
+
cy.log(` ${key}: +${value}`)
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
expect(freeExceeds.team_members).to.eq(7) // 10 - 3
|
|
433
|
+
expect(freeExceeds.tasks).to.eq(750) // 800 - 50
|
|
434
|
+
expect(freeExceeds.customers).to.eq(275) // 300 - 25
|
|
435
|
+
expect(freeExceeds.webhooks_count).to.eq(8) // 8 - 0
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
it('DOWNGRADE_041: Calculate features lost on downgrade', () => {
|
|
439
|
+
allure.story('Features Lost')
|
|
440
|
+
allure.severity('normal')
|
|
441
|
+
allure.description(`
|
|
442
|
+
Scenario: List features that will be lost on downgrade
|
|
443
|
+
Given current plan features and target plan features
|
|
444
|
+
Then list features that will be lost
|
|
445
|
+
`)
|
|
446
|
+
|
|
447
|
+
// Pro -> Free downgrade
|
|
448
|
+
const currentFeatures = PRO_PLAN.features
|
|
449
|
+
const targetFeatures = FREE_PLAN.features
|
|
450
|
+
|
|
451
|
+
const lostFeatures = currentFeatures.filter(
|
|
452
|
+
(f: string) => !targetFeatures.includes(f)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
cy.log(`Features in Pro: ${currentFeatures.length}`)
|
|
456
|
+
cy.log(`Features in Free: ${targetFeatures.length}`)
|
|
457
|
+
cy.log(`Features to be lost: ${lostFeatures.length}`)
|
|
458
|
+
|
|
459
|
+
lostFeatures.forEach((feature: string) => {
|
|
460
|
+
cy.log(` - ${feature}`)
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
expect(lostFeatures.length).to.be.greaterThan(5)
|
|
464
|
+
})
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
// ============================================================
|
|
468
|
+
// TEST GROUP 6: Integration Tests
|
|
469
|
+
// ============================================================
|
|
470
|
+
describe('Integration', () => {
|
|
471
|
+
it('DOWNGRADE_100: Complete downgrade policy validation', () => {
|
|
472
|
+
allure.story('Complete Validation')
|
|
473
|
+
allure.severity('critical')
|
|
474
|
+
allure.description(`
|
|
475
|
+
Integration test that validates downgrade policy:
|
|
476
|
+
- Soft limits preserve existing resources
|
|
477
|
+
- Creation blocked when over limit
|
|
478
|
+
- Features lost immediately
|
|
479
|
+
- Recovery possible by reducing usage
|
|
480
|
+
`)
|
|
481
|
+
|
|
482
|
+
// 1. Soft limit policy is in place
|
|
483
|
+
cy.log('1. Soft Limit Policy Verification')
|
|
484
|
+
cy.log(' Existing resources remain accessible')
|
|
485
|
+
cy.log(' Only new creation is blocked')
|
|
486
|
+
|
|
487
|
+
// 2. Feature loss is immediate
|
|
488
|
+
const proToFreeFeatureLoss = PRO_PLAN.features.filter(
|
|
489
|
+
(f: string) => !FREE_PLAN.features.includes(f)
|
|
490
|
+
)
|
|
491
|
+
expect(proToFreeFeatureLoss.length).to.be.greaterThan(0)
|
|
492
|
+
cy.log(`2. Feature loss: ${proToFreeFeatureLoss.length} features`)
|
|
493
|
+
|
|
494
|
+
// 3. Limits are enforced correctly
|
|
495
|
+
expect(FREE_PLAN.limits.tasks).to.eq(50)
|
|
496
|
+
expect(FREE_PLAN.limits.customers).to.eq(25)
|
|
497
|
+
expect(FREE_PLAN.limits.team_members).to.eq(3)
|
|
498
|
+
cy.log('3. Limits are defined correctly')
|
|
499
|
+
|
|
500
|
+
// 4. Action mappings exist for limits
|
|
501
|
+
const limitMappings = billingPlans.actionMappings.limits
|
|
502
|
+
expect(limitMappings['tasks.create']).to.eq('tasks')
|
|
503
|
+
expect(limitMappings['customers.create']).to.eq('customers')
|
|
504
|
+
expect(limitMappings['team.members.invite']).to.eq('team_members')
|
|
505
|
+
cy.log('4. Action mappings are correct')
|
|
506
|
+
|
|
507
|
+
cy.log('Downgrade policy validation complete')
|
|
508
|
+
})
|
|
509
|
+
})
|
|
510
|
+
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./billing-plans.schema.json",
|
|
3
|
+
"_description": "Test data for billing plan tests - matches billing.config.ts",
|
|
4
|
+
|
|
5
|
+
"plans": {
|
|
6
|
+
"free": {
|
|
7
|
+
"slug": "free",
|
|
8
|
+
"name": "Free",
|
|
9
|
+
"priceMonthly": 0,
|
|
10
|
+
"priceYearly": 0,
|
|
11
|
+
"features": ["basic_analytics"],
|
|
12
|
+
"limits": {
|
|
13
|
+
"team_members": 3,
|
|
14
|
+
"tasks": 50,
|
|
15
|
+
"customers": 25,
|
|
16
|
+
"api_calls": 1000,
|
|
17
|
+
"storage_gb": 1,
|
|
18
|
+
"file_uploads": 100,
|
|
19
|
+
"webhooks_count": 0
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"starter": {
|
|
23
|
+
"slug": "starter",
|
|
24
|
+
"name": "Starter",
|
|
25
|
+
"priceMonthly": 1500,
|
|
26
|
+
"priceYearly": 14400,
|
|
27
|
+
"features": ["basic_analytics", "advanced_analytics", "api_access", "guest_access"],
|
|
28
|
+
"limits": {
|
|
29
|
+
"team_members": 5,
|
|
30
|
+
"tasks": 200,
|
|
31
|
+
"customers": 100,
|
|
32
|
+
"api_calls": 10000,
|
|
33
|
+
"storage_gb": 10,
|
|
34
|
+
"file_uploads": 500,
|
|
35
|
+
"webhooks_count": 3
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"pro": {
|
|
39
|
+
"slug": "pro",
|
|
40
|
+
"name": "Pro",
|
|
41
|
+
"priceMonthly": 2900,
|
|
42
|
+
"priceYearly": 29000,
|
|
43
|
+
"features": [
|
|
44
|
+
"basic_analytics",
|
|
45
|
+
"advanced_analytics",
|
|
46
|
+
"realtime_analytics",
|
|
47
|
+
"api_access",
|
|
48
|
+
"webhooks",
|
|
49
|
+
"custom_branding",
|
|
50
|
+
"guest_access",
|
|
51
|
+
"priority_support",
|
|
52
|
+
"task_automation"
|
|
53
|
+
],
|
|
54
|
+
"limits": {
|
|
55
|
+
"team_members": 15,
|
|
56
|
+
"tasks": 1000,
|
|
57
|
+
"customers": 500,
|
|
58
|
+
"api_calls": 100000,
|
|
59
|
+
"storage_gb": 50,
|
|
60
|
+
"file_uploads": 2000,
|
|
61
|
+
"webhooks_count": 10
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"business": {
|
|
65
|
+
"slug": "business",
|
|
66
|
+
"name": "Business",
|
|
67
|
+
"priceMonthly": 7900,
|
|
68
|
+
"priceYearly": 79000,
|
|
69
|
+
"features": [
|
|
70
|
+
"basic_analytics",
|
|
71
|
+
"advanced_analytics",
|
|
72
|
+
"realtime_analytics",
|
|
73
|
+
"api_access",
|
|
74
|
+
"webhooks",
|
|
75
|
+
"custom_branding",
|
|
76
|
+
"sso",
|
|
77
|
+
"audit_logs",
|
|
78
|
+
"guest_access",
|
|
79
|
+
"priority_support",
|
|
80
|
+
"task_automation",
|
|
81
|
+
"customer_import",
|
|
82
|
+
"recurring_tasks"
|
|
83
|
+
],
|
|
84
|
+
"limits": {
|
|
85
|
+
"team_members": 50,
|
|
86
|
+
"tasks": 5000,
|
|
87
|
+
"customers": 2000,
|
|
88
|
+
"api_calls": 500000,
|
|
89
|
+
"storage_gb": 200,
|
|
90
|
+
"file_uploads": 10000,
|
|
91
|
+
"webhooks_count": 50
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"enterprise": {
|
|
95
|
+
"slug": "enterprise",
|
|
96
|
+
"name": "Enterprise",
|
|
97
|
+
"features": ["*"],
|
|
98
|
+
"limits": {
|
|
99
|
+
"team_members": -1,
|
|
100
|
+
"tasks": -1,
|
|
101
|
+
"customers": -1,
|
|
102
|
+
"api_calls": -1,
|
|
103
|
+
"storage_gb": -1,
|
|
104
|
+
"file_uploads": -1,
|
|
105
|
+
"webhooks_count": -1
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
"actionMappings": {
|
|
111
|
+
"features": {
|
|
112
|
+
"analytics.view_advanced": "advanced_analytics",
|
|
113
|
+
"analytics.view_realtime": "realtime_analytics",
|
|
114
|
+
"api.generate_key": "api_access",
|
|
115
|
+
"webhooks.create": "webhooks",
|
|
116
|
+
"branding.customize": "custom_branding",
|
|
117
|
+
"branding.white_label": "white_label",
|
|
118
|
+
"auth.configure_sso": "sso",
|
|
119
|
+
"security.view_audit_logs": "audit_logs",
|
|
120
|
+
"support.priority_access": "priority_support",
|
|
121
|
+
"support.dedicated_channel": "dedicated_support",
|
|
122
|
+
"team.invite_guest": "guest_access",
|
|
123
|
+
"tasks.automate": "task_automation",
|
|
124
|
+
"tasks.create_recurring": "recurring_tasks",
|
|
125
|
+
"customers.bulk_import": "customer_import"
|
|
126
|
+
},
|
|
127
|
+
"limits": {
|
|
128
|
+
"team.members.invite": "team_members",
|
|
129
|
+
"tasks.create": "tasks",
|
|
130
|
+
"customers.create": "customers",
|
|
131
|
+
"api.call": "api_calls",
|
|
132
|
+
"files.upload": "storage_gb",
|
|
133
|
+
"files.upload_count": "file_uploads",
|
|
134
|
+
"webhooks.create": "webhooks_count"
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
"testTeams": {
|
|
139
|
+
"free": {
|
|
140
|
+
"teamId": "team-personal-carlos-001",
|
|
141
|
+
"subscriptionId": "sub-personal-carlos-001",
|
|
142
|
+
"description": "Carlos personal team with Free plan"
|
|
143
|
+
},
|
|
144
|
+
"pro": {
|
|
145
|
+
"teamId": "team-tmt-001",
|
|
146
|
+
"subscriptionId": "sub-tmt-001",
|
|
147
|
+
"description": "TMT Core team with Pro plan"
|
|
148
|
+
},
|
|
149
|
+
"enterprise": {
|
|
150
|
+
"teamId": "team-ironvale-002",
|
|
151
|
+
"subscriptionId": "sub-ironvale-001",
|
|
152
|
+
"description": "Ironvale Global with Enterprise plan"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
"testCredentials": {
|
|
157
|
+
"superadmin": {
|
|
158
|
+
"apiKey": "test_api_key_for_testing_purposes_only_not_a_real_secret_key_abc123",
|
|
159
|
+
"userId": "test-superadmin-001",
|
|
160
|
+
"teamId": "team-tmt-001"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|