Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
638 lines
14 KiB
JSON
638 lines
14 KiB
JSON
[
|
|
{
|
|
"id": "F001",
|
|
"description": "Add 'solo' to TENANT_TIERS array so it becomes ['solo', 'pro', 'premium']",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F002",
|
|
"description": "Update TenantTier type to include 'solo'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F003",
|
|
"description": "Add TIER_LABELS entry: solo -> 'Solo'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F004",
|
|
"description": "Add TIER_RANK record: { solo: 0, pro: 1, premium: 2 }",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F005",
|
|
"description": "Add tierAtLeast(tier, minimum) helper using TIER_RANK comparison",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F006",
|
|
"description": "Add INTEGRATIONS to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F007",
|
|
"description": "Add EXTENSIONS to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F008",
|
|
"description": "Add MANAGED_EMAIL to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F009",
|
|
"description": "Add SSO to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F010",
|
|
"description": "Add ADVANCED_ASSETS to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F011",
|
|
"description": "Add CLIENT_PORTAL_ADMIN to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F012",
|
|
"description": "Add WORKFLOW_DESIGNER to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F013",
|
|
"description": "Add MOBILE_ACCESS to TIER_FEATURES enum with min tier 'pro'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F014",
|
|
"description": "Rewrite tierHasFeature() to use TIER_RANK comparison instead of map lookup",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F015",
|
|
"description": "Derive TIER_FEATURE_MAP from FEATURE_MINIMUM_TIER + TIER_RANK",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.6"
|
|
]
|
|
},
|
|
{
|
|
"id": "F016",
|
|
"description": "Add AI_ASSISTANT to ADD_ONS enum",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.7"
|
|
]
|
|
},
|
|
{
|
|
"id": "F017",
|
|
"description": "Add ADD_ON_LABELS record with AI_ASSISTANT -> 'AI Assistant'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.7"
|
|
]
|
|
},
|
|
{
|
|
"id": "F018",
|
|
"description": "Add ADD_ON_DESCRIPTIONS with marketing-friendly description for AI_ASSISTANT",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.7"
|
|
]
|
|
},
|
|
{
|
|
"id": "F019",
|
|
"description": "resolveTier() returns 'pro' for null/invalid input (unchanged behavior, Solo is opt-in)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.8"
|
|
]
|
|
},
|
|
{
|
|
"id": "F020",
|
|
"description": "isValidTier('solo') returns true",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F021",
|
|
"description": "Create getActiveAddOns(tenantId) service querying tenant_addons for non-expired add-ons",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1b.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F022",
|
|
"description": "Create assertAddOnAccess(addOn) that throws if tenant lacks the add-on",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1b.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F023",
|
|
"description": "assertAddOnAccess bypasses check in CE edition (all add-ons unlocked)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1b.2",
|
|
"R2.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F024",
|
|
"description": "Add STRIPE_AI_ADDON_PRICE_ID and STRIPE_AI_ADDON_ANNUAL_PRICE_ID env vars to Stripe config",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R1b.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F025",
|
|
"description": "Add isSolo boolean to TierContextValue (tier === 'solo')",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R2.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F026",
|
|
"description": "Add addOns array to TierContextValue populated from session/DB",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R2.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F027",
|
|
"description": "Add hasAddOn(addOn) helper to TierContextValue",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R2.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F028",
|
|
"description": "CE edition bypasses add-on checks (hasAddOn returns true for all)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R2.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F029",
|
|
"description": "Add requiredFeature?: TIER_FEATURES to MenuItem interface in menuConfig",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R3.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F030",
|
|
"description": "Annotate Extensions menu item with requiredFeature: TIER_FEATURES.EXTENSIONS",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R3.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F031",
|
|
"description": "Annotate Workflow Editor subitem with requiredFeature: TIER_FEATURES.WORKFLOW_DESIGNER",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R3.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F032",
|
|
"description": "SidebarWithFeatureFlags filters out menu items where requiredFeature is set and tier lacks it",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R3.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F033",
|
|
"description": "Sidebar filtering applies recursively to subItems",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R3.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F034",
|
|
"description": "Add requiredFeature?: TIER_FEATURES to TabContent type in SettingsPage",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F035",
|
|
"description": "Tag Integrations settings tab with TIER_FEATURES.INTEGRATIONS",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F036",
|
|
"description": "Tag Extensions settings tab with TIER_FEATURES.EXTENSIONS",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F037",
|
|
"description": "Tag Email settings tab with TIER_FEATURES.MANAGED_EMAIL",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F038",
|
|
"description": "Render FeatureUpgradeNotice instead of content when tab's requiredFeature is gated",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F039",
|
|
"description": "Gated settings tabs remain visible and clickable (not hidden)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F040",
|
|
"description": "Settings sidebar items remain visible regardless of tier (no requiredFeature filtering in settings mode)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R4.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F041",
|
|
"description": "Add assertTierAccess(TIER_FEATURES.INTEGRATIONS) to calendar/entra/teams EE route handlers",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F042",
|
|
"description": "Add assertTierAccess(TIER_FEATURES.EXTENSIONS) to extension install/uninstall EE route handlers",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F043",
|
|
"description": "Add assertTierAccess(TIER_FEATURES.MANAGED_EMAIL) to managed email EE handlers",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F044",
|
|
"description": "Add assertTierAccess(TIER_FEATURES.SSO) to SSO/OAuth EE handlers",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F045",
|
|
"description": "Add assertTierAccess(TIER_FEATURES.ADVANCED_ASSETS) to RMM EE handlers",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F046",
|
|
"description": "Add assertAddOnAccess(ADD_ONS.AI_ASSISTANT) to chat completions route",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F047",
|
|
"description": "Add assertAddOnAccess(ADD_ONS.AI_ASSISTANT) to document-assist route",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F048",
|
|
"description": "Gate RightSidebar AI component with hasAddOn(ADD_ONS.AI_ASSISTANT)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F049",
|
|
"description": "Check tenant tier in exchangeOttForSession() — reject Solo with 403",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5b.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F050",
|
|
"description": "Return upgrade message in 403 response for Solo mobile auth attempts",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R5b.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F051",
|
|
"description": "Add 'alga-psa-solo': 'solo' to stripeTierMapping",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F052",
|
|
"description": "getTierPriceIds() returns { basePriceId, userPriceId: null } for Solo",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F053",
|
|
"description": "createLicenseCheckoutSession() emits single line item when userPriceId is null",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F054",
|
|
"description": "handleCheckoutCompleted sets licensed_user_count = 1 for Solo (no per-user item)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F055",
|
|
"description": "handleSubscriptionUpdated sets licensed_user_count = 1 for Solo",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F056",
|
|
"description": "upgradeTier() supports Solo -> Pro: adds per-user line item, swaps base price",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F057",
|
|
"description": "New downgradeTier() validates active user count = 1 before proceeding",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F058",
|
|
"description": "downgradeTier() removes per-user item and swaps base price to Solo",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F059",
|
|
"description": "purchaseAddOn(AI_ASSISTANT) creates checkout session for AI add-on subscription item",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.6"
|
|
]
|
|
},
|
|
{
|
|
"id": "F060",
|
|
"description": "cancelAddOn(AI_ASSISTANT) removes AI line item from subscription",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.6"
|
|
]
|
|
},
|
|
{
|
|
"id": "F061",
|
|
"description": "Stripe webhook inserts tenant_addons row when AI subscription item is activated",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.7"
|
|
]
|
|
},
|
|
{
|
|
"id": "F062",
|
|
"description": "Stripe webhook deactivates tenant_addons row when AI subscription item is removed/cancelled",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.7"
|
|
]
|
|
},
|
|
{
|
|
"id": "F063",
|
|
"description": "Add env vars to .env.example: STRIPE_SOLO_BASE_PRICE_ID, STRIPE_SOLO_BASE_ANNUAL_PRICE_ID, STRIPE_AI_ADDON_PRICE_ID, STRIPE_AI_ADDON_ANNUAL_PRICE_ID",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.2",
|
|
"R1b.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F064",
|
|
"description": "Block addUser action when plan is 'solo' and used >= 1 internal users",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R7.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F065",
|
|
"description": "Return error 'Solo plan is limited to 1 user. Upgrade to Pro to add more users.' on block",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R7.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F066",
|
|
"description": "Disable 'Add User' button in user management UI when isSolo with upgrade CTA",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R7.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F067",
|
|
"description": "Add FEATURE_DISPLAY_NAMES entries for all 8 new TIER_FEATURES in AccountManagement",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.1"
|
|
]
|
|
},
|
|
{
|
|
"id": "F068",
|
|
"description": "Solo-specific messaging on account page: 'Your Solo plan includes core PSA features...'",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F069",
|
|
"description": "Show 'Upgrade to Pro' card for Solo tenants in AccountManagement",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.3"
|
|
]
|
|
},
|
|
{
|
|
"id": "F070",
|
|
"description": "Show 'Downgrade to Solo' option for Pro tenants when active user count = 1",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F071",
|
|
"description": "Show 'Add AI Assistant' purchase card when add-on is not active (any tier)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F072",
|
|
"description": "Show 'AI Assistant (active)' status when add-on is active with cancel option",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R8.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F073",
|
|
"description": "Update upgradeTierAction() to support Solo -> Pro",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.4"
|
|
]
|
|
},
|
|
{
|
|
"id": "F074",
|
|
"description": "Add downgradeTierAction() with user count validation",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.5"
|
|
]
|
|
},
|
|
{
|
|
"id": "F075",
|
|
"description": "Solo checkout includes 7-day trial period (trialDays=7)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F076",
|
|
"description": "Solo->Pro trial: activate Pro features for established Solo customers (past 7-day trial)",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.8"
|
|
]
|
|
},
|
|
{
|
|
"id": "F077",
|
|
"description": "Solo->Pro trial blocked if customer is still in their Solo trial period",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.8"
|
|
]
|
|
},
|
|
{
|
|
"id": "F078",
|
|
"description": "Solo->Pro trial reverts to Solo at trial end if not converted to paid Pro",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.8"
|
|
]
|
|
},
|
|
{
|
|
"id": "F079",
|
|
"description": "Show 'Try Pro free' CTA for established Solo customers in AccountManagement",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"R6.8",
|
|
"R8.3"
|
|
]
|
|
}
|
|
]
|