From 5443dba2696cb12ea46e1bc66f647b1650b65779 Mon Sep 17 00:00:00 2001 From: Ahmed Darrazi Date: Thu, 14 May 2026 13:09:36 +0200 Subject: [PATCH] refactor: consolidate internal tenant model naming --- .../Concerns/WorkspaceScopedTenantRoutes.php | 7 +- ...ChooseTenant.php => ChooseEnvironment.php} | 8 +- ...ge.php => CrossEnvironmentComparePage.php} | 248 ++++---- ...Dashboard.php => EnvironmentDashboard.php} | 32 +- ...nostics.php => EnvironmentDiagnostics.php} | 16 +- ...php => EnvironmentRequiredPermissions.php} | 28 +- .../Pages/Findings/MyFindingsInbox.php | 4 +- .../Pages/Governance/GovernanceInbox.php | 4 +- .../Pages/Monitoring/EvidenceOverview.php | 12 +- apps/platform/app/Filament/Pages/NoAccess.php | 2 +- .../Pages/Reviews/CustomerReviewWorkspace.php | 66 +-- .../Filament/Pages/Reviews/ReviewRegister.php | 60 +- .../Filament/Pages/Tenancy/RegisterTenant.php | 4 +- ...=> ManagedEnvironmentOnboardingWizard.php} | 550 +++++++++--------- ...ing.php => ManagedEnvironmentsLanding.php} | 10 +- .../Pages/ViewBaselineProfile.php | 24 +- ...urce.php => EnvironmentReviewResource.php} | 176 +++--- .../Pages/ListEnvironmentReviews.php | 20 + .../Pages/ViewEnvironmentReview.php} | 64 +- .../Resources/FindingExceptionResource.php | 2 +- .../Pages/ListFindingExceptions.php | 2 +- .../FindingResource/Pages/ListFindings.php | 4 +- ...rce.php => ManagedEnvironmentResource.php} | 196 +++---- .../Pages/EditManagedEnvironment.php} | 14 +- .../Pages/ListManagedEnvironments.php} | 26 +- .../Pages/ManageEnvironmentAccessScopes.php} | 8 +- .../Pages/ViewManagedEnvironment.php} | 54 +- ...EnvironmentMembershipsRelationManager.php} | 14 +- .../Filament/Resources/ReviewPackResource.php | 20 +- .../Pages/ListTenantReviews.php | 20 - .../System/Pages/Directory/ViewTenant.php | 8 +- .../Widgets/Dashboard/DashboardKpis.php | 4 +- ...p => EnvironmentDashboardContextChips.php} | 10 +- ...w.php => EnvironmentDashboardOverview.php} | 10 +- .../AdminRolesSummaryWidget.php | 4 +- .../BaselineCompareCoverageBanner.php | 4 +- .../FindingExceptionStatsOverview.php | 2 +- .../FindingStatsOverview.php | 2 +- .../ManagedEnvironmentArchivedBanner.php} | 6 +- .../ManagedEnvironmentReviewPackCard.php} | 12 +- ...gedEnvironmentTriageArrivalContinuity.php} | 46 +- .../ManagedEnvironmentVerificationReport.php} | 10 +- .../RecentOperationsSummary.php | 4 +- .../AdminConsentCallbackController.php | 10 +- ... => ClearEnvironmentContextController.php} | 6 +- ...anagedEnvironmentOnboardingController.php} | 6 +- .../OpenFindingExceptionsQueueController.php | 10 +- .../ReviewPackDownloadController.php | 4 +- ...er.php => SelectEnvironmentController.php} | 2 +- .../Middleware/EnsureWorkspaceSelected.php | 2 +- apps/platform/app/Jobs/BulkTenantSyncJob.php | 4 +- .../app/Jobs/CaptureBaselineSnapshotJob.php | 6 +- ...ob.php => ComposeEnvironmentReviewJob.php} | 22 +- .../app/Jobs/GenerateReviewPackJob.php | 24 +- ...CrossEnvironmentPromotionExecutionJob.php} | 42 +- .../Jobs/ProviderConnectionHealthCheckJob.php | 8 +- ...TenantReview.php => EnvironmentReview.php} | 32 +- ...ction.php => EnvironmentReviewSection.php} | 16 +- apps/platform/app/Models/EvidenceSnapshot.php | 6 +- .../app/Models/ManagedEnvironment.php | 6 +- ...> ManagedEnvironmentOnboardingSession.php} | 18 +- ...n.php => ManagedEnvironmentPermission.php} | 2 +- ...php => ManagedEnvironmentTriageReview.php} | 2 +- apps/platform/app/Models/ReviewPack.php | 6 +- ...Policy.php => EnvironmentReviewPolicy.php} | 28 +- ...gedEnvironmentOnboardingSessionPolicy.php} | 32 +- .../app/Providers/AuthServiceProvider.php | 12 +- .../Providers/Filament/AdminPanelProvider.php | 18 +- .../Services/Audit/WorkspaceAuditLogger.php | 74 +-- ... ManagedEnvironmentDiagnosticsService.php} | 2 +- ...> ManagedEnvironmentMembershipManager.php} | 2 +- .../app/Services/Auth/RoleCapabilityMap.php | 18 +- .../Auth/WorkspaceRoleCapabilityMap.php | 50 +- .../Baselines/BaselineCaptureService.php | 2 +- .../BaselineEvidenceCaptureResumeService.php | 2 +- .../EnvironmentReviewComposer.php} | 20 +- .../EnvironmentReviewFingerprint.php} | 4 +- .../EnvironmentReviewLifecycleService.php} | 50 +- .../EnvironmentReviewReadinessGate.php} | 62 +- .../EnvironmentReviewRegisterService.php} | 30 +- .../EnvironmentReviewSectionFactory.php} | 30 +- .../EnvironmentReviewService.php} | 54 +- ...> ManagedEnvironmentPermissionService.php} | 16 +- ...ntRequiredPermissionsViewModelBuilder.php} | 32 +- .../OnboardingDraftMutationService.php | 48 +- .../Onboarding/OnboardingDraftResolver.php | 26 +- .../OnboardingDraftStageResolver.php | 6 +- .../Onboarding/OnboardingLifecycleService.php | 52 +- .../QueuedExecutionLegitimacyGate.php | 2 +- .../PermissionPostureFindingGenerator.php | 2 +- ...sEnvironmentPromotionExecutionService.php} | 48 +- ...ManagedEnvironmentTriageReviewService.php} | 38 +- .../app/Services/ReviewPackService.php | 34 +- .../OperationRunTriageService.php | 8 +- .../Tenants/TenantActionPolicySurface.php | 14 +- .../Tenants/TenantOperabilityService.php | 6 +- .../app/Support/Audit/AuditActionId.php | 118 ++-- .../app/Support/Auth/Capabilities.php | 30 +- .../app/Support/Badges/BadgeCatalog.php | 12 +- .../app/Support/Badges/BadgeDomain.php | 10 +- ...nvironmentReviewCompletenessStateBadge.php | 28 + .../Domains/EnvironmentReviewStatusBadge.php | 28 + ...mentOnboardingVerificationStatusBadge.php} | 4 +- ...nagedEnvironmentPermissionStatusBadge.php} | 2 +- ...nagedEnvironmentTriageReviewStateBadge.php | 26 + .../TenantReviewCompletenessStateBadge.php | 28 - .../Domains/TenantReviewStatusBadge.php | 28 - .../Domains/TenantTriageReviewStateBadge.php | 26 - .../Badges/OperatorOutcomeTaxonomy.php | 4 +- .../WorkspaceHealthSummaryQuery.php | 16 +- .../EnvironmentDashboardSummary.php} | 4 +- .../EnvironmentDashboardSummaryBuilder.php} | 98 ++-- ...=> EnvironmentReviewCompletenessState.php} | 2 +- ...Status.php => EnvironmentReviewStatus.php} | 2 +- .../Controls/ComplianceEvidenceMappingV1.php | 16 +- .../GovernanceInboxSectionBuilder.php | 32 +- .../TrustedState/TrustedStatePolicy.php | 28 +- .../TrustedState/TrustedStateResolver.php | 6 +- .../app/Support/ManagedEnvironmentLinks.php | 6 +- .../Middleware/DenyNonMemberTenantAccess.php | 2 +- .../EnsureFilamentTenantSelected.php | 6 +- .../Navigation/CanonicalNavigationContext.php | 4 +- .../Onboarding/OnboardingCheckpoint.php | 2 +- .../Onboarding/OnboardingDraftStage.php | 2 +- .../Support/OperateHub/OperateHubShell.php | 4 + .../platform/app/Support/OperationCatalog.php | 8 +- .../app/Support/OperationRunLinks.php | 14 +- .../platform/app/Support/OperationRunType.php | 4 +- .../OperationalControlCatalog.php | 2 +- .../OperationRunCapabilityResolver.php | 4 +- .../GovernanceRunDiagnosticSummaryBuilder.php | 14 +- .../OpsUx/OperationRunProgressContract.php | 2 +- .../Support/OpsUx/OperationUxPresenter.php | 6 +- ...CrossEnvironmentComparePreviewBuilder.php} | 62 +- ...p => CrossEnvironmentCompareSelection.php} | 32 +- ...sEnvironmentPromotionExecutionPlanner.php} | 16 +- ...=> CrossEnvironmentPromotionPreflight.php} | 14 +- ...gedEnvironmentTriageReviewFingerprint.php} | 2 +- ...dEnvironmentTriageReviewStateResolver.php} | 20 +- .../PortfolioArrivalContextResolver.php | 8 +- .../ProviderCapabilityEvaluator.php | 8 +- .../SupportDiagnosticBundleBuilder.php | 56 +- .../Support/Tenants/TenantActionContext.php | 4 +- .../Tenants/TenantOperabilityContext.php | 6 +- .../ActionSurface/ActionSurfaceExemptions.php | 60 +- .../ActionSurface/ActionSurfaceValidator.php | 4 +- .../GovernanceActionCatalog.php | 52 +- .../ArtifactTruthPresenter.php | 86 +-- .../SurfaceCompressionContext.php | 10 +- ...gedEnvironmentPermissionCheckClusters.php} | 22 +- .../VerificationAssistViewModelBuilder.php | 4 +- .../TenantOwnedModelFamilies.php | 18 +- .../WorkspaceIsolation/TenantOwnedTables.php | 4 +- .../Workspaces/WorkspaceOverviewBuilder.php | 46 +- apps/platform/config/provider_boundaries.php | 2 +- apps/platform/config/tenantpilot.php | 8 +- ...ctory.php => EnvironmentReviewFactory.php} | 22 +- ...hp => EnvironmentReviewSectionFactory.php} | 20 +- ...edEnvironmentOnboardingSessionFactory.php} | 14 +- ...ManagedEnvironmentTriageReviewFactory.php} | 14 +- .../factories/ProductUsageEventFactory.php | 2 +- ...managed_environment_permissions_table.php} | 4 +- ...12_11_192942_add_is_current_to_tenants.php | 4 +- ...2_12_150000_add_rbac_fields_to_tenants.php | 4 +- ...0304_add_workspace_id_to_tenants_table.php | 4 +- ...environment_onboarding_sessions_table.php} | 6 +- ...environment_onboarding_sessions_table.php} | 6 +- ...nment_onboarding_sessions_constraints.php} | 82 +-- ...managed_environment_permissions_table.php} | 8 +- ...113_add_tenants_id_workspace_id_unique.php | 4 +- ...ace_id_not_null_on_tenant_owned_tables.php | 2 +- ...ion_constraints_to_tenant_owned_tables.php | 6 +- ...orkspace_id_fks_on_tenant_owned_tables.php | 2 +- ...15_120001_create_tenant_settings_table.php | 2 +- ...anaged_environment_onboarding_sessions.php | 49 ++ ..._to_managed_tenant_onboarding_sessions.php | 49 -- ...naged_environment_onboarding_sessions.php} | 40 +- ...000001_create_finding_exceptions_table.php | 2 +- ...eate_finding_exception_decisions_table.php | 2 +- ...ng_exception_evidence_references_table.php | 2 +- ...0000_create_environment_reviews_table.php} | 10 +- ...ate_environment_review_sections_table.php} | 8 +- ...nment_review_id_to_review_packs_table.php} | 8 +- ...aged_environment_triage_reviews_table.php} | 20 +- ...l_fields_to_managed_environments_table.php | 4 +- apps/platform/lang/de/localization.php | 4 +- apps/platform/lang/en/localization.php | 6 +- ...-onboarding-verification-report.blade.php} | 2 +- ...p => environment-review-section.blade.php} | 0 ...p => environment-review-summary.blade.php} | 0 ...blade.php => choose-environment.blade.php} | 6 +- ...hp => cross-environment-compare.blade.php} | 38 +- ....php => environment-diagnostics.blade.php} | 0 ...nvironment-required-permissions.blade.php} | 0 .../pages/reviews/review-register.blade.php | 2 +- ...d-environment-onboarding-wizard.blade.php} | 0 ...=> managed-environments-landing.blade.php} | 2 +- .../filament/partials/context-bar.blade.php | 22 +- ...ment-onboarding-checkpoint-poll.blade.php} | 0 .../pages/directory/view-tenant.blade.php | 6 +- ...ronment-dashboard-context-chips.blade.php} | 0 ... environment-dashboard-overview.blade.php} | 0 .../admin-roles-summary.blade.php | 0 ...baseline-compare-coverage-banner.blade.php | 0 ...ged-environment-archived-banner.blade.php} | 0 ...ed-environment-review-pack-card.blade.php} | 0 ...environment-verification-report.blade.php} | 0 .../recent-operations-summary.blade.php | 0 .../triage-arrival-continuity.blade.php | 4 +- apps/platform/routes/web.php | 36 +- ...TenantDashboardProductizationSmokeTest.php | 4 +- .../Browser/OnboardingDraftRefreshTest.php | 6 +- .../OnboardingDraftVerificationResumeTest.php | 14 +- ...nvironmentPromotionExecutionSmokeTest.php} | 14 +- .../CustomerReviewWorkspaceSmokeTest.php | 22 +- ...ec172DeferredOperatorSurfacesSmokeTest.php | 33 +- ...enceFreshnessPublicationTrustSmokeTest.php | 34 +- ...192RecordPageHeaderDisciplineSmokeTest.php | 32 +- ...193MonitoringSurfaceHierarchySmokeTest.php | 2 +- .../Spec194GovernanceFrictionSmokeTest.php | 46 +- ...c202GovernanceSubjectTaxonomySmokeTest.php | 4 +- .../Spec265DecisionRegisterSmokeTest.php | 4 +- ...ManagedEnvironmentCoreCutoverSmokeTest.php | 4 +- ...paceTenancyEnvironmentRoutingSmokeTest.php | 2 +- ...pec281ProviderConnectionScopeSmokeTest.php | 4 +- ...GovernanceArtifactRetargetingSmokeTest.php | 8 +- ...Spec284ArtifactSourceTaxonomySmokeTest.php | 8 +- ...orkspaceRbacEnvironmentAccessSmokeTest.php | 10 +- ...EnvironmentCopyNeutralizationSmokeTest.php | 2 +- ...nvironmentNamingConsolidationSmokeTest.php | 133 +++++ .../Browser/TenantMembershipsPageTest.php | 7 +- .../Feature/090/ActionSurfaceSmokeTest.php | 4 +- .../Feature/AdminConsentCallbackTest.php | 8 +- .../Audit/OnboardingDraftAuditTest.php | 46 +- .../ProviderConnectionIdentityAuditTest.php | 2 +- .../Audit/TenantLifecycleAuditLogTest.php | 6 +- .../Audit/TenantMembershipAuditLogTest.php | 10 +- .../Feature/Auth/AdminLocalSmokeLoginTest.php | 6 +- .../BackupHealthBrowserFixtureLoginTest.php | 6 +- .../DbOnlyPagesDoNotMakeHttpRequestsTest.php | 2 +- .../Auth/PostLoginRoutingByMembershipTest.php | 2 +- .../Auth/SessionSeparationSmokeTest.php | 6 +- .../Auth/TenantChooserSelectionTest.php | 14 +- ...torExplanationSurfaceAuthorizationTest.php | 10 +- .../Badges/OnboardingBadgeSemanticsTest.php | 6 +- .../BaselineCaptureAuditEventsTest.php | 2 +- ...aselineSnapshotNoTenantIdentifiersTest.php | 2 +- .../CaptureBaselineContentTest.php | 2 +- ...CaptureBaselineFullContentOnDemandTest.php | 2 +- .../CaptureBaselineMetaFallbackTest.php | 2 +- .../BaselineCaptureAmbiguousMatchGapTest.php | 4 +- .../BaselineCaptureGapClassificationTest.php | 2 +- ...BaselineCaptureRbacRoleDefinitionsTest.php | 2 +- .../Feature/Baselines/BaselineCaptureTest.php | 12 +- .../Baselines/BaselineCompareFindingsTest.php | 2 +- .../BaselineResolutionDeterminismTest.php | 2 +- .../BuildsGovernanceArtifactTruthFixtures.php | 40 +- .../BuildsPortfolioCompareFixtures.php | 20 +- .../BuildsPortfolioTriageFixtures.php | 24 +- ...dBackupHealthBrowserFixtureCommandTest.php | 6 +- ...nantDashboardProductizationActionsTest.php | 34 +- ...shboardProductizationAuthorizationTest.php | 50 +- ...ntDashboardProductizationReadinessTest.php | 76 +-- ...nantDashboardProductizationSummaryTest.php | 40 +- .../TenantGroupSelectorsDbOnlyTest.php | 6 +- .../AdminRolesSummaryWidgetTest.php | 2 +- .../EntraPermissionsRegistryTest.php | 12 +- .../EnvironmentReviewAuditLogTest.php} | 50 +- ...ntReviewCanonicalControlReferenceTest.php} | 10 +- .../EnvironmentReviewCreationTest.php} | 18 +- .../EnvironmentReviewCycleTest.php} | 16 +- .../EnvironmentReviewExecutivePackTest.php} | 14 +- ...vironmentReviewExplanationSurfaceTest.php} | 16 +- ...vironmentReviewExportOperationsUxTest.php} | 14 +- .../EnvironmentReviewLifecycleTest.php} | 50 +- .../EnvironmentReviewOperationsUxTest.php} | 16 +- .../EnvironmentReviewRbacTest.php} | 22 +- ...nvironmentReviewRegisterPrefilterTest.php} | 12 +- .../EnvironmentReviewRegisterRbacTest.php} | 10 +- .../EnvironmentReviewRegisterTest.php} | 32 +- .../EnvironmentReviewUiContractTest.php} | 84 +-- .../Evidence/EvidenceSnapshotResourceTest.php | 2 +- ...eEnvironmentWhenWorkspaceSelectedTest.php} | 0 ...rfacesRedirectToChooseEnvironmentTest.php} | 2 +- .../Filament/ArchivedTenantViewTest.php | 4 +- .../ArtifactSourceTaxonomySurfaceTest.php | 8 +- .../BaselineCompareCoverageBannerTest.php | 2 +- .../BaselineCompareSummaryConsistencyTest.php | 2 +- ...BaselineProfileCaptureStartSurfaceTest.php | 10 +- ...BaselineProfileCompareStartSurfaceTest.php | 10 +- ...yStateRegisterTenantCtaVisibilityTest.php} | 4 +- ...hooseEnvironmentIsWorkspaceScopedTest.php} | 4 +- ...hooseEnvironmentRequiresWorkspaceTest.php} | 4 +- .../Filament/CreateCtaPlacementTest.php | 12 +- .../EditTenantHeaderDisciplineTest.php | 6 +- .../EnvironmentContextSurfaceCopyTest.php | 4 +- ...EnvironmentReviewHeaderDisciplineTest.php} | 36 +- ...anceArtifactAdminPanelRegistrationTest.php | 8 +- ...GovernanceArtifactDeepLinkContractTest.php | 14 +- ...vernanceArtifactEnvironmentContextTest.php | 18 +- ...anceArtifactLegacyTenantPanelGuardTest.php | 16 +- .../Feature/Filament/HousekeepingTest.php | 8 +- ...edEnvironmentAccessScopeManagementTest.php | 16 +- ...nagedEnvironmentsLandingLifecycleTest.php} | 10 +- .../RecentOperationsSummaryWidgetTest.php | 2 +- .../TenantWorkspaceRemovalTest.php | 8 +- ...iewRegisterDerivedStateMemoizationTest.php | 20 +- ...ctEnvironmentPostPersistsLastUsedTest.php} | 6 +- ...edVerificationReportFamilyContractTest.php | 8 +- .../TableStandardsCriticalListsTest.php | 4 +- .../Filament/TableStatePersistenceTest.php | 4 +- .../TenantActionsAuthorizationTest.php | 34 +- ...DashboardArrivalContextPerformanceTest.php | 4 +- .../TenantDashboardArrivalContextTest.php | 28 +- .../Filament/TenantDashboardDbOnlyTest.php | 6 +- .../TenantDashboardTenantScopeTest.php | 6 +- .../Filament/TenantDiagnosticsRepairsTest.php | 10 +- .../TenantGlobalSearchLifecycleScopeTest.php | 10 +- ...lePresentationAcrossTenantSurfacesTest.php | 8 +- ...antLifecycleStatusDomainSeparationTest.php | 4 +- .../Filament/TenantMakeCurrentTest.php | 10 +- .../TenantMembersDbOnlyRenderTest.php | 8 +- .../Feature/Filament/TenantMembersTest.php | 20 +- .../TenantPortfolioContextSwitchTest.php | 12 +- .../Feature/Filament/TenantRbacWizardTest.php | 24 +- .../TenantRegistryArrivalContextTest.php | 10 +- .../TenantRegistryRecoveryTriageTest.php | 22 +- .../TenantRegistryTriageReviewStateTest.php | 42 +- .../TenantRequiredPermissionsPageTest.php | 16 +- ...nantResourceIndexIsWorkspaceScopedTest.php | 10 +- ...enantRoleDefinitionsSelectorDbOnlyTest.php | 6 +- .../Feature/Filament/TenantScopingTest.php | 4 +- .../Feature/Filament/TenantSetupTest.php | 14 +- .../TenantSwitcherUrlResolvesTenantTest.php | 4 +- .../TenantTruthCleanupSpec179Test.php | 12 +- .../TenantVerificationReportWidgetTest.php | 26 +- .../TenantViewHeaderUiEnforcementTest.php | 18 +- ...aceContextTopbarAndTenantSelectionTest.php | 2 +- ...spaceOnlySurfaceTenantIndependenceTest.php | 6 +- .../WorkspaceOverviewAuthorizationTest.php | 10 +- .../Filament/WorkspaceOverviewContentTest.php | 10 +- ...rkspaceOverviewDrilldownContinuityTest.php | 14 +- ...kspaceOverviewPermissionVisibilityTest.php | 6 +- .../WorkspaceOverviewSummaryMetricsTest.php | 10 +- ...kspaceOverviewTriageReviewProgressTest.php | 8 +- .../Findings/FindingExceptionRegisterTest.php | 4 +- .../FindingOutcomeSummaryReportingTest.php | 8 +- .../Findings/FindingsListEnterpriseUxTest.php | 2 +- .../Feature/Findings/MyWorkInboxTest.php | 2 +- .../Governance/GovernanceInboxPageTest.php | 8 +- .../Guards/ActionSurfaceContractTest.php | 140 ++--- .../Guards/ActionSurfaceValidatorTest.php | 4 +- .../Guards/AdminTenantResolverGuardTest.php | 14 +- .../Guards/ConfidenceLaneContractTest.php | 2 +- ...EnvironmentCopyNeutralizationGuardTest.php | 10 +- .../FilamentTableStandardsGuardTest.php | 32 +- .../HeavyGovernanceLaneContractTest.php | 2 +- .../Guards/LivewireTrustedStateGuardTest.php | 4 +- ...dEnvironmentCanonicalRouteContractTest.php | 14 +- .../NoActiveTenantResourceRoutesTest.php | 15 +- .../NoAdHocFilamentAuthPatternsTest.php | 8 +- ...oAdHocTenantLifecycleChecksSpec143Test.php | 10 +- ...acyProviderConnectionStateFallbackTest.php | 2 +- .../NoLegacyTenantProviderFallbackTest.php | 4 +- .../NoPlatformCredentialFallbackTest.php | 8 +- ...enantCredentialRuntimeReadsSpec081Test.php | 2 +- .../OperationLifecycleOpsUxGuardTest.php | 2 +- .../OperationRunLinkContractGuardTest.php | 4 +- .../Guards/ProfileLaneContractTest.php | 2 +- .../ProviderConnectionNeutralityGuardTest.php | 2 +- .../ProviderDispatchGateCoverageTest.php | 4 +- .../SharedDetailFamilyContractGuardTest.php | 4 +- ...192RecordPageHeaderDisciplineGuardTest.php | 32 +- ...193MonitoringSurfaceHierarchyGuardTest.php | 16 +- ...c194GovernanceActionSemanticsGuardTest.php | 8 +- ...5ResidualActionSurfaceClosureGuardTest.php | 12 +- ...Spec288NoLegacyRouteAndHelperGuardTest.php | 2 +- ...8ProviderCoreAndRoleAuthorityGuardTest.php | 4 +- .../Guards/TestTaxonomyPlacementGuardTest.php | 4 +- .../Hardening/TenantRbacCardRenderTest.php | 10 +- .../CustomerReviewSurfaceLocalizationTest.php | 28 +- .../EnvironmentContextTerminologyTest.php | 4 +- .../LegacyTenantCoreGuardTest.php | 44 +- .../ManagedEnvironmentPanelContextTest.php | 14 +- .../ManagedEnvironmentRouteBindingTest.php | 24 +- ...anagedEnvironmentOnboardingWizardTest.php} | 212 +++---- .../AuthorizationSemanticsTest.php | 9 +- .../OnboardingRedirectTest.php | 0 .../ArtifactTruthManualCasesDataset.php | 6 +- .../Monitoring/ArtifactTruthRunDetailTest.php | 2 +- .../AuditCoverageGovernanceTest.php | 4 +- .../GovernanceOperationRunSummariesTest.php | 2 +- .../GovernanceRunExplanationFallbackTest.php | 2 +- .../Monitoring/HeaderContextBarTest.php | 4 +- .../OperationRunNotificationTest.php | 4 +- ...ironmentLifecyclePresentationCopyTest.php} | 14 +- ...ronmentOnboardingCapabilityAssistTest.php} | 2 +- ...dEnvironmentOnboardingEntitlementTest.php} | 22 +- ...OnboardingProviderConnectionScopeTest.php} | 8 +- .../Onboarding/OnboardingActivationTest.php | 32 +- .../Onboarding/OnboardingDraftAccessTest.php | 18 +- .../OnboardingDraftAuthorizationTest.php | 48 +- .../OnboardingDraftLifecycleTest.php | 56 +- .../OnboardingDraftMultiTabTest.php | 8 +- .../Onboarding/OnboardingDraftPickerTest.php | 26 +- .../Onboarding/OnboardingDraftRoutingTest.php | 22 +- .../Onboarding/OnboardingFoundationsTest.php | 32 +- ... => OnboardingIdentifyEnvironmentTest.php} | 16 +- .../OnboardingInlineConnectionEditTest.php | 36 +- ...gProviderConnectionPlatformDefaultTest.php | 10 +- .../OnboardingProviderConnectionTest.php | 28 +- .../OnboardingRbacSemanticsTest.php | 8 +- .../Onboarding/OnboardingSecretSafetyTest.php | 12 +- .../OnboardingVerificationAssistTest.php | 18 +- .../OnboardingVerificationClustersTest.php | 16 +- .../Onboarding/OnboardingVerificationTest.php | 54 +- .../OnboardingVerificationV1_5UxTest.php | 10 +- .../ProductKnowledgeOnboardingHelpTest.php | 6 +- .../ProductTelemetryOnboardingCaptureTest.php | 8 +- .../OpsUx/ActivityFeedbackSurfaceTest.php | 4 +- .../Feature/OpsUx/OperateHubShellTest.php | 16 +- ...ssEnvironmentCompareAuthorizationTest.php} | 30 +- ...ssEnvironmentCompareLaunchContextTest.php} | 126 ++-- ...hp => CrossEnvironmentComparePageTest.php} | 54 +- ...vironmentPromotionExecutionActionTest.php} | 34 +- ...nvironmentPromotionExecutionAuditTest.php} | 38 +- ...ntPromotionExecutionAuthorizationTest.php} | 90 +-- ...nvironmentPromotionExecutionRunUxTest.php} | 20 +- ...nvironmentPromotionPreflightAuditTest.php} | 22 +- ...nectionViewsDbOnlyRenderingSpec081Test.php | 4 +- ...derOperationBlockedGuidanceSpec081Test.php | 4 +- .../ProviderCapabilityEvaluationTest.php | 8 +- .../AdminGlobalSearchContextSafetyTest.php | 12 +- ...DashboardRecoveryPostureVisibilityTest.php | 6 +- .../EditTenantArchiveUiEnforcementTest.php | 10 +- ...tifactsWorkspaceFirstAuthorizationTest.php | 10 +- .../OnboardingWizardUiEnforcementTest.php | 24 +- ...tionRunWorkspaceFirstAuthorizationTest.php | 2 +- .../TenantActionSurfaceConsistencyTest.php | 64 +- .../Rbac/TenantAdminAuthorizationTest.php | 4 +- ...tDashboardArrivalContextVisibilityTest.php | 4 +- .../Rbac/TenantLifecycleActionNamingTest.php | 24 +- .../TenantLifecycleActionVisibilityTest.php | 46 +- ...rshipsRelationManagerUiEnforcementTest.php | 8 +- ...antRequiredPermissionsTrustedStateTest.php | 10 +- .../Rbac/TenantResourceAuthorizationTest.php | 48 +- .../TriageReviewStateAuthorizationTest.php | 20 +- .../Rbac/UiEnforcementNonMemberHiddenTest.php | 4 +- .../GovernanceReasonPresentationTest.php | 4 +- .../ProductTelemetryReportCaptureTest.php | 2 +- .../RequiredPermissionsEmptyStateTest.php | 4 +- .../RequiredPermissionsFiltersTest.php | 20 +- .../RequiredPermissionsLinksTest.php | 4 +- .../RequiredPermissionsOverviewTest.php | 4 +- .../RequiredPermissionsSidebarTest.php | 6 +- ...nvironmentReviewDerivedReviewPackTest.php} | 10 +- .../ReviewPackEntitlementEnforcementTest.php | 14 +- .../ReviewPack/ReviewPackGenerationTest.php | 10 +- .../ReviewPackRedactionIntegrityTest.php | 5 +- .../ReviewPack/ReviewPackResourceTest.php | 15 +- .../ReviewPackValidRiskAcceptanceTest.php | 5 +- .../ReviewPack/ReviewPackWidgetTest.php | 22 +- ...stomerReviewWorkspaceAuthorizationTest.php | 2 +- ...CustomerReviewWorkspaceLaunchLinksTest.php | 56 +- ...erReviewWorkspaceNavigationContextTest.php | 12 +- .../CustomerReviewWorkspacePackAccessTest.php | 56 +- .../CustomerReviewWorkspacePageTest.php | 92 +-- ...rkspaceManagedTenantAdminMigrationTest.php | 12 +- .../Spec085/DenyAsNotFoundSemanticsTest.php | 4 +- .../Spec085/OperationsIndexHeaderTest.php | 6 +- ...enantNavigationMonitoringShortcutsTest.php | 4 +- ...perationRunSupportDiagnosticActionTest.php | 6 +- .../ProductKnowledgeAuthorizationTest.php | 6 +- ...ductKnowledgeSupportDiagnosticHelpTest.php | 4 +- ...TelemetrySupportDiagnosticsCaptureTest.php | 4 +- .../SupportDiagnosticAuditTest.php | 4 +- .../SupportDiagnosticAuthorizationTest.php | 6 +- .../TenantSupportDiagnosticActionTest.php | 16 +- .../SupportRequestAuditTest.php | 4 +- .../SupportRequestAuthorizationTest.php | 4 +- ...SupportRequestExternalHandoffAuditTest.php | 4 +- ...equestExternalHandoffAuthorizationTest.php | 4 +- .../TenantSupportRequestActionTest.php | 6 +- ...enantSupportRequestExternalHandoffTest.php | 4 +- .../NoAdHocTelemetryBypassTest.php | 4 +- .../ProductTelemetryDashboardWidgetTest.php | 4 +- .../System/Spec114/OpsFailuresViewTest.php | 4 +- .../ArchivedTenantRouteAccessTest.php | 20 +- .../Feature/TenantRBAC/LastOwnerGuardTest.php | 6 +- .../TenantRBAC/MembershipAuditLogTest.php | 4 +- .../TenantDiagnosticsAccessTest.php | 4 +- .../TenantGuidVsBigintGuardTest.php | 4 +- .../TenantRBAC/TenantMembershipCrudTest.php | 4 +- .../TenantRouteDenyAsNotFoundTest.php | 4 +- .../TenantRBAC/TenantSwitcherScopeTest.php | 22 +- .../TenantProviderBackedActionStartTest.php | 6 +- .../TenantProviderConnectionsCtaTest.php | 26 +- .../IntuneRbacPermissionCoverageTest.php | 4 +- ...rConnectionHealthCheckWritesReportTest.php | 8 +- .../VerificationReportViewerDbOnlyTest.php | 4 +- .../VerificationStartDedupeTest.php | 4 +- .../TenantOwnedWorkspaceInvariantTest.php | 4 +- .../WorkspaceIdForeignKeyConstraintTest.php | 2 +- ...Test.php => ChooseEnvironmentPageTest.php} | 20 +- ...spaceRedirectsToChooseEnvironmentTest.php} | 12 +- .../EnsureWorkspaceSelectedMiddlewareTest.php | 8 +- .../GlobalContextShellContractTest.php | 6 +- ...nvironmentOnboardingProviderStartTest.php} | 14 +- ...ManagedEnvironmentsLivewireUpdateTest.php} | 2 +- ...nagedEnvironmentsWorkspaceRoutingTest.php} | 8 +- ...hp => SelectEnvironmentControllerTest.php} | 14 +- ...Spec195ManagedEnvironmentsLandingTest.php} | 24 +- .../SwitchWorkspaceControllerTest.php | 4 +- .../WorkspaceRedirectResolverTest.php | 4 +- apps/platform/tests/Pest.php | 44 +- .../tests/Support/TestLaneManifest.php | 16 +- .../Unit/Auth/NoRoleStringChecksTest.php | 4 +- .../tests/Unit/Badges/BadgeCatalogTest.php | 2 +- .../Badges/GovernanceArtifactTruthTest.php | 12 +- ...nvironmentTriageReviewStateBadgesTest.php} | 12 +- .../Badges/OperatorOutcomeTaxonomyTest.php | 2 +- .../tests/Unit/Badges/TenantBadgesTest.php | 10 +- .../EnvironmentReviewBadgeTest.php | 28 + .../EnvironmentReviewComposerTest.php} | 30 +- ...nvironmentPermissionCheckClustersTest.php} | 12 +- ...nagedEnvironmentPermissionServiceTest.php} | 40 +- .../OnboardingDraftResolverTest.php | 4 +- .../OnboardingDraftStageResolverTest.php | 10 +- .../OnboardingLifecycleServiceTest.php | 20 +- .../OperationLifecyclePolicyValidatorTest.php | 6 +- .../QueuedExecutionLegitimacyGateTest.php | 6 +- ...nvironmentOnboardingSessionPolicyTest.php} | 10 +- .../ProviderConnectionBadgeMappingTest.php | 8 +- .../ProviderOperationStartGateTest.php | 8 +- .../WorkspaceHealthSummaryQueryTest.php | 4 +- .../GovernanceInboxSectionBuilderTest.php | 10 +- .../OperateHubShellResolutionTest.php | 2 +- .../OperationalControlCatalogTest.php | 2 +- .../OperationRunExplanationTest.php | 2 +- ...ernanceRunDiagnosticSummaryBuilderTest.php | 4 +- .../OperationRunProgressContractTest.php | 6 +- ...sEnvironmentComparePreviewBuilderTest.php} | 54 +- ...ironmentPromotionExecutionPlannerTest.php} | 40 +- ...rossEnvironmentPromotionPreflightTest.php} | 72 +-- ...nvironmentTriageReviewFingerprintTest.php} | 8 +- ...ironmentTriageReviewStateResolverTest.php} | 26 +- .../ProductTelemetryRecorderTest.php | 8 +- .../ProductTelemetrySafeMetadataTest.php | 6 +- .../ProductTelemetrySummaryQueryTest.php | 4 +- .../SupportDiagnosticBundleBuilderTest.php | 4 +- .../RequestScopedDerivedStateStoreTest.php | 24 +- .../CompressedGovernanceOutcomeTest.php | 2 +- ...nantRequiredPermissionsCopyPayloadTest.php | 10 +- ...ntRequiredPermissionsFeatureImpactTest.php | 4 +- ...TenantRequiredPermissionsFilteringTest.php | 18 +- ...TenantRequiredPermissionsFreshnessTest.php | 12 +- ...ntRequiredPermissionsOverallStatusTest.php | 12 +- .../Unit/TenantResourceConsentUrlTest.php | 6 +- .../TenantReview/TenantReviewBadgeTest.php | 28 - .../Tenants/TenantActionPolicySurfaceTest.php | 4 +- .../Unit/Tenants/TenantPageCategoryTest.php | 2 +- .../GovernanceActionCatalogTest.php | 2 +- ...onmentPermissionCapabilityMappingTest.php} | 8 +- ...VerificationAssistViewModelBuilderTest.php | 8 +- ...cationReportSanitizerEvidenceKindsTest.php | 4 +- .../admin-canonical-tenant-rollout.md | 4 +- ...-scoped-derived-state.logical.openapi.yaml | 22 +- .../allowed-tenant-references.md | 58 ++ .../checklists/requirements.md | 56 ++ .../final-tenant-reference-audit.md | 169 ++++++ .../plan.md | 278 +++++++++ .../spec.md | 254 ++++++++ .../tasks.md | 175 ++++++ .../tenant-reference-inventory.md | 129 ++++ 574 files changed, 6178 insertions(+), 4846 deletions(-) rename apps/platform/app/Filament/Pages/{ChooseTenant.php => ChooseEnvironment.php} (95%) rename apps/platform/app/Filament/Pages/{CrossTenantComparePage.php => CrossEnvironmentComparePage.php} (71%) rename apps/platform/app/Filament/Pages/{TenantDashboard.php => EnvironmentDashboard.php} (95%) rename apps/platform/app/Filament/Pages/{TenantDiagnostics.php => EnvironmentDiagnostics.php} (84%) rename apps/platform/app/Filament/Pages/{TenantRequiredPermissions.php => EnvironmentRequiredPermissions.php} (94%) rename apps/platform/app/Filament/Pages/Workspaces/{ManagedTenantOnboardingWizard.php => ManagedEnvironmentOnboardingWizard.php} (91%) rename apps/platform/app/Filament/Pages/Workspaces/{ManagedTenantsLanding.php => ManagedEnvironmentsLanding.php} (92%) rename apps/platform/app/Filament/Resources/{TenantReviewResource.php => EnvironmentReviewResource.php} (84%) create mode 100644 apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ListEnvironmentReviews.php rename apps/platform/app/Filament/Resources/{TenantReviewResource/Pages/ViewTenantReview.php => EnvironmentReviewResource/Pages/ViewEnvironmentReview.php} (85%) rename apps/platform/app/Filament/Resources/{TenantResource.php => ManagedEnvironmentResource.php} (95%) rename apps/platform/app/Filament/Resources/{TenantResource/Pages/EditTenant.php => ManagedEnvironmentResource/Pages/EditManagedEnvironment.php} (64%) rename apps/platform/app/Filament/Resources/{TenantResource/Pages/ListTenants.php => ManagedEnvironmentResource/Pages/ListManagedEnvironments.php} (77%) rename apps/platform/app/Filament/Resources/{TenantResource/Pages/ManageTenantMemberships.php => ManagedEnvironmentResource/Pages/ManageEnvironmentAccessScopes.php} (76%) rename apps/platform/app/Filament/Resources/{TenantResource/Pages/ViewTenant.php => ManagedEnvironmentResource/Pages/ViewManagedEnvironment.php} (72%) rename apps/platform/app/Filament/Resources/{TenantResource/RelationManagers/TenantMembershipsRelationManager.php => ManagedEnvironmentResource/RelationManagers/ManagedEnvironmentMembershipsRelationManager.php} (94%) delete mode 100644 apps/platform/app/Filament/Resources/TenantReviewResource/Pages/ListTenantReviews.php rename apps/platform/app/Filament/Widgets/Dashboard/{TenantDashboardContextChips.php => EnvironmentDashboardContextChips.php} (76%) rename apps/platform/app/Filament/Widgets/Dashboard/{TenantDashboardOverview.php => EnvironmentDashboardOverview.php} (85%) rename apps/platform/app/Filament/Widgets/{Tenant => ManagedEnvironment}/AdminRolesSummaryWidget.php (97%) rename apps/platform/app/Filament/Widgets/{Tenant => ManagedEnvironment}/BaselineCompareCoverageBanner.php (93%) rename apps/platform/app/Filament/Widgets/{Tenant => ManagedEnvironment}/FindingExceptionStatsOverview.php (95%) rename apps/platform/app/Filament/Widgets/{Tenant => ManagedEnvironment}/FindingStatsOverview.php (95%) rename apps/platform/app/Filament/Widgets/{Tenant/TenantArchivedBanner.php => ManagedEnvironment/ManagedEnvironmentArchivedBanner.php} (74%) rename apps/platform/app/Filament/Widgets/{Tenant/TenantReviewPackCard.php => ManagedEnvironment/ManagedEnvironmentReviewPackCard.php} (95%) rename apps/platform/app/Filament/Widgets/{Tenant/TenantTriageArrivalContinuity.php => ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php} (84%) rename apps/platform/app/Filament/Widgets/{Tenant/TenantVerificationReport.php => ManagedEnvironment/ManagedEnvironmentVerificationReport.php} (94%) rename apps/platform/app/Filament/Widgets/{Tenant => ManagedEnvironment}/RecentOperationsSummary.php (93%) rename apps/platform/app/Http/Controllers/{ClearTenantContextController.php => ClearEnvironmentContextController.php} (93%) rename apps/platform/app/Http/Controllers/{TenantOnboardingController.php => ManagedEnvironmentOnboardingController.php} (95%) rename apps/platform/app/Http/Controllers/{SelectTenantController.php => SelectEnvironmentController.php} (98%) rename apps/platform/app/Jobs/{ComposeTenantReviewJob.php => ComposeEnvironmentReviewJob.php} (73%) rename apps/platform/app/Jobs/Operations/{CrossTenantPromotionExecutionJob.php => CrossEnvironmentPromotionExecutionJob.php} (89%) rename apps/platform/app/Models/{TenantReview.php => EnvironmentReview.php} (85%) rename apps/platform/app/Models/{TenantReviewSection.php => EnvironmentReviewSection.php} (79%) rename apps/platform/app/Models/{TenantOnboardingSession.php => ManagedEnvironmentOnboardingSession.php} (93%) rename apps/platform/app/Models/{TenantPermission.php => ManagedEnvironmentPermission.php} (92%) rename apps/platform/app/Models/{TenantTriageReview.php => ManagedEnvironmentTriageReview.php} (98%) rename apps/platform/app/Policies/{TenantReviewPolicy.php => EnvironmentReviewPolicy.php} (70%) rename apps/platform/app/Policies/{TenantOnboardingSessionPolicy.php => ManagedEnvironmentOnboardingSessionPolicy.php} (73%) rename apps/platform/app/Services/Auth/{TenantDiagnosticsService.php => ManagedEnvironmentDiagnosticsService.php} (98%) rename apps/platform/app/Services/Auth/{TenantMembershipManager.php => ManagedEnvironmentMembershipManager.php} (99%) rename apps/platform/app/Services/{TenantReviews/TenantReviewComposer.php => EnvironmentReviews/EnvironmentReviewComposer.php} (95%) rename apps/platform/app/Services/{TenantReviews/TenantReviewFingerprint.php => EnvironmentReviews/EnvironmentReviewFingerprint.php} (94%) rename apps/platform/app/Services/{TenantReviews/TenantReviewLifecycleService.php => EnvironmentReviews/EnvironmentReviewLifecycleService.php} (78%) rename apps/platform/app/Services/{TenantReviews/TenantReviewReadinessGate.php => EnvironmentReviews/EnvironmentReviewReadinessGate.php} (55%) rename apps/platform/app/Services/{TenantReviews/TenantReviewRegisterService.php => EnvironmentReviews/EnvironmentReviewRegisterService.php} (82%) rename apps/platform/app/Services/{TenantReviews/TenantReviewSectionFactory.php => EnvironmentReviews/EnvironmentReviewSectionFactory.php} (94%) rename apps/platform/app/Services/{TenantReviews/TenantReviewService.php => EnvironmentReviews/EnvironmentReviewService.php} (87%) rename apps/platform/app/Services/Intune/{TenantPermissionService.php => ManagedEnvironmentPermissionService.php} (96%) rename apps/platform/app/Services/Intune/{TenantRequiredPermissionsViewModelBuilder.php => ManagedEnvironmentRequiredPermissionsViewModelBuilder.php} (93%) rename apps/platform/app/Services/PortfolioCompare/{CrossTenantPromotionExecutionService.php => CrossEnvironmentPromotionExecutionService.php} (74%) rename apps/platform/app/Services/PortfolioTriage/{TenantTriageReviewService.php => ManagedEnvironmentTriageReviewService.php} (79%) create mode 100644 apps/platform/app/Support/Badges/Domains/EnvironmentReviewCompletenessStateBadge.php create mode 100644 apps/platform/app/Support/Badges/Domains/EnvironmentReviewStatusBadge.php rename apps/platform/app/Support/Badges/Domains/{ManagedTenantOnboardingVerificationStatusBadge.php => ManagedEnvironmentOnboardingVerificationStatusBadge.php} (80%) rename apps/platform/app/Support/Badges/Domains/{TenantPermissionStatusBadge.php => ManagedEnvironmentPermissionStatusBadge.php} (89%) create mode 100644 apps/platform/app/Support/Badges/Domains/ManagedEnvironmentTriageReviewStateBadge.php delete mode 100644 apps/platform/app/Support/Badges/Domains/TenantReviewCompletenessStateBadge.php delete mode 100644 apps/platform/app/Support/Badges/Domains/TenantReviewStatusBadge.php delete mode 100644 apps/platform/app/Support/Badges/Domains/TenantTriageReviewStateBadge.php rename apps/platform/app/Support/{TenantDashboard/TenantDashboardSummary.php => EnvironmentDashboard/EnvironmentDashboardSummary.php} (95%) rename apps/platform/app/Support/{TenantDashboard/TenantDashboardSummaryBuilder.php => EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php} (95%) rename apps/platform/app/Support/{TenantReviewCompletenessState.php => EnvironmentReviewCompletenessState.php} (88%) rename apps/platform/app/Support/{TenantReviewStatus.php => EnvironmentReviewStatus.php} (95%) rename apps/platform/app/Support/PortfolioCompare/{CrossTenantComparePreviewBuilder.php => CrossEnvironmentComparePreviewBuilder.php} (86%) rename apps/platform/app/Support/PortfolioCompare/{CrossTenantCompareSelection.php => CrossEnvironmentCompareSelection.php} (59%) rename apps/platform/app/Support/PortfolioCompare/{CrossTenantPromotionExecutionPlanner.php => CrossEnvironmentPromotionExecutionPlanner.php} (93%) rename apps/platform/app/Support/PortfolioCompare/{CrossTenantPromotionPreflight.php => CrossEnvironmentPromotionPreflight.php} (86%) rename apps/platform/app/Support/PortfolioTriage/{TenantTriageReviewFingerprint.php => ManagedEnvironmentTriageReviewFingerprint.php} (98%) rename apps/platform/app/Support/PortfolioTriage/{TenantTriageReviewStateResolver.php => ManagedEnvironmentTriageReviewStateResolver.php} (88%) rename apps/platform/app/Support/Verification/{TenantPermissionCheckClusters.php => ManagedEnvironmentPermissionCheckClusters.php} (96%) rename apps/platform/database/factories/{TenantReviewFactory.php => EnvironmentReviewFactory.php} (78%) rename apps/platform/database/factories/{TenantReviewSectionFactory.php => EnvironmentReviewSectionFactory.php} (60%) rename apps/platform/database/factories/{TenantOnboardingSessionFactory.php => ManagedEnvironmentOnboardingSessionFactory.php} (93%) rename apps/platform/database/factories/{TenantTriageReviewFactory.php => ManagedEnvironmentTriageReviewFactory.php} (89%) rename apps/platform/database/migrations/{2025_12_11_122423_create_tenant_permissions_table.php => 2025_12_11_122423_create_managed_environment_permissions_table.php} (85%) rename apps/platform/database/migrations/{2026_02_03_090449_create_tenant_onboarding_sessions_table.php => 2026_02_03_090449_create_managed_environment_onboarding_sessions_table.php} (82%) rename apps/platform/database/migrations/{2026_02_03_150001_create_managed_tenant_onboarding_sessions_table.php => 2026_02_03_150001_create_managed_environment_onboarding_sessions_table.php} (81%) rename apps/platform/database/migrations/{2026_02_04_090010_update_tenant_onboarding_sessions_constraints.php => 2026_02_04_090010_update_managed_environment_onboarding_sessions_constraints.php} (65%) rename apps/platform/database/migrations/{2026_02_14_220112_add_workspace_id_to_tenant_permissions_table.php => 2026_02_14_220112_add_workspace_id_to_managed_environment_permissions_table.php} (59%) create mode 100644 apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_environment_onboarding_sessions.php delete mode 100644 apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_tenant_onboarding_sessions.php rename apps/platform/database/migrations/{2026_03_14_000001_add_lifecycle_and_version_to_managed_tenant_onboarding_sessions.php => 2026_03_14_000001_add_lifecycle_and_version_to_managed_environment_onboarding_sessions.php} (78%) rename apps/platform/database/migrations/{2026_03_20_000000_create_tenant_reviews_table.php => 2026_03_20_000000_create_environment_reviews_table.php} (84%) rename apps/platform/database/migrations/{2026_03_20_000100_create_tenant_review_sections_table.php => 2026_03_20_000100_create_environment_review_sections_table.php} (79%) rename apps/platform/database/migrations/{2026_03_20_000200_add_tenant_review_id_to_review_packs_table.php => 2026_03_20_000200_add_environment_review_id_to_review_packs_table.php} (69%) rename apps/platform/database/migrations/{2026_04_10_000003_create_tenant_triage_reviews_table.php => 2026_04_10_000003_create_managed_environment_triage_reviews_table.php} (65%) rename apps/platform/resources/views/filament/forms/components/{managed-tenant-onboarding-verification-report.blade.php => managed-environment-onboarding-verification-report.blade.php} (99%) rename apps/platform/resources/views/filament/infolists/entries/{tenant-review-section.blade.php => environment-review-section.blade.php} (100%) rename apps/platform/resources/views/filament/infolists/entries/{tenant-review-summary.blade.php => environment-review-summary.blade.php} (100%) rename apps/platform/resources/views/filament/pages/{choose-tenant.blade.php => choose-environment.blade.php} (97%) rename apps/platform/resources/views/filament/pages/{cross-tenant-compare.blade.php => cross-environment-compare.blade.php} (86%) rename apps/platform/resources/views/filament/pages/{tenant-diagnostics.blade.php => environment-diagnostics.blade.php} (100%) rename apps/platform/resources/views/filament/pages/{tenant-required-permissions.blade.php => environment-required-permissions.blade.php} (100%) rename apps/platform/resources/views/filament/pages/workspaces/{managed-tenant-onboarding-wizard.blade.php => managed-environment-onboarding-wizard.blade.php} (100%) rename apps/platform/resources/views/filament/pages/workspaces/{managed-tenants-landing.blade.php => managed-environments-landing.blade.php} (99%) rename apps/platform/resources/views/filament/schemas/components/{managed-tenant-onboarding-checkpoint-poll.blade.php => managed-environment-onboarding-checkpoint-poll.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/dashboard/{tenant-dashboard-context-chips.blade.php => environment-dashboard-context-chips.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/dashboard/{tenant-dashboard-overview.blade.php => environment-dashboard-overview.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/{tenant => managed-environment}/admin-roles-summary.blade.php (100%) rename apps/platform/resources/views/filament/widgets/{tenant => managed-environment}/baseline-compare-coverage-banner.blade.php (100%) rename apps/platform/resources/views/filament/widgets/{tenant/tenant-archived-banner.blade.php => managed-environment/managed-environment-archived-banner.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/{tenant/tenant-review-pack-card.blade.php => managed-environment/managed-environment-review-pack-card.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/{tenant/tenant-verification-report.blade.php => managed-environment/managed-environment-verification-report.blade.php} (100%) rename apps/platform/resources/views/filament/widgets/{tenant => managed-environment}/recent-operations-summary.blade.php (100%) rename apps/platform/resources/views/filament/widgets/{tenant => managed-environment}/triage-arrival-continuity.blade.php (96%) rename apps/platform/tests/Browser/PortfolioCompare/{CrossTenantPromotionExecutionSmokeTest.php => CrossEnvironmentPromotionExecutionSmokeTest.php} (79%) create mode 100644 apps/platform/tests/Browser/Spec300ManagedEnvironmentNamingConsolidationSmokeTest.php rename apps/platform/tests/Feature/{TenantReview/TenantReviewAuditLogTest.php => EnvironmentReview/EnvironmentReviewAuditLogTest.php} (68%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewCanonicalControlReferenceTest.php => EnvironmentReview/EnvironmentReviewCanonicalControlReferenceTest.php} (86%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewCreationTest.php => EnvironmentReview/EnvironmentReviewCreationTest.php} (72%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewCycleTest.php => EnvironmentReview/EnvironmentReviewCycleTest.php} (59%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewExecutivePackTest.php => EnvironmentReview/EnvironmentReviewExecutivePackTest.php} (87%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewExplanationSurfaceTest.php => EnvironmentReview/EnvironmentReviewExplanationSurfaceTest.php} (88%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewExportOperationsUxTest.php => EnvironmentReview/EnvironmentReviewExportOperationsUxTest.php} (82%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewLifecycleTest.php => EnvironmentReview/EnvironmentReviewLifecycleTest.php} (66%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewOperationsUxTest.php => EnvironmentReview/EnvironmentReviewOperationsUxTest.php} (69%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewRbacTest.php => EnvironmentReview/EnvironmentReviewRbacTest.php} (62%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewRegisterPrefilterTest.php => EnvironmentReview/EnvironmentReviewRegisterPrefilterTest.php} (93%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewRegisterRbacTest.php => EnvironmentReview/EnvironmentReviewRegisterRbacTest.php} (89%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewRegisterTest.php => EnvironmentReview/EnvironmentReviewRegisterTest.php} (82%) rename apps/platform/tests/Feature/{TenantReview/TenantReviewUiContractTest.php => EnvironmentReview/EnvironmentReviewUiContractTest.php} (72%) rename apps/platform/tests/Feature/Filament/{AdminHomeRedirectsToChooseTenantWhenWorkspaceSelectedTest.php => AdminHomeRedirectsToChooseEnvironmentWhenWorkspaceSelectedTest.php} (100%) rename apps/platform/tests/Feature/Filament/{AdminTenantScopedSurfacesRedirectToChooseTenantTest.php => AdminTenantScopedSurfacesRedirectToChooseEnvironmentTest.php} (99%) rename apps/platform/tests/Feature/Filament/{ChooseTenantEmptyStateRegisterTenantCtaVisibilityTest.php => ChooseEnvironmentEmptyStateRegisterTenantCtaVisibilityTest.php} (95%) rename apps/platform/tests/Feature/Filament/{ChooseTenantIsWorkspaceScopedTest.php => ChooseEnvironmentIsWorkspaceScopedTest.php} (96%) rename apps/platform/tests/Feature/Filament/{ChooseTenantRequiresWorkspaceTest.php => ChooseEnvironmentRequiresWorkspaceTest.php} (84%) rename apps/platform/tests/Feature/Filament/{TenantReviewHeaderDisciplineTest.php => EnvironmentReviewHeaderDisciplineTest.php} (57%) rename apps/platform/tests/Feature/Filament/{ManagedTenantsLandingLifecycleTest.php => ManagedEnvironmentsLandingLifecycleTest.php} (93%) rename apps/platform/tests/Feature/Filament/{SelectTenantPostPersistsLastUsedTest.php => SelectEnvironmentPostPersistsLastUsedTest.php} (88%) rename apps/platform/tests/Feature/{ManagedTenantOnboardingWizardTest.php => ManagedEnvironmentOnboardingWizardTest.php} (91%) rename apps/platform/tests/Feature/{ManagedTenants => ManagedEnvironments}/AuthorizationSemanticsTest.php (92%) rename apps/platform/tests/Feature/{ManagedTenants => ManagedEnvironments}/OnboardingRedirectTest.php (100%) rename apps/platform/tests/Feature/Onboarding/{TenantLifecyclePresentationCopyTest.php => EnvironmentLifecyclePresentationCopyTest.php} (79%) rename apps/platform/tests/Feature/Onboarding/{ManagedTenantOnboardingCapabilityAssistTest.php => ManagedEnvironmentOnboardingCapabilityAssistTest.php} (94%) rename apps/platform/tests/Feature/Onboarding/{ManagedTenantOnboardingEntitlementTest.php => ManagedEnvironmentOnboardingEntitlementTest.php} (93%) rename apps/platform/tests/Feature/Onboarding/{ManagedTenantOnboardingProviderConnectionScopeTest.php => ManagedEnvironmentOnboardingProviderConnectionScopeTest.php} (88%) rename apps/platform/tests/Feature/Onboarding/{OnboardingIdentifyTenantTest.php => OnboardingIdentifyEnvironmentTest.php} (85%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantCompareAuthorizationTest.php => CrossEnvironmentCompareAuthorizationTest.php} (73%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantCompareLaunchContextTest.php => CrossEnvironmentCompareLaunchContextTest.php} (63%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantComparePageTest.php => CrossEnvironmentComparePageTest.php} (59%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantPromotionExecutionActionTest.php => CrossEnvironmentPromotionExecutionActionTest.php} (77%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantPromotionExecutionAuditTest.php => CrossEnvironmentPromotionExecutionAuditTest.php} (77%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantPromotionExecutionAuthorizationTest.php => CrossEnvironmentPromotionExecutionAuthorizationTest.php} (63%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantPromotionExecutionRunUxTest.php => CrossEnvironmentPromotionExecutionRunUxTest.php} (72%) rename apps/platform/tests/Feature/PortfolioCompare/{CrossTenantPromotionPreflightAuditTest.php => CrossEnvironmentPromotionPreflightAuditTest.php} (67%) rename apps/platform/tests/Feature/ReviewPack/{TenantReviewDerivedReviewPackTest.php => EnvironmentReviewDerivedReviewPackTest.php} (88%) rename apps/platform/tests/Feature/Workspaces/{ChooseTenantPageTest.php => ChooseEnvironmentPageTest.php} (91%) rename apps/platform/tests/Feature/Workspaces/{ChooseWorkspaceRedirectsToChooseTenantTest.php => ChooseWorkspaceRedirectsToChooseEnvironmentTest.php} (87%) rename apps/platform/tests/Feature/Workspaces/{ManagedTenantOnboardingProviderStartTest.php => ManagedEnvironmentOnboardingProviderStartTest.php} (92%) rename apps/platform/tests/Feature/Workspaces/{ManagedTenantsLivewireUpdateTest.php => ManagedEnvironmentsLivewireUpdateTest.php} (96%) rename apps/platform/tests/Feature/Workspaces/{ManagedTenantsWorkspaceRoutingTest.php => ManagedEnvironmentsWorkspaceRoutingTest.php} (94%) rename apps/platform/tests/Feature/Workspaces/{SelectTenantControllerTest.php => SelectEnvironmentControllerTest.php} (92%) rename apps/platform/tests/Feature/Workspaces/{Spec195ManagedTenantsLandingTest.php => Spec195ManagedEnvironmentsLandingTest.php} (80%) rename apps/platform/tests/Unit/Badges/{TenantTriageReviewStateBadgesTest.php => ManagedEnvironmentTriageReviewStateBadgesTest.php} (52%) create mode 100644 apps/platform/tests/Unit/EnvironmentReview/EnvironmentReviewBadgeTest.php rename apps/platform/tests/Unit/{TenantReview/TenantReviewComposerTest.php => EnvironmentReview/EnvironmentReviewComposerTest.php} (75%) rename apps/platform/tests/Unit/{TenantPermissionCheckClustersTest.php => ManagedEnvironmentPermissionCheckClustersTest.php} (90%) rename apps/platform/tests/Unit/{TenantPermissionServiceTest.php => ManagedEnvironmentPermissionServiceTest.php} (80%) rename apps/platform/tests/Unit/Policies/{TenantOnboardingSessionPolicyTest.php => ManagedEnvironmentOnboardingSessionPolicyTest.php} (89%) rename apps/platform/tests/Unit/Support/PortfolioCompare/{CrossTenantComparePreviewBuilderTest.php => CrossEnvironmentComparePreviewBuilderTest.php} (76%) rename apps/platform/tests/Unit/Support/PortfolioCompare/{CrossTenantPromotionExecutionPlannerTest.php => CrossEnvironmentPromotionExecutionPlannerTest.php} (75%) rename apps/platform/tests/Unit/Support/PortfolioCompare/{CrossTenantPromotionPreflightTest.php => CrossEnvironmentPromotionPreflightTest.php} (73%) rename apps/platform/tests/Unit/Support/PortfolioTriage/{TenantTriageReviewFingerprintTest.php => ManagedEnvironmentTriageReviewFingerprintTest.php} (94%) rename apps/platform/tests/Unit/Support/PortfolioTriage/{TenantTriageReviewStateResolverTest.php => ManagedEnvironmentTriageReviewStateResolverTest.php} (88%) delete mode 100644 apps/platform/tests/Unit/TenantReview/TenantReviewBadgeTest.php rename apps/platform/tests/Unit/Verification/{TenantPermissionCapabilityMappingTest.php => ManagedEnvironmentPermissionCapabilityMappingTest.php} (65%) create mode 100644 specs/300-internal-tenant-model-naming-consolidation/allowed-tenant-references.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/checklists/requirements.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/final-tenant-reference-audit.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/plan.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/spec.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/tasks.md create mode 100644 specs/300-internal-tenant-model-naming-consolidation/tenant-reference-inventory.md diff --git a/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php b/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php index 1f7048a1..17fb6d75 100644 --- a/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php +++ b/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php @@ -40,8 +40,9 @@ public static function getUrl(?string $name = null, array $parameters = [], bool return url('/admin'); } - $parameters['tenant'] ??= $resolvedTenant; + $parameters['environment'] ??= $resolvedTenant; $parameters['workspace'] ??= $workspace; + unset($parameters['tenant']); return parent::getUrl($name, $parameters, $isAbsolute, $panelId, null, $shouldGuessMissingParameters); } @@ -52,7 +53,7 @@ protected static function workspaceScopedSlug(string $slug, ?Panel $panel = null return $slug; } - $prefix = 'workspaces/{workspace}/environments/{tenant}/'; + $prefix = 'workspaces/{workspace}/environments/{environment}/'; return str_starts_with($slug, $prefix) ? $slug @@ -148,4 +149,4 @@ protected static function workspaceScopedTenantRelationshipName(): string ? $relationshipName : 'tenant'; } -} \ No newline at end of file +} diff --git a/apps/platform/app/Filament/Pages/ChooseTenant.php b/apps/platform/app/Filament/Pages/ChooseEnvironment.php similarity index 95% rename from apps/platform/app/Filament/Pages/ChooseTenant.php rename to apps/platform/app/Filament/Pages/ChooseEnvironment.php index 3bfa1f8f..7a5ad6a6 100644 --- a/apps/platform/app/Filament/Pages/ChooseTenant.php +++ b/apps/platform/app/Filament/Pages/ChooseEnvironment.php @@ -18,7 +18,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\Schema; -class ChooseTenant extends Page +class ChooseEnvironment extends Page { protected static string $layout = 'filament-panels::components.layout.simple'; @@ -26,9 +26,9 @@ class ChooseTenant extends Page protected static bool $isDiscovered = false; - protected static ?string $slug = 'choose-tenant'; + protected static ?string $slug = 'choose-environment'; - protected string $view = 'filament.pages.choose-tenant'; + protected string $view = 'filament.pages.choose-environment'; public function getTitle(): string { @@ -66,7 +66,7 @@ public function getTenants(): Collection return app(TenantOperabilityService::class)->filterSelectable(collect($tenants)); } - public function selectTenant(int $tenantId): void + public function selectEnvironment(int $tenantId): void { $user = auth()->user(); diff --git a/apps/platform/app/Filament/Pages/CrossTenantComparePage.php b/apps/platform/app/Filament/Pages/CrossEnvironmentComparePage.php similarity index 71% rename from apps/platform/app/Filament/Pages/CrossTenantComparePage.php rename to apps/platform/app/Filament/Pages/CrossEnvironmentComparePage.php index 4558695f..37459a95 100644 --- a/apps/platform/app/Filament/Pages/CrossTenantComparePage.php +++ b/apps/platform/app/Filament/Pages/CrossEnvironmentComparePage.php @@ -11,7 +11,7 @@ use App\Services\Audit\WorkspaceAuditLogger; use App\Services\Auth\CapabilityResolver; use App\Services\Auth\WorkspaceCapabilityResolver; -use App\Services\PortfolioCompare\CrossTenantPromotionExecutionService; +use App\Services\PortfolioCompare\CrossEnvironmentPromotionExecutionService; use App\Support\Auth\Capabilities; use App\Support\ManagedEnvironmentLinks; use App\Support\Navigation\CanonicalNavigationContext; @@ -19,9 +19,9 @@ use App\Support\OperationRunLinks; use App\Support\OpsUx\OpsUxBrowserEvents; use App\Support\OpsUx\ProviderOperationStartResultPresenter; -use App\Support\PortfolioCompare\CrossTenantComparePreviewBuilder; -use App\Support\PortfolioCompare\CrossTenantCompareSelection; -use App\Support\PortfolioCompare\CrossTenantPromotionPreflight; +use App\Support\PortfolioCompare\CrossEnvironmentComparePreviewBuilder; +use App\Support\PortfolioCompare\CrossEnvironmentCompareSelection; +use App\Support\PortfolioCompare\CrossEnvironmentPromotionPreflight; use App\Support\Rbac\WorkspaceUiEnforcement; use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile; @@ -42,13 +42,13 @@ use Illuminate\Support\Str; use UnitEnum; -class CrossTenantComparePage extends Page implements HasForms +class CrossEnvironmentComparePage extends Page implements HasForms { use InteractsWithForms; - private const string SOURCE_TENANT_QUERY_KEY = 'source_tenant_id'; + private const string SOURCE_ENVIRONMENT_QUERY_KEY = 'source_environment_id'; - private const string TARGET_TENANT_QUERY_KEY = 'target_tenant_id'; + private const string TARGET_ENVIRONMENT_QUERY_KEY = 'target_environment_id'; private const string POLICY_TYPE_QUERY_KEY = 'policy_type'; @@ -60,15 +60,15 @@ class CrossTenantComparePage extends Page implements HasForms protected static string|UnitEnum|null $navigationGroup = 'Governance'; - protected static ?string $title = 'Cross-ManagedEnvironment Compare'; + protected static ?string $title = 'Cross-environment compare'; - protected static ?string $slug = 'cross-tenant-compare'; + protected static ?string $slug = 'cross-environment-compare'; - protected string $view = 'filament.pages.cross-tenant-compare'; + protected string $view = 'filament.pages.cross-environment-compare'; - public ?string $sourceTenantId = null; + public ?string $sourceEnvironmentId = null; - public ?string $targetTenantId = null; + public ?string $targetEnvironmentId = null; /** * @var list @@ -95,12 +95,12 @@ class CrossTenantComparePage extends Page implements HasForms public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration { return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::ListOnlyReadOnly) - ->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions preserve return navigation, tenant drill-downs, and one dominant promotion-preflight action.') + ->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions preserve return navigation, environment drill-downs, and one dominant promotion-preflight action.') ->exempt(ActionSurfaceSlot::InspectAffordance, 'The compare page uses explicit selection controls instead of row-click inspection.') - ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Cross-tenant compare renders focused subject summaries instead of row-level overflow actions.') + ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Cross-environment compare renders focused subject summaries instead of row-level overflow actions.') ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'The compare page has no bulk actions.') ->satisfy(ActionSurfaceSlot::ListEmptyState, 'The compare page explains when a selection is incomplete or invalid before any preview exists.') - ->exempt(ActionSurfaceSlot::DetailHeader, 'Cross-tenant compare is a workspace decision page, not a record detail header.'); + ->exempt(ActionSurfaceSlot::DetailHeader, 'Cross-environment compare is a workspace decision page, not a record detail header.'); } public function mount(): void @@ -124,24 +124,24 @@ public function form(Schema $schema): Schema 'xl' => 3, ]) ->schema([ - Select::make('sourceTenantId') - ->label('Source tenant') - ->options(fn (): array => $this->tenantOptions()) + Select::make('sourceEnvironmentId') + ->label('Source environment') + ->options(fn (): array => $this->environmentOptions()) ->searchable() ->preload() ->native(false) - ->placeholder('Select a source tenant') - ->extraFieldWrapperAttributes(['data-testid' => 'cross-tenant-source']) - ->extraInputAttributes(['data-testid' => 'cross-tenant-source']), - Select::make('targetTenantId') - ->label('Target tenant') - ->options(fn (): array => $this->tenantOptions()) + ->placeholder('Select a source environment') + ->extraFieldWrapperAttributes(['data-testid' => 'cross-environment-source']) + ->extraInputAttributes(['data-testid' => 'cross-environment-source']), + Select::make('targetEnvironmentId') + ->label('Target environment') + ->options(fn (): array => $this->environmentOptions()) ->searchable() ->preload() ->native(false) - ->placeholder('Select a target tenant') - ->extraFieldWrapperAttributes(['data-testid' => 'cross-tenant-target']) - ->extraInputAttributes(['data-testid' => 'cross-tenant-target']), + ->placeholder('Select a target environment') + ->extraFieldWrapperAttributes(['data-testid' => 'cross-environment-target']) + ->extraInputAttributes(['data-testid' => 'cross-environment-target']), Select::make('selectedPolicyTypes') ->label('Governed subjects') ->options(fn (): array => $this->policyTypeOptions()) @@ -151,10 +151,10 @@ public function form(Schema $schema): Schema ->native(false) ->placeholder('All governed subjects') ->helperText(fn (): ?string => $this->policyTypeOptions() === [] - ? 'Governed subject filters appear after authorized tenant inventory exists in the active workspace.' + ? 'Governed subject filters appear after authorized environment inventory exists in the active workspace.' : null) - ->extraFieldWrapperAttributes(['data-testid' => 'cross-tenant-policy-types']) - ->extraInputAttributes(['data-testid' => 'cross-tenant-policy-types']), + ->extraFieldWrapperAttributes(['data-testid' => 'cross-environment-policy-types']) + ->extraInputAttributes(['data-testid' => 'cross-environment-policy-types']), ]), ]); } @@ -176,24 +176,24 @@ protected function getHeaderActions(): array ->url($navigationContext->backLinkUrl); } - $sourceTenant = $this->selectedSourceTenant(); + $sourceEnvironment = $this->selectedSourceEnvironment(); - if ($sourceTenant instanceof ManagedEnvironment) { - $actions[] = Action::make('open_source_tenant') - ->label('Open source tenant') + if ($sourceEnvironment instanceof ManagedEnvironment) { + $actions[] = Action::make('open_source_environment') + ->label('Open source environment') ->icon('heroicon-o-arrow-top-right-on-square') ->color('gray') - ->url(ManagedEnvironmentLinks::viewUrl($sourceTenant)); + ->url(ManagedEnvironmentLinks::viewUrl($sourceEnvironment)); } - $targetTenant = $this->selectedTargetTenant(); + $targetEnvironment = $this->selectedTargetEnvironment(); - if ($targetTenant instanceof ManagedEnvironment) { - $actions[] = Action::make('open_target_tenant') - ->label('Open target tenant') + if ($targetEnvironment instanceof ManagedEnvironment) { + $actions[] = Action::make('open_target_environment') + ->label('Open target environment') ->icon('heroicon-o-arrow-top-right-on-square') ->color('gray') - ->url(ManagedEnvironmentLinks::viewUrl($targetTenant)); + ->url(ManagedEnvironmentLinks::viewUrl($targetEnvironment)); } $preflightAction = Action::make('generatePromotionPreflight') @@ -254,15 +254,15 @@ public function applySelection(): void $this->selectionMessage = null; $this->preflight = null; - $this->sourceTenantId = $this->normalizeTenantIdentifier($this->sourceTenantId); - $this->targetTenantId = $this->normalizeTenantIdentifier($this->targetTenantId); + $this->sourceEnvironmentId = $this->normalizeEnvironmentIdentifier($this->sourceEnvironmentId); + $this->targetEnvironmentId = $this->normalizeEnvironmentIdentifier($this->targetEnvironmentId); $this->selectedPolicyTypes = $this->normalizePolicyTypes($this->selectedPolicyTypes); - if ($this->sourceTenantId !== null - && $this->targetTenantId !== null - && $this->sourceTenantId === $this->targetTenantId) { - $this->selectionMessage = 'Choose two different tenants.'; - $this->addError('targetTenantId', $this->selectionMessage); + if ($this->sourceEnvironmentId !== null + && $this->targetEnvironmentId !== null + && $this->sourceEnvironmentId === $this->targetEnvironmentId) { + $this->selectionMessage = 'Choose two different environments.'; + $this->addError('targetEnvironmentId', $this->selectionMessage); return; } @@ -285,20 +285,20 @@ public function generatePromotionPreflight(): void $selection = $this->compareSelection(); - if (! $selection instanceof CrossTenantCompareSelection) { + if (! $selection instanceof CrossEnvironmentCompareSelection) { return; } - $this->preflight = app(CrossTenantPromotionPreflight::class)->build($this->preview); + $this->preflight = app(CrossEnvironmentPromotionPreflight::class)->build($this->preview); $workspace = $this->workspace(); $user = auth()->user(); if ($workspace instanceof Workspace && $user instanceof User) { - app(WorkspaceAuditLogger::class)->logCrossTenantPromotionPreflightGenerated( + app(WorkspaceAuditLogger::class)->logCrossEnvironmentPromotionPreflightGenerated( workspace: $workspace, - sourceTenant: $selection->sourceTenant, - targetTenant: $selection->targetTenant, + sourceEnvironment: $selection->sourceEnvironment, + targetEnvironment: $selection->targetEnvironment, preflight: $this->preflight, actor: $user, ); @@ -323,7 +323,7 @@ public function executePromotion(): void $selection = $this->compareSelection(); $user = auth()->user(); - if (! $selection instanceof CrossTenantCompareSelection || ! $user instanceof User) { + if (! $selection instanceof CrossEnvironmentCompareSelection || ! $user instanceof User) { Notification::make() ->title('Promotion execution unavailable') ->body('Refresh the compare selection before executing promotion.') @@ -334,7 +334,7 @@ public function executePromotion(): void } try { - $result = app(CrossTenantPromotionExecutionService::class)->start( + $result = app(CrossEnvironmentPromotionExecutionService::class)->start( selection: $selection, preview: $this->preview, preflight: $this->preflight, @@ -376,8 +376,8 @@ public function executePromotion(): void public function clearSelectionUrl(): string { return static::getUrl($this->routeParameters([ - self::SOURCE_TENANT_QUERY_KEY => null, - self::TARGET_TENANT_QUERY_KEY => null, + self::SOURCE_ENVIRONMENT_QUERY_KEY => null, + self::TARGET_ENVIRONMENT_QUERY_KEY => null, self::POLICY_TYPE_QUERY_KEY => null, ]), panel: 'admin'); } @@ -388,18 +388,18 @@ public function selectionUrl(): string } public static function launchUrl( - ?ManagedEnvironment $sourceTenant = null, - ?ManagedEnvironment $targetTenant = null, + ?ManagedEnvironment $sourceEnvironment = null, + ?ManagedEnvironment $targetEnvironment = null, ?CanonicalNavigationContext $navigationContext = null, ): string { $parameters = []; - if ($sourceTenant instanceof ManagedEnvironment) { - $parameters[self::SOURCE_TENANT_QUERY_KEY] = (int) $sourceTenant->getKey(); + if ($sourceEnvironment instanceof ManagedEnvironment) { + $parameters[self::SOURCE_ENVIRONMENT_QUERY_KEY] = (int) $sourceEnvironment->getKey(); } - if ($targetTenant instanceof ManagedEnvironment) { - $parameters[self::TARGET_TENANT_QUERY_KEY] = (int) $targetTenant->getKey(); + if ($targetEnvironment instanceof ManagedEnvironment) { + $parameters[self::TARGET_ENVIRONMENT_QUERY_KEY] = (int) $targetEnvironment->getKey(); } if ($navigationContext instanceof CanonicalNavigationContext) { @@ -411,8 +411,8 @@ public static function launchUrl( public function hasActiveSelection(): bool { - return $this->sourceTenantId !== null - || $this->targetTenantId !== null + return $this->sourceEnvironmentId !== null + || $this->targetEnvironmentId !== null || $this->selectedPolicyTypes !== []; } @@ -438,26 +438,26 @@ public function reasonLabel(string $reasonCode): string return Str::headline(str_replace('_', ' ', $reasonCode)); } - public function sourceTenantUrl(): ?string + public function sourceEnvironmentUrl(): ?string { - $tenant = $this->selectedSourceTenant(); + $environment = $this->selectedSourceEnvironment(); - if (! $tenant instanceof ManagedEnvironment) { + if (! $environment instanceof ManagedEnvironment) { return null; } - return ManagedEnvironmentLinks::viewUrl($tenant); + return ManagedEnvironmentLinks::viewUrl($environment); } - public function targetTenantUrl(): ?string + public function targetEnvironmentUrl(): ?string { - $tenant = $this->selectedTargetTenant(); + $environment = $this->selectedTargetEnvironment(); - if (! $tenant instanceof ManagedEnvironment) { + if (! $environment instanceof ManagedEnvironment) { return null; } - return ManagedEnvironmentLinks::viewUrl($tenant); + return ManagedEnvironmentLinks::viewUrl($environment); } /** @@ -466,16 +466,16 @@ public function targetTenantUrl(): ?string private function formState(): array { return [ - 'sourceTenantId' => $this->sourceTenantId, - 'targetTenantId' => $this->targetTenantId, + 'sourceEnvironmentId' => $this->sourceEnvironmentId, + 'targetEnvironmentId' => $this->targetEnvironmentId, 'selectedPolicyTypes' => $this->selectedPolicyTypes, ]; } private function hydrateSelectionFromRequest(): void { - $this->sourceTenantId = $this->normalizeTenantIdentifier(request()->query(self::SOURCE_TENANT_QUERY_KEY)); - $this->targetTenantId = $this->normalizeTenantIdentifier(request()->query(self::TARGET_TENANT_QUERY_KEY)); + $this->sourceEnvironmentId = $this->normalizeEnvironmentIdentifier(request()->query(self::SOURCE_ENVIRONMENT_QUERY_KEY)); + $this->targetEnvironmentId = $this->normalizeEnvironmentIdentifier(request()->query(self::TARGET_ENVIRONMENT_QUERY_KEY)); $this->selectedPolicyTypes = $this->normalizePolicyTypes(request()->query(self::POLICY_TYPE_QUERY_KEY, [])); } @@ -487,11 +487,11 @@ private function refreshPreview(): void $selection = $this->compareSelection(); - if (! $selection instanceof CrossTenantCompareSelection) { + if (! $selection instanceof CrossEnvironmentCompareSelection) { return; } - $this->preview = app(CrossTenantComparePreviewBuilder::class)->build($selection); + $this->preview = app(CrossEnvironmentComparePreviewBuilder::class)->build($selection); } private function authorizePageAccess(): void @@ -554,61 +554,61 @@ private function authorizePromotionExecution(): void abort(403); } - $targetTenant = $this->selectedTargetTenant(); + $targetEnvironment = $this->selectedTargetEnvironment(); - if (! $targetTenant instanceof ManagedEnvironment) { + if (! $targetEnvironment instanceof ManagedEnvironment) { abort(404); } /** @var CapabilityResolver $resolver */ $resolver = app(CapabilityResolver::class); - if (! $resolver->can($user, $targetTenant, Capabilities::TENANT_MANAGE)) { + if (! $resolver->can($user, $targetEnvironment, Capabilities::TENANT_MANAGE)) { abort(403); } } - private function compareSelection(): ?CrossTenantCompareSelection + private function compareSelection(): ?CrossEnvironmentCompareSelection { - $sourceTenant = $this->selectedSourceTenant(); - $targetTenant = $this->selectedTargetTenant(); + $sourceEnvironment = $this->selectedSourceEnvironment(); + $targetEnvironment = $this->selectedTargetEnvironment(); - if (! $sourceTenant instanceof ManagedEnvironment || ! $targetTenant instanceof ManagedEnvironment) { + if (! $sourceEnvironment instanceof ManagedEnvironment || ! $targetEnvironment instanceof ManagedEnvironment) { return null; } - if ((int) $sourceTenant->getKey() === (int) $targetTenant->getKey()) { - $this->selectionMessage = 'Choose two different tenants.'; + if ((int) $sourceEnvironment->getKey() === (int) $targetEnvironment->getKey()) { + $this->selectionMessage = 'Choose two different environments.'; return null; } - return new CrossTenantCompareSelection( - sourceTenant: $sourceTenant, - targetTenant: $targetTenant, + return new CrossEnvironmentCompareSelection( + sourceEnvironment: $sourceEnvironment, + targetEnvironment: $targetEnvironment, policyTypes: $this->selectedPolicyTypes, ); } - private function selectedSourceTenant(): ?ManagedEnvironment + private function selectedSourceEnvironment(): ?ManagedEnvironment { - if ($this->sourceTenantId === null) { + if ($this->sourceEnvironmentId === null) { return null; } - return $this->resolveAuthorizedTenant($this->sourceTenantId); + return $this->resolveAuthorizedEnvironment($this->sourceEnvironmentId); } - private function selectedTargetTenant(): ?ManagedEnvironment + private function selectedTargetEnvironment(): ?ManagedEnvironment { - if ($this->targetTenantId === null) { + if ($this->targetEnvironmentId === null) { return null; } - return $this->resolveAuthorizedTenant($this->targetTenantId); + return $this->resolveAuthorizedEnvironment($this->targetEnvironmentId); } - private function resolveAuthorizedTenant(string $tenantId): ManagedEnvironment + private function resolveAuthorizedEnvironment(string $environmentId): ManagedEnvironment { $workspace = $this->workspace(); $user = auth()->user(); @@ -617,29 +617,29 @@ private function resolveAuthorizedTenant(string $tenantId): ManagedEnvironment abort(404); } - $tenant = ManagedEnvironment::query() + $environment = ManagedEnvironment::query() ->where('workspace_id', (int) $workspace->getKey()) - ->whereKey((int) $tenantId) + ->whereKey((int) $environmentId) ->first(); - if (! $tenant instanceof ManagedEnvironment) { + if (! $environment instanceof ManagedEnvironment) { abort(404); } /** @var CapabilityResolver $resolver */ $resolver = app(CapabilityResolver::class); - if (! $user->canAccessTenant($tenant) || ! $resolver->can($user, $tenant, Capabilities::TENANT_VIEW)) { + if (! $user->canAccessTenant($environment) || ! $resolver->can($user, $environment, Capabilities::TENANT_VIEW)) { abort(404); } - return $tenant; + return $environment; } /** * @return array */ - private function tenantOptions(): array + private function environmentOptions(): array { $workspace = $this->workspace(); $user = auth()->user(); @@ -651,17 +651,17 @@ private function tenantOptions(): array /** @var CapabilityResolver $resolver */ $resolver = app(CapabilityResolver::class); - $tenants = $user->accessibleManagedEnvironmentsQuery((int) $workspace->getKey()) + $environments = $user->accessibleManagedEnvironmentsQuery((int) $workspace->getKey()) ->select('managed_environments.*') ->orderBy('managed_environments.name') ->get(); - $resolver->primeMemberships($user, $tenants->modelKeys()); + $resolver->primeMemberships($user, $environments->modelKeys()); - return $tenants - ->filter(fn (ManagedEnvironment $tenant): bool => $resolver->can($user, $tenant, Capabilities::TENANT_VIEW)) - ->mapWithKeys(fn (ManagedEnvironment $tenant): array => [ - (string) $tenant->getKey() => (string) $tenant->name, + return $environments + ->filter(fn (ManagedEnvironment $environment): bool => $resolver->can($user, $environment, Capabilities::TENANT_VIEW)) + ->mapWithKeys(fn (ManagedEnvironment $environment): array => [ + (string) $environment->getKey() => (string) $environment->name, ]) ->all(); } @@ -671,14 +671,14 @@ private function tenantOptions(): array */ private function policyTypeOptions(): array { - $tenantIds = array_map(static fn (string $tenantId): int => (int) $tenantId, array_keys($this->tenantOptions())); + $environmentIds = array_map(static fn (string $environmentId): int => (int) $environmentId, array_keys($this->environmentOptions())); - if ($tenantIds === []) { + if ($environmentIds === []) { return []; } return InventoryItem::query() - ->whereIn('managed_environment_id', $tenantIds) + ->whereIn('managed_environment_id', $environmentIds) ->whereNotNull('policy_type') ->where('policy_type', '!=', '') ->distinct() @@ -697,7 +697,7 @@ private function preflightDisabledReason(): ?string } if (! is_array($this->preview)) { - return 'Select an authorized source and target tenant to generate a promotion preflight.'; + return 'Select an authorized source and target environment to generate a promotion preflight.'; } if ((int) data_get($this->preview, 'summary.total', 0) === 0) { @@ -737,14 +737,14 @@ private function executePromotionDisabledReason(): ?string return 'You need workspace baseline manage access to execute promotion.'; } - $targetTenant = $this->selectedTargetTenant(); + $targetEnvironment = $this->selectedTargetEnvironment(); - if ($targetTenant instanceof ManagedEnvironment) { + if ($targetEnvironment instanceof ManagedEnvironment) { /** @var CapabilityResolver $resolver */ $resolver = app(CapabilityResolver::class); - if (! $resolver->can($user, $targetTenant, Capabilities::TENANT_MANAGE)) { - return 'You need target tenant manage access to execute promotion.'; + if (! $resolver->can($user, $targetEnvironment, Capabilities::TENANT_MANAGE)) { + return 'You need target environment manage access to execute promotion.'; } } } @@ -760,13 +760,13 @@ private function executePromotionConfirmationDescription(): string $manualMappingRequired = (int) data_get($this->preflight, 'summary.manual_mapping_required', 0); $excluded = $blocked + $manualMappingRequired; - $sourceTenantName = $selection?->sourceTenant->name ?? 'Source tenant'; - $targetTenantName = $selection?->targetTenant->name ?? 'Target tenant'; + $sourceEnvironmentName = $selection?->sourceEnvironment->name ?? 'Source environment'; + $targetEnvironmentName = $selection?->targetEnvironment->name ?? 'Target environment'; return sprintf( 'Queue one promotion run from %s to %s for %d ready governed subject%s. %d subject%s remain excluded on the compare page.', - $sourceTenantName, - $targetTenantName, + $sourceEnvironmentName, + $targetEnvironmentName, $ready, $ready === 1 ? '' : 's', $excluded, @@ -777,7 +777,7 @@ private function executePromotionConfirmationDescription(): string /** * @param mixed $value */ - private function normalizeTenantIdentifier(mixed $value): ?string + private function normalizeEnvironmentIdentifier(mixed $value): ?string { if (! is_string($value) && ! is_int($value)) { return null; @@ -815,8 +815,8 @@ private function normalizePolicyTypes(mixed $value): array private function routeParameters(array $overrides = []): array { $parameters = [ - self::SOURCE_TENANT_QUERY_KEY => $this->sourceTenantId, - self::TARGET_TENANT_QUERY_KEY => $this->targetTenantId, + self::SOURCE_ENVIRONMENT_QUERY_KEY => $this->sourceEnvironmentId, + self::TARGET_ENVIRONMENT_QUERY_KEY => $this->targetEnvironmentId, self::POLICY_TYPE_QUERY_KEY => $this->selectedPolicyTypes, ]; diff --git a/apps/platform/app/Filament/Pages/TenantDashboard.php b/apps/platform/app/Filament/Pages/EnvironmentDashboard.php similarity index 95% rename from apps/platform/app/Filament/Pages/TenantDashboard.php rename to apps/platform/app/Filament/Pages/EnvironmentDashboard.php index c8656c03..0de101b2 100644 --- a/apps/platform/app/Filament/Pages/TenantDashboard.php +++ b/apps/platform/app/Filament/Pages/EnvironmentDashboard.php @@ -5,9 +5,9 @@ namespace App\Filament\Pages; use App\Filament\Pages\Governance\GovernanceInbox; -use App\Filament\Widgets\Tenant\TenantTriageArrivalContinuity; -use App\Filament\Widgets\Dashboard\TenantDashboardContextChips; -use App\Filament\Widgets\Dashboard\TenantDashboardOverview; +use App\Filament\Widgets\ManagedEnvironment\ManagedEnvironmentTriageArrivalContinuity; +use App\Filament\Widgets\Dashboard\EnvironmentDashboardContextChips; +use App\Filament\Widgets\Dashboard\EnvironmentDashboardOverview; use App\Models\SupportRequest; use App\Models\ManagedEnvironment; use App\Models\User; @@ -21,8 +21,8 @@ use App\Support\SupportDiagnostics\SupportDiagnosticBundleBuilder; use App\Support\SupportRequests\ExternalSupportDeskHandoffService; use App\Support\SupportRequests\SupportRequestSubmissionService; -use App\Support\TenantDashboard\TenantDashboardSummary; -use App\Support\TenantDashboard\TenantDashboardSummaryBuilder; +use App\Support\EnvironmentDashboard\EnvironmentDashboardSummary; +use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder; use Filament\Actions\Action; use Filament\Actions\ActionGroup; use Filament\Facades\Filament; @@ -43,7 +43,7 @@ use App\Filament\Widgets\Dashboard\DashboardKpis; -class TenantDashboard extends Dashboard +class EnvironmentDashboard extends Dashboard { protected Width|string|null $maxContentWidth = Width::Full; @@ -52,7 +52,7 @@ class TenantDashboard extends Dashboard */ public array $supportDiagnosticsAuditKeys = []; - private ?TenantDashboardSummary $dashboardSummary = null; + private ?EnvironmentDashboardSummary $dashboardSummary = null; public static function getNavigationLabel(): string { @@ -69,7 +69,7 @@ public function getTitle(): string | Htmlable $summary = $this->dashboardSummary(); - if (! $summary instanceof TenantDashboardSummary) { + if (! $summary instanceof EnvironmentDashboardSummary) { return (string) $tenant->name; } @@ -112,7 +112,7 @@ public static function getUrl(array $parameters = [], bool $isAbsolute = true, ? protected function getHeaderWidgets(): array { return [ - TenantDashboardContextChips::class, + EnvironmentDashboardContextChips::class, ]; } @@ -127,9 +127,9 @@ public function getHeaderWidgetsColumns(): int|array public function getWidgets(): array { return [ - TenantTriageArrivalContinuity::class, + ManagedEnvironmentTriageArrivalContinuity::class, DashboardKpis::class, - TenantDashboardOverview::class, + EnvironmentDashboardOverview::class, ]; } @@ -204,7 +204,7 @@ private function primaryFollowUpHeaderPayload(): ?array { $summary = $this->dashboardSummary(); - if (! $summary instanceof TenantDashboardSummary) { + if (! $summary instanceof EnvironmentDashboardSummary) { return null; } @@ -222,7 +222,7 @@ private function secondaryHeaderPayload(): ?array { $summary = $this->dashboardSummary(); - if (! $summary instanceof TenantDashboardSummary) { + if (! $summary instanceof EnvironmentDashboardSummary) { return null; } @@ -304,9 +304,9 @@ private function summaryHeaderAction(string $name, array $payload, string $color return $action; } - private function dashboardSummary(): ?TenantDashboardSummary + private function dashboardSummary(): ?EnvironmentDashboardSummary { - if ($this->dashboardSummary instanceof TenantDashboardSummary) { + if ($this->dashboardSummary instanceof EnvironmentDashboardSummary) { return $this->dashboardSummary; } @@ -317,7 +317,7 @@ private function dashboardSummary(): ?TenantDashboardSummary return null; } - $this->dashboardSummary = app(TenantDashboardSummaryBuilder::class)->build($tenant, $user); + $this->dashboardSummary = app(EnvironmentDashboardSummaryBuilder::class)->build($tenant, $user); return $this->dashboardSummary; } diff --git a/apps/platform/app/Filament/Pages/TenantDiagnostics.php b/apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php similarity index 84% rename from apps/platform/app/Filament/Pages/TenantDiagnostics.php rename to apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php index 04ef13b3..48a6081b 100644 --- a/apps/platform/app/Filament/Pages/TenantDiagnostics.php +++ b/apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php @@ -6,8 +6,8 @@ use App\Filament\Concerns\ResolvesPanelTenantContext; use App\Models\User; -use App\Services\Auth\TenantDiagnosticsService; -use App\Services\Auth\TenantMembershipManager; +use App\Services\Auth\ManagedEnvironmentDiagnosticsService; +use App\Services\Auth\ManagedEnvironmentMembershipManager; use App\Support\Auth\Capabilities; use App\Support\Rbac\UiEnforcement; use App\Support\Rbac\UiTooltips; @@ -17,7 +17,7 @@ use Filament\Actions\Action; use Filament\Pages\Page; -class TenantDiagnostics extends Page +class EnvironmentDiagnostics extends Page { use ResolvesPanelTenantContext; @@ -25,7 +25,7 @@ class TenantDiagnostics extends Page protected static ?string $slug = 'diagnostics'; - protected string $view = 'filament.pages.tenant-diagnostics'; + protected string $view = 'filament.pages.environment-diagnostics'; public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration { @@ -44,14 +44,14 @@ public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration public function mount(): void { $tenant = static::resolveTenantContextForCurrentPanelOrFail(); - $this->missingOwner = app(TenantDiagnosticsService::class)->tenantHasNoOwners($tenant); + $this->missingOwner = app(ManagedEnvironmentDiagnosticsService::class)->tenantHasNoOwners($tenant); $user = auth()->user(); if (! $user instanceof User) { abort(403, 'Not allowed'); } - $this->hasDuplicateMembershipsForCurrentUser = app(TenantDiagnosticsService::class) + $this->hasDuplicateMembershipsForCurrentUser = app(ManagedEnvironmentDiagnosticsService::class) ->userHasDuplicateMemberships($tenant, $user); } @@ -96,7 +96,7 @@ public function bootstrapOwner(): void abort(403, 'Not allowed'); } - app(TenantMembershipManager::class)->grantScope($tenant, $user, $user, sourceRef: 'diagnostic'); + app(ManagedEnvironmentMembershipManager::class)->grantScope($tenant, $user, $user, sourceRef: 'diagnostic'); $this->mount(); } @@ -110,7 +110,7 @@ public function mergeDuplicateMemberships(): void abort(403, 'Not allowed'); } - app(TenantDiagnosticsService::class)->mergeDuplicateMembershipsForUser($tenant, $user, $user); + app(ManagedEnvironmentDiagnosticsService::class)->mergeDuplicateMembershipsForUser($tenant, $user, $user); $this->mount(); } diff --git a/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php b/apps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php similarity index 94% rename from apps/platform/app/Filament/Pages/TenantRequiredPermissions.php rename to apps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php index 4fba214d..4e3128a8 100644 --- a/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php +++ b/apps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php @@ -7,7 +7,7 @@ use App\Models\ManagedEnvironment; use App\Models\User; use App\Models\WorkspaceMembership; -use App\Services\Intune\TenantRequiredPermissionsViewModelBuilder; +use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder; use App\Support\Badges\BadgeDomain; use App\Support\Badges\BadgeRenderer; use App\Support\Filament\TablePaginationProfiles; @@ -29,7 +29,7 @@ use Livewire\Attributes\Locked; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class TenantRequiredPermissions extends Page implements HasTable +class EnvironmentRequiredPermissions extends Page implements HasTable { use InteractsWithTable; @@ -37,11 +37,11 @@ class TenantRequiredPermissions extends Page implements HasTable protected static bool $shouldRegisterNavigation = false; - protected static ?string $slug = 'workspaces/{workspace}/environments/{tenant}/required-permissions'; + protected static ?string $slug = 'workspaces/{workspace}/environments/{environment}/required-permissions'; protected static ?string $title = 'Required permissions'; - protected string $view = 'filament.pages.tenant-required-permissions'; + protected string $view = 'filament.pages.environment-required-permissions'; public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration { @@ -73,9 +73,9 @@ public function currentTenant(): ?ManagedEnvironment return $this->trustedScopedTenant(); } - public function mount(ManagedEnvironment|string|null $tenant = null): void + public function mount(ManagedEnvironment|string|null $environment = null): void { - $tenant = static::resolveScopedTenant($tenant); + $tenant = static::resolveScopedTenant($environment); if (! $tenant instanceof ManagedEnvironment || ! static::hasScopedTenantAccess($tenant)) { abort(404); @@ -151,10 +151,10 @@ public function table(Table $table): Table TextColumn::make('status') ->label('Status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantPermissionStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantPermissionStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantPermissionStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantPermissionStatus)) + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->color(BadgeRenderer::color(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::ManagedEnvironmentPermissionStatus)) ->sortable(), TextColumn::make('features_label') ->label('Features') @@ -235,7 +235,7 @@ protected static function resolveScopedTenant(ManagedEnvironment|string|null $te ->first(); } - $routeTenant = request()->route('tenant'); + $routeTenant = request()->route('environment') ?? request()->route('tenant'); if ($routeTenant instanceof ManagedEnvironment) { return $routeTenant; @@ -333,7 +333,7 @@ private function trustedScopedTenant(): ?ManagedEnvironment */ private function filterState(array $filters = [], ?string $search = null): array { - return TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ + return ManagedEnvironmentRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => $filters['status']['value'] ?? data_get($this->tableFilters, 'status.value'), 'type' => $filters['type']['value'] ?? data_get($this->tableFilters, 'type.value'), 'features' => $filters['features']['values'] ?? data_get($this->tableFilters, 'features.values', []), @@ -359,7 +359,7 @@ private function viewModelForState(array $state): array return $this->cachedViewModel; } - $builder = app(TenantRequiredPermissionsViewModelBuilder::class); + $builder = app(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class); $this->cachedViewModelStateKey = $stateKey ?: null; $this->cachedViewModel = $builder->build($tenant, $state); @@ -514,7 +514,7 @@ private function seedTableStateFromQuery(): void $queryFeatures = request()->query('features', []); - $state = TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ + $state = ManagedEnvironmentRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => request()->query('status', 'missing'), 'type' => request()->query('type', 'all'), 'features' => is_array($queryFeatures) ? $queryFeatures : [], diff --git a/apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php b/apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php index fac0bd2b..bd22ae4d 100644 --- a/apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php +++ b/apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php @@ -288,10 +288,10 @@ public function emptyState(): array 'title' => 'No visible assigned findings right now', 'body' => 'Nothing currently assigned to you needs attention across the visible environment scope. Choose an environment to continue working elsewhere in the workspace.', 'icon' => 'heroicon-o-clipboard-document-check', - 'action_name' => 'choose_tenant_empty', + 'action_name' => 'choose_environment_empty', 'action_label' => 'Choose an environment', 'action_kind' => 'url', - 'action_url' => route('filament.admin.pages.choose-tenant'), + 'action_url' => route('filament.admin.pages.choose-environment'), ]; } diff --git a/apps/platform/app/Filament/Pages/Governance/GovernanceInbox.php b/apps/platform/app/Filament/Pages/Governance/GovernanceInbox.php index 13bef1f2..2d917839 100644 --- a/apps/platform/app/Filament/Pages/Governance/GovernanceInbox.php +++ b/apps/platform/app/Filament/Pages/Governance/GovernanceInbox.php @@ -11,7 +11,7 @@ use App\Models\Workspace; use App\Services\Auth\CapabilityResolver; use App\Services\Auth\WorkspaceCapabilityResolver; -use App\Services\TenantReviews\TenantReviewRegisterService; +use App\Services\EnvironmentReviews\EnvironmentReviewRegisterService; use App\Support\Auth\Capabilities; use App\Support\GovernanceInbox\GovernanceInboxSectionBuilder; use App\Support\Navigation\CanonicalNavigationContext; @@ -333,7 +333,7 @@ private function reviewTenants(): array return $this->reviewTenants = []; } - $service = app(TenantReviewRegisterService::class); + $service = app(EnvironmentReviewRegisterService::class); if (! $service->canAccessWorkspace($user, $workspace)) { return $this->reviewTenants = []; diff --git a/apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php b/apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php index b1f005d1..6ff4f0ab 100644 --- a/apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php +++ b/apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php @@ -7,11 +7,11 @@ use App\Filament\Resources\EvidenceSnapshotResource; use App\Models\EvidenceSnapshot; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Support\Badges\BadgeCatalog; use App\Support\Badges\BadgeDomain; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewStatus; use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile; @@ -398,13 +398,13 @@ private function latestAccessibleSnapshots(): Collection */ private function currentReviewTenantIds(Collection $snapshots): array { - return TenantReview::query() + return EnvironmentReview::query() ->where('workspace_id', $this->workspaceId()) ->whereIn('managed_environment_id', $snapshots->pluck('managed_environment_id')->map(static fn (mixed $tenantId): int => (int) $tenantId)->all()) ->whereIn('status', [ - TenantReviewStatus::Draft->value, - TenantReviewStatus::Ready->value, - TenantReviewStatus::Published->value, + EnvironmentReviewStatus::Draft->value, + EnvironmentReviewStatus::Ready->value, + EnvironmentReviewStatus::Published->value, ]) ->pluck('managed_environment_id') ->mapWithKeys(static fn (mixed $tenantId): array => [(int) $tenantId => true]) diff --git a/apps/platform/app/Filament/Pages/NoAccess.php b/apps/platform/app/Filament/Pages/NoAccess.php index 09389ff9..c69b1f81 100644 --- a/apps/platform/app/Filament/Pages/NoAccess.php +++ b/apps/platform/app/Filament/Pages/NoAccess.php @@ -93,6 +93,6 @@ public function createWorkspace(array $data): void ->success() ->send(); - $this->redirect(ChooseTenant::getUrl()); + $this->redirect(ChooseEnvironment::getUrl()); } } diff --git a/apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php b/apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php index 5b178df6..2ea649e7 100644 --- a/apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php +++ b/apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php @@ -4,16 +4,16 @@ namespace App\Filament\Pages\Reviews; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\EvidenceSnapshot; use App\Models\FindingException; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; use App\Services\Audit\WorkspaceAuditLogger; -use App\Services\TenantReviews\TenantReviewRegisterService; +use App\Services\EnvironmentReviews\EnvironmentReviewRegisterService; use App\Support\Audit\AuditActionId; use App\Support\Auth\Capabilities; use App\Support\Findings\FindingOutcomeSemantics; @@ -21,7 +21,7 @@ use App\Support\Governance\Controls\ComplianceEvidenceMappingV1; use App\Support\Navigation\CanonicalNavigationContext; use App\Support\ReviewPackStatus; -use App\Support\TenantReviewCompletenessState; +use App\Support\EnvironmentReviewCompletenessState; use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile; @@ -236,7 +236,7 @@ public function authorizedTenants(): array return $this->authorizedTenants = []; } - return $this->authorizedTenants = app(TenantReviewRegisterService::class)->authorizedTenants($user, $workspace); + return $this->authorizedTenants = app(EnvironmentReviewRegisterService::class)->authorizedTenants($user, $workspace); } private function authorizePageAccess(): void @@ -252,7 +252,7 @@ private function authorizePageAccess(): void throw new NotFoundHttpException; } - $service = app(TenantReviewRegisterService::class); + $service = app(EnvironmentReviewRegisterService::class); if (! $service->canAccessWorkspace($user, $workspace)) { throw new NotFoundHttpException; @@ -300,7 +300,7 @@ private function workspaceQuery(): Builder return ManagedEnvironment::query()->whereRaw('1 = 0'); } - return app(TenantReviewRegisterService::class)->customerWorkspaceTenantQuery($user, $workspace); + return app(EnvironmentReviewRegisterService::class)->customerWorkspaceTenantQuery($user, $workspace); } /** @@ -377,18 +377,18 @@ private function workspace(): ?Workspace : null; } - private function latestPublishedReview(ManagedEnvironment $tenant): ?TenantReview + private function latestPublishedReview(ManagedEnvironment $tenant): ?EnvironmentReview { - $review = $tenant->tenantReviews->first(); + $review = $tenant->environmentReviews->first(); - return $review instanceof TenantReview ? $review : null; + return $review instanceof EnvironmentReview ? $review : null; } private function latestReviewUrl(ManagedEnvironment $tenant): ?string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return null; } @@ -404,7 +404,7 @@ private function latestReviewUrl(ManagedEnvironment $tenant): ?string static fn (mixed $value): bool => $value !== null && $value !== '', ); - return $this->appendQuery(TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant), $query); + return $this->appendQuery(EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant), $query); } private function latestPublishedAt(ManagedEnvironment $tenant): ?\Illuminate\Support\Carbon @@ -416,8 +416,8 @@ private function reviewTruth(ManagedEnvironment $tenant): ?ArtifactTruthEnvelope { $review = $this->latestPublishedReview($tenant); - return $review instanceof TenantReview - ? app(ArtifactTruthPresenter::class)->forTenantReview($review) + return $review instanceof EnvironmentReview + ? app(ArtifactTruthPresenter::class)->forEnvironmentReview($review) : null; } @@ -427,7 +427,7 @@ private function reviewOutcome(ManagedEnvironment $tenant): ?CompressedGovernanc $review = $this->latestPublishedReview($tenant); $truth = $this->reviewTruth($tenant); - if (! $review instanceof TenantReview || ! $truth instanceof ArtifactTruthEnvelope) { + if (! $review instanceof EnvironmentReview || ! $truth instanceof ArtifactTruthEnvelope) { return null; } @@ -439,7 +439,7 @@ private function latestReviewStateLabel(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review'); } @@ -452,7 +452,7 @@ private function latestReviewStateColor(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return 'gray'; } @@ -481,7 +481,7 @@ private function reviewOutcomeDescription(ManagedEnvironment $tenant): ?string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review_available'); } @@ -524,7 +524,7 @@ private function governancePackageSummary(ManagedEnvironment $tenant): array { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return []; } @@ -541,7 +541,7 @@ private function governancePackageAvailability(ManagedEnvironment $tenant): arra { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return [ 'state' => 'unavailable', 'label' => __('localization.review.governance_package_unavailable'), @@ -553,8 +553,8 @@ private function governancePackageAvailability(ManagedEnvironment $tenant): arra $user = auth()->user(); $limitations = is_array($review->controlInterpretation()['limitations'] ?? null) ? $review->controlInterpretation()['limitations'] : []; $isPartialReview = in_array((string) $review->completeness_state, [ - TenantReviewCompletenessState::Partial->value, - TenantReviewCompletenessState::Stale->value, + EnvironmentReviewCompletenessState::Partial->value, + EnvironmentReviewCompletenessState::Stale->value, ], true) || $limitations !== []; if (! $pack instanceof ReviewPack) { @@ -652,7 +652,7 @@ private function controlReadinessDescription(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review_available'); } @@ -720,7 +720,7 @@ private function workspaceReviewNeedsAttention(ManagedEnvironment $tenant): bool { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return true; } @@ -739,7 +739,7 @@ private function evidenceStatusState(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return 'pending'; } @@ -802,7 +802,7 @@ private function primaryControlSummary(ManagedEnvironment $tenant): ?array { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return null; } @@ -818,7 +818,7 @@ private function primaryControlSummary(ManagedEnvironment $tenant): ?array ->first(); } - private function controlLimitationSummary(TenantReview $review): ?string + private function controlLimitationSummary(EnvironmentReview $review): ?string { $counts = $review->controlInterpretationLimitationCounts(); @@ -842,7 +842,7 @@ private function findingSummary(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review_available'); } @@ -869,7 +869,7 @@ private function acceptedRiskSummary(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review_available'); } @@ -897,7 +897,7 @@ private function evidenceProofAvailability(ManagedEnvironment $tenant): string { $review = $this->latestPublishedReview($tenant); - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return __('localization.review.no_published_review_available'); } @@ -941,10 +941,10 @@ private function visibleInterpretationVersions(): array return []; } - return app(TenantReviewRegisterService::class) + return app(EnvironmentReviewRegisterService::class) ->latestPublishedQuery($user, $workspace) ->get() - ->map(static fn (TenantReview $review): ?string => $review->controlInterpretationVersion()) + ->map(static fn (EnvironmentReview $review): ?string => $review->controlInterpretationVersion()) ->filter() ->unique() ->values() @@ -965,7 +965,7 @@ private function currentTenantFilterInterpretationVersion(): ?string return null; } - return $tenant->tenantReviews()->published() + return $tenant->environmentReviews()->published() ->latest('published_at') ->latest('generated_at') ->latest('id') diff --git a/apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php b/apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php index cc86abf2..6aac6e0d 100644 --- a/apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php +++ b/apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php @@ -4,13 +4,13 @@ namespace App\Filament\Pages\Reviews; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; use App\Services\ReviewPackService; -use App\Services\TenantReviews\TenantReviewRegisterService; +use App\Services\EnvironmentReviews\EnvironmentReviewRegisterService; use App\Support\Auth\Capabilities; use App\Support\Badges\BadgeCatalog; use App\Support\Badges\BadgeDomain; @@ -19,7 +19,7 @@ use App\Support\Filament\CanonicalAdminTenantFilterState; use App\Support\Filament\FilterPresets; use App\Support\Filament\TablePaginationProfiles; -use App\Support\TenantReviewCompletenessState; +use App\Support\EnvironmentReviewCompletenessState; use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile; @@ -112,15 +112,15 @@ public function table(Table $table): Table ->persistFiltersInSession() ->persistSearchInSession() ->persistSortInSession() - ->recordUrl(fn (TenantReview $record): string => TenantReviewResource::tenantScopedUrl('view', ['record' => $record], $record->tenant)) + ->recordUrl(fn (EnvironmentReview $record): string => EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $record], $record->tenant)) ->columns([ TextColumn::make('tenant.name')->label('ManagedEnvironment')->searchable(), TextColumn::make('status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewStatus)), + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewStatus)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewStatus)), TextColumn::make('outcome') ->label('Outcome') ->badge() @@ -154,7 +154,7 @@ public function table(Table $table): Table ]), SelectFilter::make('completeness_state') ->label('Completeness') - ->options(BadgeCatalog::options(BadgeDomain::TenantReviewCompleteness, TenantReviewCompletenessState::values())), + ->options(BadgeCatalog::options(BadgeDomain::EnvironmentReviewCompleteness, EnvironmentReviewCompletenessState::values())), SelectFilter::make('published_state') ->label('Published state') ->options([ @@ -174,11 +174,11 @@ public function table(Table $table): Table Action::make('export_executive_pack') ->label('Export executive pack') ->icon('heroicon-o-arrow-down-tray') - ->visible(fn (TenantReview $record): bool => auth()->user() instanceof User - && auth()->user()->can(Capabilities::TENANT_REVIEW_MANAGE, $record->tenant) + ->visible(fn (EnvironmentReview $record): bool => auth()->user() instanceof User + && auth()->user()->can(Capabilities::ENVIRONMENT_REVIEW_MANAGE, $record->tenant) && in_array($record->status, ['ready', 'published'], true)) - ->disabled(fn (TenantReview $record): bool => (bool) (app(ReviewPackService::class)->reviewPackGenerationDecisionForTenant($record->tenant)['is_blocked'] ?? false)) - ->tooltip(function (TenantReview $record): ?string { + ->disabled(fn (EnvironmentReview $record): bool => (bool) (app(ReviewPackService::class)->reviewPackGenerationDecisionForTenant($record->tenant)['is_blocked'] ?? false)) + ->tooltip(function (EnvironmentReview $record): ?string { $decision = app(ReviewPackService::class)->reviewPackGenerationDecisionForTenant($record->tenant); if ((bool) ($decision['is_blocked'] ?? false)) { @@ -195,7 +195,7 @@ public function table(Table $table): Table return null; }) - ->action(fn (TenantReview $record): mixed => TenantReviewResource::executeExport($record)), + ->action(fn (EnvironmentReview $record): mixed => EnvironmentReviewResource::executeExport($record)), ]) ->bulkActions([]) ->emptyStateHeading('No review records match this view') @@ -225,7 +225,7 @@ public function authorizedTenants(): array return $this->authorizedTenants = []; } - return $this->authorizedTenants = app(TenantReviewRegisterService::class)->authorizedTenants($user, $workspace); + return $this->authorizedTenants = app(EnvironmentReviewRegisterService::class)->authorizedTenants($user, $workspace); } private function authorizePageAccess(): void @@ -241,7 +241,7 @@ private function authorizePageAccess(): void throw new NotFoundHttpException; } - $service = app(TenantReviewRegisterService::class); + $service = app(EnvironmentReviewRegisterService::class); if (! $service->canAccessWorkspace($user, $workspace)) { throw new NotFoundHttpException; @@ -258,10 +258,10 @@ private function registerQuery(): Builder $workspace = $this->workspace(); if (! $user instanceof User || ! $workspace instanceof Workspace) { - return TenantReview::query()->whereRaw('1 = 0'); + return EnvironmentReview::query()->whereRaw('1 = 0'); } - return app(TenantReviewRegisterService::class)->query($user, $workspace); + return app(EnvironmentReviewRegisterService::class)->query($user, $workspace); } /** @@ -341,36 +341,36 @@ private function workspace(): ?Workspace : null; } - private function reviewTruth(TenantReview $record, bool $fresh = false): ArtifactTruthEnvelope + private function reviewTruth(EnvironmentReview $record, bool $fresh = false): ArtifactTruthEnvelope { $presenter = app(ArtifactTruthPresenter::class); return $fresh - ? $presenter->forTenantReviewFresh($record) - : $presenter->forTenantReview($record); + ? $presenter->forEnvironmentReviewFresh($record) + : $presenter->forEnvironmentReview($record); } - private function reviewOutcomeLabel(TenantReview $record): string + private function reviewOutcomeLabel(EnvironmentReview $record): string { return $this->reviewOutcome($record)->primaryLabel; } - private function reviewOutcomeBadgeColor(TenantReview $record): string + private function reviewOutcomeBadgeColor(EnvironmentReview $record): string { return $this->reviewOutcome($record)->primaryBadge->color; } - private function reviewOutcomeBadgeIcon(TenantReview $record): ?string + private function reviewOutcomeBadgeIcon(EnvironmentReview $record): ?string { return $this->reviewOutcome($record)->primaryBadge->icon; } - private function reviewOutcomeBadgeIconColor(TenantReview $record): ?string + private function reviewOutcomeBadgeIconColor(EnvironmentReview $record): ?string { return $this->reviewOutcome($record)->primaryBadge->iconColor; } - private function reviewOutcomeDescription(TenantReview $record): ?string + private function reviewOutcomeDescription(EnvironmentReview $record): ?string { $primaryReason = $this->reviewOutcome($record)->primaryReason; $findingOutcomeSummary = $this->findingOutcomeSummary($record); @@ -382,12 +382,12 @@ private function reviewOutcomeDescription(TenantReview $record): ?string return trim($primaryReason.' Terminal outcomes: '.$findingOutcomeSummary.'.'); } - private function reviewOutcomeNextStep(TenantReview $record): string + private function reviewOutcomeNextStep(EnvironmentReview $record): string { return $this->reviewOutcome($record)->nextActionText; } - private function reviewOutcome(TenantReview $record, bool $fresh = false): CompressedGovernanceOutcome + private function reviewOutcome(EnvironmentReview $record, bool $fresh = false): CompressedGovernanceOutcome { $presenter = app(ArtifactTruthPresenter::class); $truth = $fresh @@ -401,7 +401,7 @@ private function reviewOutcome(TenantReview $record, bool $fresh = false): Compr ); } - private function findingOutcomeSummary(TenantReview $record): ?string + private function findingOutcomeSummary(EnvironmentReview $record): ?string { $summary = is_array($record->summary) ? $record->summary : []; $outcomeCounts = $summary['finding_outcomes'] ?? []; diff --git a/apps/platform/app/Filament/Pages/Tenancy/RegisterTenant.php b/apps/platform/app/Filament/Pages/Tenancy/RegisterTenant.php index 7ba646d5..fb9b8259 100644 --- a/apps/platform/app/Filament/Pages/Tenancy/RegisterTenant.php +++ b/apps/platform/app/Filament/Pages/Tenancy/RegisterTenant.php @@ -6,7 +6,7 @@ use App\Models\User; use App\Models\WorkspaceMembership; use App\Services\Auth\ManagedEnvironmentAccessScopeResolver; -use App\Services\Auth\TenantMembershipManager; +use App\Services\Auth\ManagedEnvironmentMembershipManager; use App\Support\Workspaces\WorkspaceContext; use Filament\Forms; use Filament\Pages\Tenancy\RegisterTenant as BaseRegisterTenant; @@ -105,7 +105,7 @@ protected function handleRegistration(array $data): Model ->allowedManagedEnvironmentIdsForWorkspace($user, $workspaceId); if (is_array($explicitScopes)) { - app(TenantMembershipManager::class)->grantScope( + app(ManagedEnvironmentMembershipManager::class)->grantScope( tenant: $tenant, actor: $user, member: $user, diff --git a/apps/platform/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php b/apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentOnboardingWizard.php similarity index 91% rename from apps/platform/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php rename to apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentOnboardingWizard.php index 63bd8558..680e4c35 100644 --- a/apps/platform/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php +++ b/apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentOnboardingWizard.php @@ -7,7 +7,7 @@ use BackedEnum; use App\Exceptions\Onboarding\OnboardingDraftConflictException; use App\Exceptions\Onboarding\OnboardingDraftImmutableException; -use App\Filament\Resources\TenantResource; +use App\Filament\Resources\ManagedEnvironmentResource; use App\Filament\Support\VerificationReportChangeIndicator; use App\Filament\Support\VerificationReportViewer; use App\Jobs\ProviderComplianceSnapshotJob; @@ -16,14 +16,14 @@ use App\Models\OperationRun; use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\VerificationCheckAcknowledgement; use App\Models\Workspace; use App\Services\Audit\WorkspaceAuditLogger; -use App\Services\Auth\TenantMembershipManager; +use App\Services\Auth\ManagedEnvironmentMembershipManager; use App\Services\Intune\AuditLogger; -use App\Services\Intune\TenantRequiredPermissionsViewModelBuilder; +use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder; use App\Services\Onboarding\OnboardingDraftMutationService; use App\Services\Onboarding\OnboardingDraftResolver; use App\Services\Onboarding\OnboardingDraftStageResolver; @@ -102,7 +102,7 @@ use RuntimeException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class ManagedTenantOnboardingWizard extends Page +class ManagedEnvironmentOnboardingWizard extends Page { use AuthorizesRequests; @@ -114,7 +114,7 @@ class ManagedTenantOnboardingWizard extends Page protected static bool $isDiscovered = false; - protected static ?string $title = 'Managed tenant onboarding'; + protected static ?string $title = 'Managed environment onboarding'; protected static ?string $slug = 'onboarding'; @@ -132,12 +132,12 @@ protected function getLayoutData(): array public Workspace $workspace; - public ?ManagedEnvironment $managedTenant = null; + public ?ManagedEnvironment $managedEnvironment = null; #[Locked] - public ?int $managedTenantId = null; + public ?int $managedEnvironmentId = null; - public ?TenantOnboardingSession $onboardingSession = null; + public ?ManagedEnvironmentOnboardingSession $onboardingSession = null; #[Locked] public ?int $onboardingSessionId = null; @@ -169,7 +169,7 @@ protected function getHeaderActions(): array { $actions = []; $draft = $this->currentOnboardingSessionRecord(); - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (isset($this->workspace)) { $actions[] = Action::make('back_to_workspace') @@ -185,9 +185,9 @@ protected function getHeaderActions(): array ->url(route('admin.onboarding')); } - if ($this->canViewLinkedTenant()) { - $actions[] = Action::make('view_linked_tenant') - ->label($this->linkedTenantActionLabel()) + if ($this->canViewLinkedEnvironment()) { + $actions[] = Action::make('view_linked_environment') + ->label($this->linkedEnvironmentActionLabel()) ->color('gray') ->url($tenant instanceof ManagedEnvironment ? ManagedEnvironmentLinks::viewUrl($tenant) : null); } @@ -199,7 +199,7 @@ protected function getHeaderActions(): array ->requiresConfirmation() ->modalHeading('Cancel onboarding draft') ->modalDescription('This draft will become non-resumable. Confirm only if you intend to stop this onboarding flow.') - ->visible(fn (): bool => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL)) + ->visible(fn (): bool => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL)) ->action(fn () => $this->cancelOnboardingDraft()); } @@ -209,19 +209,19 @@ protected function getHeaderActions(): array ->color('danger') ->requiresConfirmation() ->modalHeading('Delete onboarding draft') - ->modalDescription('This permanently deletes the onboarding draft record. The linked tenant record, if any, is not deleted.') + ->modalDescription('This permanently deletes the onboarding draft record. The linked environment record, if any, is not deleted.') ->modalSubmitActionLabel('Delete draft') - ->visible(fn (): bool => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL)) + ->visible(fn (): bool => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL)) ->action(fn () => $this->deleteOnboardingDraft()); } return $actions; } - private function canViewLinkedTenant(): bool + private function canViewLinkedEnvironment(): bool { $user = auth()->user(); - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $user instanceof User || ! $tenant instanceof ManagedEnvironment) { return false; @@ -240,21 +240,21 @@ private function canViewLinkedTenant(): bool )->allowed; } - private function linkedTenantActionLabel(): string + private function linkedEnvironmentActionLabel(): string { - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $tenant instanceof ManagedEnvironment) { - return 'View tenant'; + return 'View environment'; } return sprintf( - 'View tenant (%s)', + 'View environment (%s)', TenantLifecyclePresentation::fromTenant($tenant)->label, ); } - public function mount(TenantOnboardingSession|int|string|null $onboardingDraft = null): void + public function mount(ManagedEnvironmentOnboardingSession|int|string|null $onboardingDraft = null): void { $user = auth()->user(); @@ -286,7 +286,7 @@ public function mount(TenantOnboardingSession|int|string|null $onboardingDraft = $this->workspace = $workspace; - $this->authorize('viewAny', TenantOnboardingSession::class); + $this->authorize('viewAny', ManagedEnvironmentOnboardingSession::class); if ($onboardingDraft !== null) { $this->loadOnboardingDraft($user, $onboardingDraft); @@ -316,18 +316,18 @@ public function content(Schema $schema): Schema return $schema ->statePath('data') ->schema([ - SchemaView::make('filament.schemas.components.managed-tenant-onboarding-checkpoint-poll') + SchemaView::make('filament.schemas.components.managed-environment-onboarding-checkpoint-poll') ->visible(fn (): bool => $this->shouldPollCheckpointLifecycle()), ...$this->resumeContextSchema(), ...$this->routeBoundReadinessSchema(), Wizard::make([ - Step::make('Identify managed tenant') - ->description('Create or resume a managed tenant in this workspace.') + Step::make('Identify managed environment') + ->description('Create or resume a managed environment in this workspace.') ->schema([ - Section::make('ManagedEnvironment') + Section::make('Managed environment') ->schema([ TextInput::make('entra_tenant_id') - ->label('ManagedEnvironment ID (GUID)') + ->label('Entra tenant ID (GUID)') ->required() ->placeholder('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') ->rules(['uuid']) @@ -358,22 +358,22 @@ public function content(Schema $schema): Schema ->afterValidation(function (): void { $entraTenantId = (string) ($this->data['entra_tenant_id'] ?? ''); $environment = (string) ($this->data['environment'] ?? 'other'); - $tenantName = (string) ($this->data['name'] ?? ''); + $environmentName = (string) ($this->data['name'] ?? ''); $primaryDomain = (string) ($this->data['primary_domain'] ?? ''); $notes = (string) ($this->data['notes'] ?? ''); try { - $this->identifyManagedTenant([ + $this->identifyManagedEnvironment([ 'entra_tenant_id' => $entraTenantId, 'environment' => $environment, - 'name' => $tenantName, + 'name' => $environmentName, 'primary_domain' => $primaryDomain, 'notes' => $notes, ]); } catch (NotFoundHttpException) { Notification::make() ->title('ManagedEnvironment not available') - ->body('This tenant cannot be onboarded in this workspace.') + ->body('This environment cannot be onboarded in this workspace.') ->danger() ->send(); @@ -414,8 +414,8 @@ public function content(Schema $schema): Schema ->closeModalByClickingAway(false) ->visible(fn (Get $get): bool => $get('connection_mode') === 'existing' && is_numeric($get('provider_connection_id'))) - ->disabled(fn (): bool => ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE)) - ->tooltip(fn (): ?string => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE) + ->disabled(fn (): bool => ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE)) + ->tooltip(fn (): ?string => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE) ? null : 'You don\'t have permission to edit connections.') ->fillForm(function (Get $get): array { @@ -474,7 +474,7 @@ public function content(Schema $schema): Schema ->visible(fn (Get $get): bool => $get('connection_mode') === 'new'), TextInput::make('new_connection.target_scope_id') ->label('Target scope ID') - ->default(fn (): string => $this->currentManagedTenantRecord()?->managed_environment_id ?? '') + ->default(fn (): string => $this->currentManagedEnvironmentRecord()?->managed_environment_id ?? '') ->disabled() ->dehydrated(false) ->visible(fn (Get $get): bool => $get('connection_mode') === 'new') @@ -517,7 +517,7 @@ public function content(Schema $schema): Schema ]), ]) ->afterValidation(function (): void { - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { throw new Halt; } @@ -566,9 +566,9 @@ public function content(Schema $schema): Schema SchemaActions::make([ Action::make('wizardStartVerification') ->label('Start verification') - ->visible(fn (): bool => $this->managedTenant instanceof ManagedEnvironment && ! $this->verificationRunIsActive()) - ->disabled(fn (): bool => ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START)) - ->tooltip(fn (): ?string => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START) + ->visible(fn (): bool => $this->managedEnvironment instanceof ManagedEnvironment && ! $this->verificationRunIsActive()) + ->disabled(fn (): bool => ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START)) + ->tooltip(fn (): ?string => $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START) ? null : 'You do not have permission to start verification.') ->action(fn () => $this->startVerification()), @@ -580,9 +580,9 @@ public function content(Schema $schema): Schema ViewField::make('verification_report') ->label('') ->default(null) - ->view('filament.forms.components.managed-tenant-onboarding-verification-report') + ->view('filament.forms.components.managed-environment-onboarding-verification-report') ->viewData(fn (): array => $this->verificationReportViewData()) - ->visible(fn (): bool => $this->managedTenant instanceof ManagedEnvironment), + ->visible(fn (): bool => $this->managedEnvironment instanceof ManagedEnvironment), ]), ]) ->beforeValidation(function (): void { @@ -611,7 +611,7 @@ public function content(Schema $schema): Schema SchemaActions::make([ Action::make('wizardStartBootstrap') ->label('Start bootstrap') - ->visible(fn (): bool => $this->managedTenant instanceof ManagedEnvironment) + ->visible(fn (): bool => $this->managedEnvironment instanceof ManagedEnvironment) ->disabled(fn (): bool => ! $this->canStartAnyBootstrap()) ->tooltip(fn (): ?string => $this->canStartAnyBootstrap() ? null @@ -636,18 +636,18 @@ public function content(Schema $schema): Schema }), Step::make('Complete') - ->description('Review configuration and complete onboarding for this tenant.') + ->description('Review configuration and complete onboarding for this environment.') ->schema([ Section::make('Review & Complete onboarding') - ->description('Review the onboarding summary before completing onboarding for this tenant.') + ->description('Review the onboarding summary before completing onboarding for this environment.') ->schema([ Section::make('Onboarding summary') ->compact() ->columns(2) ->schema([ - Text::make('ManagedEnvironment') + Text::make('Managed environment') ->color('gray'), - Text::make(fn (): string => $this->completionSummaryTenantLine()) + Text::make(fn (): string => $this->completionSummaryEnvironmentLine()) ->weight(FontWeight::SemiBold), Text::make('Provider connection') ->color('gray'), @@ -691,7 +691,7 @@ public function content(Schema $schema): Schema ->label('Override blocked verification') ->helperText('Owner-only. Requires a reason and will be recorded in the audit log.') ->visible(fn (): bool => $this->verificationStatus() === 'blocked' - && $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE)), + && $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE)), Textarea::make('override_reason') ->label('Override reason') ->required(fn (Get $get): bool => (bool) $get('override_blocked')) @@ -704,12 +704,12 @@ public function content(Schema $schema): Schema ->color('success') ->requiresConfirmation() ->modalHeading('Complete onboarding') - ->modalDescription(fn (): string => $this->managedTenant instanceof ManagedEnvironment - ? sprintf('Are you sure you want to complete onboarding for "%s"? This will make the tenant operational.', $this->managedTenant->name) - : 'Are you sure you want to complete onboarding for this tenant?') + ->modalDescription(fn (): string => $this->managedEnvironment instanceof ManagedEnvironment + ? sprintf('Are you sure you want to complete onboarding for "%s"? This will make the environment operational.', $this->managedEnvironment->name) + : 'Are you sure you want to complete onboarding for this environment?') ->modalSubmitActionLabel('Yes, complete onboarding') ->disabled(fn (): bool => ! $this->canCompleteOnboarding() - || ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE)) + || ! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE)) ->tooltip(fn (): ?string => $this->completionActionTooltip()) ->action(fn () => $this->completeOnboarding()), ]), @@ -733,7 +733,7 @@ private function resolveLandingState(User $user): bool if ($drafts->count() === 1) { $draft = $drafts->first(); - if ($draft instanceof TenantOnboardingSession) { + if ($draft instanceof ManagedEnvironmentOnboardingSession) { $this->redirect(route('admin.onboarding.draft', ['onboardingDraft' => $draft])); return true; @@ -747,7 +747,7 @@ private function resolveLandingState(User $user): bool return false; } - private function loadOnboardingDraft(User $user, TenantOnboardingSession|int|string $onboardingDraft): void + private function loadOnboardingDraft(User $user, ManagedEnvironmentOnboardingSession|int|string $onboardingDraft): void { $draft = app(OnboardingDraftResolver::class)->resolve($onboardingDraft, $user, $this->workspace); @@ -755,10 +755,10 @@ private function loadOnboardingDraft(User $user, TenantOnboardingSession|int|str $this->showStartState = false; $this->setOnboardingSession($draft); - $tenant = $draft->tenant; + $tenant = $draft->managedEnvironment; if ($tenant instanceof ManagedEnvironment && (int) $tenant->workspace_id === (int) $this->workspace->getKey()) { - $this->setManagedTenant($tenant); + $this->setManagedEnvironment($tenant); } $providerConnectionId = $draft->state['provider_connection_id'] ?? null; @@ -828,8 +828,8 @@ private function normalizeBootstrapOperationType(string $operationType): string private function supportedBootstrapCapabilities(): array { return [ - 'inventory.sync' => Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, - 'compliance.snapshot' => Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_POLICY_SYNC, + 'inventory.sync' => Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, + 'compliance.snapshot' => Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_POLICY_SYNC, ]; } @@ -844,7 +844,7 @@ private function persistBootstrapSelection(array $operationTypes): void abort(403); } - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return; } @@ -864,7 +864,7 @@ private function persistBootstrapSelection(array $operationTypes): void actor: $user, expectedVersion: $this->expectedDraftVersion(), incrementVersion: false, - mutator: function (TenantOnboardingSession $draft) use ($normalized): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($normalized): void { $state = is_array($draft->state) ? $draft->state : []; $state['bootstrap_operation_types'] = $normalized; @@ -883,7 +883,7 @@ private function persistBootstrapSelection(array $operationTypes): void } /** - * @return Collection + * @return Collection */ private function availableDraftsFor(User $user): Collection { @@ -962,7 +962,7 @@ private function resumeContextSchema(): array { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return []; } @@ -999,7 +999,7 @@ private function routeBoundReadinessSchema(): array { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return []; } @@ -1045,7 +1045,7 @@ private function routeBoundReadinessSchema(): array /** * @return array */ - private function draftCompactReadinessSchema(TenantOnboardingSession $draft): array + private function draftCompactReadinessSchema(ManagedEnvironmentOnboardingSession $draft): array { $payload = $this->onboardingReadinessPayload($draft); @@ -1203,7 +1203,7 @@ private function readinessPermissionDiagnosticsSchema(array $payload, string $ke /** * @return array{ - * draft: array{id: int, tenant_name: string, stage_label: string, draft_status_label: string, started_by: string, updated_by: string, last_updated_human: string}, + * draft: array{id: int, environment_name: string, stage_label: string, draft_status_label: string, started_by: string, updated_by: string, last_updated_human: string}, * checkpoint: array{current_checkpoint: string|null, current_checkpoint_label: string|null, last_completed_checkpoint: string|null, lifecycle_state: string, lifecycle_label: string}, * provider_summary: array|null, * verification: array{status: string, status_label: string, run_id: int|null, run_url: string|null, is_active: bool, has_report: bool, matches_selected_connection: bool|null, overall: string|null}, @@ -1215,7 +1215,7 @@ private function readinessPermissionDiagnosticsSchema(array $payload, string $ke * supporting_links: list * } */ - private function onboardingReadinessPayload(TenantOnboardingSession $draft): array + private function onboardingReadinessPayload(ManagedEnvironmentOnboardingSession $draft): array { $snapshot = $this->lifecycleService()->snapshot($draft); $stage = app(OnboardingDraftStageResolver::class)->resolve($draft); @@ -1229,7 +1229,7 @@ private function onboardingReadinessPayload(TenantOnboardingSession $draft): arr ? $snapshot['last_completed_checkpoint'] : null; - $tenant = $draft->tenant instanceof ManagedEnvironment ? $draft->tenant : null; + $tenant = $draft->managedEnvironment instanceof ManagedEnvironment ? $draft->managedEnvironment : null; $providerConnection = $this->readinessProviderConnection($draft); $selectedProviderConnectionId = $providerConnection instanceof ProviderConnection ? (int) $providerConnection->getKey() @@ -1275,7 +1275,7 @@ private function onboardingReadinessPayload(TenantOnboardingSession $draft): arr return [ 'draft' => [ 'id' => (int) $draft->getKey(), - 'tenant_name' => $this->draftTitle($draft), + 'environment_name' => $this->draftTitle($draft), 'stage_label' => $stage->label(), 'draft_status_label' => $draft->status()->label(), 'started_by' => $draft->startedByUser?->name ?? 'Unknown', @@ -1292,7 +1292,7 @@ private function onboardingReadinessPayload(TenantOnboardingSession $draft): arr 'provider_summary' => $this->readinessProviderSummary($providerConnection), 'verification' => [ 'status' => $verificationStatus, - 'status_label' => BadgeCatalog::spec(BadgeDomain::ManagedTenantOnboardingVerificationStatus, $verificationStatus)->label, + 'status_label' => BadgeCatalog::spec(BadgeDomain::ManagedEnvironmentOnboardingVerificationStatus, $verificationStatus)->label, 'run_id' => $verificationRun instanceof OperationRun ? (int) $verificationRun->getKey() : null, 'run_url' => $verificationRun instanceof OperationRun && $this->canInspectOperationRun($verificationRun) ? OperationRunLinks::tenantlessView($verificationRun) @@ -1440,7 +1440,7 @@ private function readinessPrimaryNextActionComponent(array $payload, string $key ->color($this->readinessNextActionColor($kind)); } - private function readinessProviderConnection(TenantOnboardingSession $draft): ?ProviderConnection + private function readinessProviderConnection(ManagedEnvironmentOnboardingSession $draft): ?ProviderConnection { $state = is_array($draft->state) ? $draft->state : []; $providerConnectionId = $this->normalizeReadinessInteger( @@ -1494,7 +1494,7 @@ private function readinessProviderSummary(?ProviderConnection $connection): ?arr */ private function readinessPermissionOverview(ManagedEnvironment $tenant): array { - $viewModel = app(TenantRequiredPermissionsViewModelBuilder::class)->build($tenant, [ + $viewModel = app(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class)->build($tenant, [ 'status' => 'all', 'type' => 'all', 'features' => [], @@ -1656,7 +1656,7 @@ private function readinessFreshnessNote( * @param array|null $permissions */ private function readinessSummaryText( - TenantOnboardingSession $draft, + ManagedEnvironmentOnboardingSession $draft, OnboardingLifecycleState $lifecycleState, ?ProviderConnection $providerConnection, ?OperationRun $verificationRun, @@ -1665,7 +1665,7 @@ private function readinessSummaryText( bool $connectionRecentlyUpdated, bool $verificationMismatch, ): string { - if (! $this->readinessDraftHasTenantIdentity($draft)) { + if (! $this->readinessDraftHasEnvironmentIdentity($draft)) { return 'ManagedEnvironment identity required'; } @@ -1736,7 +1736,7 @@ private function readinessSummaryText( * @return array{label: string, kind: string, url: string|null, action_name: string|null, required_capability: string|null} */ private function readinessNextAction( - TenantOnboardingSession $draft, + ManagedEnvironmentOnboardingSession $draft, OnboardingLifecycleState $lifecycleState, ?ProviderConnection $providerConnection, ?OperationRun $verificationRun, @@ -1747,8 +1747,8 @@ private function readinessNextAction( bool $verificationMismatch, array $supportingLinks, ): array { - if (! $this->readinessDraftHasTenantIdentity($draft)) { - return $this->readinessAction('Identify tenant', 'start_onboarding'); + if (! $this->readinessDraftHasEnvironmentIdentity($draft)) { + return $this->readinessAction('Identify environment', 'start_onboarding'); } if (! $providerConnection instanceof ProviderConnection) { @@ -1770,7 +1770,7 @@ private function readinessNextAction( return $this->readinessAction( label: 'Grant admin consent', kind: 'grant_consent', - url: $draft->tenant instanceof ManagedEnvironment ? RequiredPermissionsLinks::adminConsentPrimaryUrl($draft->tenant) : null, + url: $draft->managedEnvironment instanceof ManagedEnvironment ? RequiredPermissionsLinks::adminConsentPrimaryUrl($draft->managedEnvironment) : null, ); } @@ -1784,7 +1784,7 @@ private function readinessNextAction( return $this->readinessAction( label: 'Grant admin consent', kind: 'grant_consent', - url: $draft->tenant instanceof ManagedEnvironment ? RequiredPermissionsLinks::adminConsentPrimaryUrl($draft->tenant) : null, + url: $draft->managedEnvironment instanceof ManagedEnvironment ? RequiredPermissionsLinks::adminConsentPrimaryUrl($draft->managedEnvironment) : null, ); } @@ -1792,7 +1792,7 @@ private function readinessNextAction( return $this->readinessAction( label: 'Review provider capability', kind: 'review_permissions', - url: $draft->tenant instanceof ManagedEnvironment ? RequiredPermissionsLinks::requiredPermissions($draft->tenant) : null, + url: $draft->managedEnvironment instanceof ManagedEnvironment ? RequiredPermissionsLinks::requiredPermissions($draft->managedEnvironment) : null, ); } @@ -1801,7 +1801,7 @@ private function readinessNextAction( label: 'Start verification', kind: 'start_verification', actionName: 'wizardStartVerification', - requiredCapability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START, + requiredCapability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START, ); } @@ -1810,7 +1810,7 @@ private function readinessNextAction( label: 'Rerun verification', kind: 'rerun_verification', actionName: 'wizardStartVerification', - requiredCapability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START, + requiredCapability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START, ); } @@ -1831,7 +1831,7 @@ private function readinessNextAction( label: 'Complete onboarding', kind: 'complete_onboarding', actionName: 'wizardCompleteOnboarding', - requiredCapability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE, + requiredCapability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE, ); } @@ -1860,7 +1860,7 @@ private function readinessAction( /** * @return list */ - private function readinessSupportingLinks(?OperationRun $verificationRun, TenantOnboardingSession $draft, ?int $selectedProviderConnectionId): array + private function readinessSupportingLinks(?OperationRun $verificationRun, ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId): array { $links = []; @@ -1919,14 +1919,14 @@ private function readinessRunMatchesSelectedConnection(OperationRun $run, ?int $ return $runProviderConnectionId !== null && $runProviderConnectionId === $selectedProviderConnectionId; } - private function readinessConnectionRecentlyUpdated(TenantOnboardingSession $draft): bool + private function readinessConnectionRecentlyUpdated(ManagedEnvironmentOnboardingSession $draft): bool { $state = is_array($draft->state) ? $draft->state : []; return (bool) ($state['connection_recently_updated'] ?? false); } - private function readinessDraftHasTenantIdentity(TenantOnboardingSession $draft): bool + private function readinessDraftHasEnvironmentIdentity(ManagedEnvironmentOnboardingSession $draft): bool { if ($draft->managed_environment_id !== null) { return true; @@ -1964,7 +1964,7 @@ private function nonResumableSummarySchema(): array { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return []; } @@ -2008,7 +2008,7 @@ private function nonResumableSummarySchema(): array ->color('danger') ->requiresConfirmation() ->modalHeading('Delete onboarding draft') - ->modalDescription('This permanently deletes the onboarding draft record. The linked tenant record, if any, is not deleted.') + ->modalDescription('This permanently deletes the onboarding draft record. The linked environment record, if any, is not deleted.') ->modalSubmitActionLabel('Delete draft') ->visible(fn (): bool => $this->canDeleteDraft($this->currentOnboardingSessionRecord() ?? $draft)) ->action(fn () => $this->deleteOnboardingDraft()), @@ -2020,7 +2020,7 @@ private function startNewOnboardingDraft(): void { $this->showDraftPicker = false; $this->showStartState = true; - $this->setManagedTenant(null); + $this->setManagedEnvironment(null); $this->setOnboardingSession(null); $this->selectedProviderConnectionId = null; $this->selectedBootstrapOperationTypes = []; @@ -2042,7 +2042,7 @@ private function resumeOnboardingDraft(int $draftId, bool $logSelection): void if ($logSelection) { app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingDraftSelected->value, + action: AuditActionId::ManagedEnvironmentOnboardingDraftSelected->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -2052,7 +2052,7 @@ private function resumeOnboardingDraft(int $draftId, bool $logSelection): void ], actor: $user, status: 'success', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $draft->getKey(), ); } @@ -2068,7 +2068,7 @@ private function cancelOnboardingDraft(): void abort(403); } - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { abort(404); } @@ -2099,7 +2099,7 @@ private function cancelOnboardingDraft(): void draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft): void { $draft->current_step = 'cancelled'; $draft->completed_at = null; $draft->cancelled_at = now(); @@ -2117,7 +2117,7 @@ private function cancelOnboardingDraft(): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingCancelled->value, + action: AuditActionId::ManagedEnvironmentOnboardingCancelled->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -2127,7 +2127,7 @@ private function cancelOnboardingDraft(): void ], actor: $user, status: 'success', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $this->onboardingSession->getKey(), ); @@ -2146,7 +2146,7 @@ private function cancelOnboardingDraft(): void ], ); - $this->setManagedTenant($normalizedTenant); + $this->setManagedEnvironment($normalizedTenant); } Notification::make() @@ -2165,7 +2165,7 @@ private function deleteOnboardingDraft(): void abort(403); } - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { abort(404); } @@ -2201,7 +2201,7 @@ private function deleteOnboardingDraft(): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingDeleted->value, + action: AuditActionId::ManagedEnvironmentOnboardingDeleted->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -2213,12 +2213,12 @@ private function deleteOnboardingDraft(): void ], actor: $user, status: 'success', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $draftId, targetLabel: $draftTitle, ); - $this->setManagedTenant(null); + $this->setManagedEnvironment(null); $this->setOnboardingSession(null); Notification::make() @@ -2233,15 +2233,15 @@ private function showsNonResumableSummary(): bool { $draft = $this->currentOnboardingSessionRecord(); - return $draft instanceof TenantOnboardingSession + return $draft instanceof ManagedEnvironmentOnboardingSession && ! $this->canResumeDraft($draft); } - private function canDeleteDraft(?TenantOnboardingSession $draft): bool + private function canDeleteDraft(?ManagedEnvironmentOnboardingSession $draft): bool { - return $draft instanceof TenantOnboardingSession + return $draft instanceof ManagedEnvironmentOnboardingSession && ! $this->canResumeDraft($draft) - && $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL); + && $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL); } private function onboardingDraftLandingActionLabel(): string @@ -2262,14 +2262,14 @@ private function resumeOnboardingActionLabel(): string private function onboardingEntryActionDescriptor(int $resumableDraftCount): \App\Support\Tenants\TenantActionDescriptor { - return TenantResource::tenantActionPolicy()->onboardingEntryDescriptor($resumableDraftCount); + return ManagedEnvironmentResource::tenantActionPolicy()->onboardingEntryDescriptor($resumableDraftCount); } private function shouldShowDraftLandingAction(): bool { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return false; } @@ -2290,21 +2290,21 @@ private function shouldShowDraftLandingAction(): bool return $this->availableDraftsFor($user)->count() > 1; } - private function draftTitle(TenantOnboardingSession $draft): string + private function draftTitle(ManagedEnvironmentOnboardingSession $draft): string { $state = is_array($draft->state) ? $draft->state : []; - $tenantName = $state['tenant_name'] ?? $draft->tenant?->name ?? null; - $tenantName = is_string($tenantName) && trim($tenantName) !== '' ? trim($tenantName) : 'Unidentified tenant'; + $environmentName = $state['environment_name'] ?? $draft->managedEnvironment?->name ?? null; + $environmentName = is_string($environmentName) && trim($environmentName) !== '' ? trim($environmentName) : 'Unidentified environment'; $entraTenantId = $state['entra_tenant_id'] ?? $draft->entra_tenant_id; if (is_string($entraTenantId) && trim($entraTenantId) !== '') { - return sprintf('%s (%s)', $tenantName, trim($entraTenantId)); + return sprintf('%s (%s)', $environmentName, trim($entraTenantId)); } - return $tenantName; + return $environmentName; } - private function draftDescription(TenantOnboardingSession $draft): string + private function draftDescription(ManagedEnvironmentOnboardingSession $draft): string { $state = is_array($draft->state) ? $draft->state : []; $environment = $state['environment'] ?? null; @@ -2316,12 +2316,12 @@ private function draftDescription(TenantOnboardingSession $draft): string ])->filter()->implode(' · '); } - private function draftStageLabel(TenantOnboardingSession $draft): string + private function draftStageLabel(ManagedEnvironmentOnboardingSession $draft): string { return app(OnboardingDraftStageResolver::class)->resolve($draft)->label(); } - private function draftStageColor(TenantOnboardingSession $draft): string + private function draftStageColor(ManagedEnvironmentOnboardingSession $draft): string { return match (app(OnboardingDraftStageResolver::class)->resolve($draft)) { OnboardingDraftStage::Identify => 'gray', @@ -2334,7 +2334,7 @@ private function draftStageColor(TenantOnboardingSession $draft): string }; } - private function draftStatusColor(TenantOnboardingSession $draft): string + private function draftStatusColor(ManagedEnvironmentOnboardingSession $draft): string { return match ($draft->status()->value) { 'draft' => 'info', @@ -2368,46 +2368,46 @@ private function expectedDraftVersion(): ?int : null; } - private function setOnboardingSession(?TenantOnboardingSession $draft): void + private function setOnboardingSession(?ManagedEnvironmentOnboardingSession $draft): void { $this->onboardingSession = $draft; - $this->onboardingSessionId = $draft instanceof TenantOnboardingSession + $this->onboardingSessionId = $draft instanceof ManagedEnvironmentOnboardingSession ? (int) $draft->getKey() : null; - $this->onboardingSessionVersion = $draft instanceof TenantOnboardingSession + $this->onboardingSessionVersion = $draft instanceof ManagedEnvironmentOnboardingSession ? $draft->expectedVersion() : null; - if ($draft instanceof TenantOnboardingSession && $draft->tenant instanceof ManagedEnvironment) { - $this->setManagedTenant($draft->tenant); + if ($draft instanceof ManagedEnvironmentOnboardingSession && $draft->managedEnvironment instanceof ManagedEnvironment) { + $this->setManagedEnvironment($draft->managedEnvironment); return; } - if ($draft instanceof TenantOnboardingSession && $draft->managed_environment_id !== null) { - $this->managedTenantId = (int) $draft->managed_environment_id; + if ($draft instanceof ManagedEnvironmentOnboardingSession && $draft->managed_environment_id !== null) { + $this->managedEnvironmentId = (int) $draft->managed_environment_id; return; } - $this->setManagedTenant(null); + $this->setManagedEnvironment(null); } - private function setManagedTenant(?ManagedEnvironment $tenant): void + private function setManagedEnvironment(?ManagedEnvironment $tenant): void { - $this->managedTenant = $tenant; - $this->managedTenantId = $tenant instanceof ManagedEnvironment + $this->managedEnvironment = $tenant; + $this->managedEnvironmentId = $tenant instanceof ManagedEnvironment ? (int) $tenant->getKey() : null; - if ($this->onboardingSession instanceof TenantOnboardingSession && $tenant instanceof ManagedEnvironment) { - $this->onboardingSession->setRelation('tenant', $tenant); + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession && $tenant instanceof ManagedEnvironment) { + $this->onboardingSession->setRelation('managedEnvironment', $tenant); } } - private function currentOnboardingSessionRecord(): ?TenantOnboardingSession + private function currentOnboardingSessionRecord(): ?ManagedEnvironmentOnboardingSession { - if ($this->onboardingSession instanceof TenantOnboardingSession + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession && $this->onboardingSessionId !== null && (int) $this->onboardingSession->getKey() === $this->onboardingSessionId) { return $this->onboardingSession; @@ -2417,8 +2417,8 @@ private function currentOnboardingSessionRecord(): ?TenantOnboardingSession return $this->onboardingSession; } - $query = TenantOnboardingSession::query() - ->with(['tenant', 'startedByUser', 'updatedByUser']) + $query = ManagedEnvironmentOnboardingSession::query() + ->with(['managedEnvironment', 'startedByUser', 'updatedByUser']) ->whereKey($this->onboardingSessionId); if (isset($this->workspace)) { @@ -2428,25 +2428,25 @@ private function currentOnboardingSessionRecord(): ?TenantOnboardingSession return $query->first(); } - private function currentManagedTenantRecord(): ?ManagedEnvironment + private function currentManagedEnvironmentRecord(): ?ManagedEnvironment { $draft = $this->currentOnboardingSessionRecord(); - if ($draft instanceof TenantOnboardingSession && $draft->tenant instanceof ManagedEnvironment) { - return $draft->tenant; + if ($draft instanceof ManagedEnvironmentOnboardingSession && $draft->managedEnvironment instanceof ManagedEnvironment) { + return $draft->managedEnvironment; } - if ($this->managedTenant instanceof ManagedEnvironment - && $this->managedTenantId !== null - && (int) $this->managedTenant->getKey() === $this->managedTenantId) { - return $this->managedTenant; + if ($this->managedEnvironment instanceof ManagedEnvironment + && $this->managedEnvironmentId !== null + && (int) $this->managedEnvironment->getKey() === $this->managedEnvironmentId) { + return $this->managedEnvironment; } - if ($this->managedTenantId === null) { - return $this->managedTenant; + if ($this->managedEnvironmentId === null) { + return $this->managedEnvironment; } - $query = ManagedEnvironment::query()->withTrashed()->whereKey($this->managedTenantId); + $query = ManagedEnvironment::query()->withTrashed()->whereKey($this->managedEnvironmentId); if (isset($this->workspace)) { $query->where('workspace_id', (int) $this->workspace->getKey()); @@ -2459,7 +2459,7 @@ private function refreshOnboardingDraftFromBackend(): void { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return; } @@ -2506,7 +2506,7 @@ private function lifecycleState(): OnboardingLifecycleState { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return OnboardingLifecycleState::Draft; } @@ -2535,7 +2535,7 @@ private function currentCheckpointLabel(): string { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return OnboardingCheckpoint::Identify->label(); } @@ -2547,7 +2547,7 @@ public function shouldPollCheckpointLifecycle(): bool { $draft = $this->currentOnboardingSessionRecord(); - return $draft instanceof TenantOnboardingSession + return $draft instanceof ManagedEnvironmentOnboardingSession && $this->lifecycleService()->hasActiveCheckpoint($draft); } @@ -2555,16 +2555,16 @@ public function refreshCheckpointLifecycle(): void { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return; } $this->setOnboardingSession($this->lifecycleService()->syncPersistedLifecycle($draft)); - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if ($tenant instanceof ManagedEnvironment) { - $this->setManagedTenant($tenant->fresh()); + $this->setManagedEnvironment($tenant->fresh()); } $this->initializeWizardData(); @@ -2591,7 +2591,7 @@ private function initializeWizardData(): void $this->data['new_connection']['is_default'] ??= true; } - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if ($tenant instanceof ManagedEnvironment) { $this->data['entra_tenant_id'] ??= (string) $tenant->managed_environment_id; @@ -2608,7 +2608,7 @@ private function initializeWizardData(): void $draft = $this->currentOnboardingSessionRecord(); - if ($draft instanceof TenantOnboardingSession) { + if ($draft instanceof ManagedEnvironmentOnboardingSession) { $state = is_array($draft->state) ? $draft->state : []; if (isset($state['entra_tenant_id']) && is_string($state['entra_tenant_id']) && trim($state['entra_tenant_id']) !== '') { @@ -2619,8 +2619,8 @@ private function initializeWizardData(): void $this->data['environment'] ??= trim($state['environment']); } - if (isset($state['tenant_name']) && is_string($state['tenant_name']) && trim($state['tenant_name']) !== '') { - $this->data['name'] ??= trim($state['tenant_name']); + if (isset($state['environment_name']) && is_string($state['environment_name']) && trim($state['environment_name']) !== '') { + $this->data['name'] ??= trim($state['environment_name']); } if (array_key_exists('primary_domain', $state)) { @@ -2672,7 +2672,7 @@ private function computeWizardStartStep(): int */ private function providerConnectionOptions(): array { - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $tenant instanceof ManagedEnvironment) { return []; @@ -2735,7 +2735,7 @@ private function providerConnectionTargetScopeAuditMetadata(ProviderConnection $ private function verificationStatusLabel(): string { return BadgeCatalog::spec( - BadgeDomain::ManagedTenantOnboardingVerificationStatus, + BadgeDomain::ManagedEnvironmentOnboardingVerificationStatus, $this->verificationStatus(), )->label; } @@ -2744,7 +2744,7 @@ private function verificationStatus(): string { $draft = $this->currentOnboardingSessionRecord(); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return 'not_started'; } @@ -2859,7 +2859,7 @@ private function verificationRunIsActive(): bool private function verificationStatusColor(): string { return BadgeCatalog::spec( - BadgeDomain::ManagedTenantOnboardingVerificationStatus, + BadgeDomain::ManagedEnvironmentOnboardingVerificationStatus, $this->verificationStatus(), )->color; } @@ -2937,8 +2937,8 @@ private function verificationReportViewData(): array $previousRunUrl = $this->verificationPreviousRunUrl($changeIndicator); $user = auth()->user(); - $canAcknowledge = $user instanceof User && $this->managedTenant instanceof ManagedEnvironment - ? $user->can(Capabilities::TENANT_VERIFICATION_ACKNOWLEDGE, $this->managedTenant) + $canAcknowledge = $user instanceof User && $this->managedEnvironment instanceof ManagedEnvironment + ? $user->can(Capabilities::TENANT_VERIFICATION_ACKNOWLEDGE, $this->managedEnvironment) : false; $acknowledgements = VerificationCheckAcknowledgement::query() @@ -3032,7 +3032,7 @@ private function verificationReportViewData(): array */ private function verificationContextualHelp(array $verificationReport, OperationRun $run): ?array { - $tenant = $this->managedTenant; + $tenant = $this->managedEnvironment; if (! $tenant instanceof ManagedEnvironment) { return null; @@ -3125,11 +3125,11 @@ public function acknowledgeVerificationCheckAction(): Action abort(403); } - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { abort(404); } - $tenant = $this->managedTenant->fresh(); + $tenant = $this->managedEnvironment->fresh(); if (! $tenant instanceof ManagedEnvironment) { abort(404); @@ -3177,11 +3177,11 @@ public function acknowledgeVerificationCheckAction(): Action return false; } - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { return false; } - if (! $user->can(Capabilities::TENANT_VERIFICATION_ACKNOWLEDGE, $this->managedTenant)) { + if (! $user->can(Capabilities::TENANT_VERIFICATION_ACKNOWLEDGE, $this->managedEnvironment)) { return false; } @@ -3238,7 +3238,7 @@ public function acknowledgeVerificationCheckAction(): Action private function bootstrapRunsLabel(): string { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return ''; } @@ -3270,7 +3270,7 @@ private function touchOnboardingSessionStep(string $step): void abort(403); } - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return; } @@ -3284,7 +3284,7 @@ private function touchOnboardingSessionStep(string $step): void actor: $user, expectedVersion: $this->expectedDraftVersion(), incrementVersion: false, - mutator: function (TenantOnboardingSession $draft) use ($step): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($step): void { $draft->current_step = $step; }, )); @@ -3300,7 +3300,7 @@ private function touchOnboardingSessionStep(string $step): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingDraftUpdated->value, + action: AuditActionId::ManagedEnvironmentOnboardingDraftUpdated->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -3311,7 +3311,7 @@ private function touchOnboardingSessionStep(string $step): void ], actor: $user, status: 'success', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $this->onboardingSession->getKey(), ); } @@ -3327,7 +3327,7 @@ private function authorizeWorkspaceMutation(User $user, string $capability): voi private function authorizeEditableDraft(User $user): void { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return; } @@ -3351,9 +3351,9 @@ private function authorizeEditableDraft(User $user): void } } - private function trustedManagedTenantForUser(User $user): ManagedEnvironment + private function trustedManagedEnvironmentForUser(User $user): ManagedEnvironment { - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $tenant instanceof ManagedEnvironment) { abort(404); @@ -3367,25 +3367,25 @@ private function trustedManagedTenantForUser(User $user): ManagedEnvironment $tenant = app(WorkspaceContext::class)->ensureTenantAccessibleInCurrentWorkspace($tenant, $user, request()); - $this->setManagedTenant($tenant); + $this->setManagedEnvironment($tenant); return $tenant; } - private function canResumeDraft(?TenantOnboardingSession $draft): bool + private function canResumeDraft(?ManagedEnvironmentOnboardingSession $draft): bool { - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return false; } - if (! $draft->tenant instanceof ManagedEnvironment) { + if (! $draft->managedEnvironment instanceof ManagedEnvironment) { return $this->lifecycleService()->canResumeDraft($draft); } $user = $this->currentUser(); return app(TenantOperabilityService::class)->outcomeFor( - tenant: $draft->tenant, + tenant: $draft->managedEnvironment, question: TenantOperabilityQuestion::ResumeOnboardingEligibility, actor: $user instanceof User ? $user : null, workspaceId: isset($this->workspace) ? (int) $this->workspace->getKey() : null, @@ -3403,7 +3403,7 @@ private function authorizeWorkspaceMember(User $user): void ); } - private function resolveWorkspaceIdForUnboundTenant(ManagedEnvironment $tenant): ?int + private function resolveWorkspaceIdForUnboundEnvironment(ManagedEnvironment $tenant): ?int { $workspaceId = DB::table('managed_environment_memberships') ->join('workspace_memberships', 'workspace_memberships.user_id', '=', 'managed_environment_memberships.user_id') @@ -3417,7 +3417,7 @@ private function resolveWorkspaceIdForUnboundTenant(ManagedEnvironment $tenant): /** * @param array{entra_tenant_id: string, environment: string, name: string, primary_domain?: string, notes?: string} $data */ - public function identifyManagedTenant(array $data): void + public function identifyManagedEnvironment(array $data): void { $user = auth()->user(); @@ -3425,15 +3425,15 @@ public function identifyManagedTenant(array $data): void abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_IDENTIFY); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_IDENTIFY); $entraTenantId = (string) ($data['entra_tenant_id'] ?? ''); - $tenantName = (string) ($data['name'] ?? ''); + $environmentName = (string) ($data['name'] ?? ''); $environment = (string) ($data['environment'] ?? 'other'); $primaryDomain = trim((string) ($data['primary_domain'] ?? '')); $notes = trim((string) ($data['notes'] ?? '')); - if ($entraTenantId === '' || $tenantName === '') { + if ($entraTenantId === '' || $environmentName === '') { abort(422); } @@ -3448,9 +3448,9 @@ public function identifyManagedTenant(array $data): void $notificationBody = null; try { - DB::transaction(function () use ($user, $entraTenantId, $tenantName, $environment, $primaryDomain, $notes, &$notificationTitle, &$notificationBody): void { + DB::transaction(function () use ($user, $entraTenantId, $environmentName, $environment, $primaryDomain, $notes, &$notificationTitle, &$notificationBody): void { $auditLogger = app(WorkspaceAuditLogger::class); - $membershipManager = app(TenantMembershipManager::class); + $membershipManager = app(ManagedEnvironmentMembershipManager::class); $currentDraftId = $this->onboardingSession?->getKey(); $sessionWasCreated = false; @@ -3465,7 +3465,7 @@ public function identifyManagedTenant(array $data): void } if ($existingTenant->workspace_id === null) { - $resolvedWorkspaceId = $this->resolveWorkspaceIdForUnboundTenant($existingTenant); + $resolvedWorkspaceId = $this->resolveWorkspaceIdForUnboundEnvironment($existingTenant); if ($resolvedWorkspaceId === (int) $this->workspace->getKey()) { $existingTenant->forceFill(['workspace_id' => $resolvedWorkspaceId])->save(); @@ -3477,7 +3477,7 @@ public function identifyManagedTenant(array $data): void } $existingTenant->forceFill([ - 'name' => $tenantName, + 'name' => $environmentName, 'environment' => $environment, 'domain' => $primaryDomain, 'status' => $existingTenant->status === ManagedEnvironment::STATUS_DRAFT ? ManagedEnvironment::STATUS_ONBOARDING : $existingTenant->status, @@ -3491,7 +3491,7 @@ public function identifyManagedTenant(array $data): void try { $tenant = ManagedEnvironment::query()->create([ 'workspace_id' => (int) $this->workspace->getKey(), - 'name' => $tenantName, + 'name' => $environmentName, 'slug' => $entraTenantId, 'domain' => $primaryDomain, 'environment' => $environment, @@ -3535,12 +3535,12 @@ public function identifyManagedTenant(array $data): void entraTenantId: $entraTenantId, preferredDraft: $this->onboardingSession, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($tenant, $entraTenantId, $tenantName, $environment, $primaryDomain, $notes): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($tenant, $entraTenantId, $environmentName, $environment, $primaryDomain, $notes): void { $draft->managed_environment_id = (int) $tenant->getKey(); $draft->current_step = 'identify'; $draft->state = array_merge($draft->state ?? [], [ 'entra_tenant_id' => $entraTenantId, - 'tenant_name' => $tenantName, + 'environment_name' => $environmentName, 'environment' => $environment, 'primary_domain' => $primaryDomain, 'notes' => $notes, @@ -3562,21 +3562,21 @@ public function identifyManagedTenant(array $data): void ? 'Existing onboarding draft resumed' : 'Onboarding draft ready'; $notificationBody = $didResumeExistingDraft - ? 'A resumable draft already exists for this tenant. TenantAtlas reopened it instead of creating a duplicate.' + ? 'A resumable draft already exists for this environment. TenantAtlas reopened it instead of creating a duplicate.' : null; $auditLogger->log( workspace: $this->workspace, action: ($sessionWasCreated - ? AuditActionId::ManagedTenantOnboardingStart - : AuditActionId::ManagedTenantOnboardingResume + ? AuditActionId::ManagedEnvironmentOnboardingStart + : AuditActionId::ManagedEnvironmentOnboardingResume )->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), 'tenant_db_id' => (int) $tenant->getKey(), 'entra_tenant_id' => $entraTenantId, - 'tenant_name' => $tenantName, + 'environment_name' => $environmentName, 'onboarding_session_id' => (int) $session->getKey(), 'current_step' => (string) $session->current_step, ], @@ -3587,7 +3587,7 @@ public function identifyManagedTenant(array $data): void resourceId: (string) $tenant->getKey(), ); - $this->setManagedTenant($tenant); + $this->setManagedEnvironment($tenant); $this->setOnboardingSession($session); }); } catch (OnboardingDraftConflictException) { @@ -3610,7 +3610,7 @@ public function identifyManagedTenant(array $data): void $notification->send(); - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $this->redirect(route('admin.onboarding.draft', ['onboardingDraft' => $this->onboardingSession])); } } @@ -3623,10 +3623,10 @@ public function selectProviderConnection(int $providerConnectionId): void abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW); $this->authorizeEditableDraft($user); - $tenant = $this->trustedManagedTenantForUser($user); + $tenant = $this->trustedManagedEnvironmentForUser($user); $connection = ProviderConnection::query() ->where('workspace_id', (int) $this->workspace->getKey()) @@ -3642,13 +3642,13 @@ public function selectProviderConnection(int $providerConnectionId): void $this->selectedProviderConnectionId = (int) $connection->getKey(); - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { try { $this->setOnboardingSession($this->mutationService()->mutate( draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($connection, $previousProviderConnectionId): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($connection, $previousProviderConnectionId): void { $draft->state = $this->resetDependentOnboardingStateOnConnectionChange( state: array_merge($draft->state ?? [], [ 'provider_connection_id' => (int) $connection->getKey(), @@ -3672,7 +3672,7 @@ public function selectProviderConnection(int $providerConnectionId): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingProviderConnectionChanged->value, + action: AuditActionId::ManagedEnvironmentOnboardingProviderConnectionChanged->value, context: [ 'metadata' => $this->providerConnectionTargetScopeAuditMetadata($connection, [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -3705,10 +3705,10 @@ public function createProviderConnection(array $data): void abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE); $this->authorizeEditableDraft($user); - $tenant = $this->trustedManagedTenantForUser($user)->fresh(); + $tenant = $this->trustedManagedEnvironmentForUser($user)->fresh(); if (! $tenant instanceof ManagedEnvironment) { abort(404); @@ -3748,7 +3748,7 @@ public function createProviderConnection(array $data): void } if ($usesDedicatedCredential) { - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED); } if ($usesDedicatedCredential && ($clientId === '' || $clientSecret === '')) { @@ -3826,7 +3826,7 @@ public function createProviderConnection(array $data): void 'metadata' => $this->providerConnectionTargetScopeAuditMetadata($connection, [ 'workspace_id' => (int) $this->workspace->getKey(), 'connection_type' => $connection->connection_type->value, - 'source' => 'managed_tenant_onboarding_wizard.create', + 'source' => 'managed_environment_onboarding_wizard.create', ]), ], actorId: $actorId, @@ -3847,7 +3847,7 @@ public function createProviderConnection(array $data): void 'workspace_id' => (int) $this->workspace->getKey(), 'from_connection_type' => $previousConnectionType->value, 'to_connection_type' => $connection->connection_type->value, - 'source' => 'managed_tenant_onboarding_wizard.create', + 'source' => 'managed_environment_onboarding_wizard.create', ]), ], actorId: $actorId, @@ -3861,7 +3861,7 @@ public function createProviderConnection(array $data): void $this->selectedProviderConnectionId = (int) $connection->getKey(); - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $previousProviderConnectionId = $this->onboardingSession->state['provider_connection_id'] ?? null; $previousProviderConnectionId = is_int($previousProviderConnectionId) ? $previousProviderConnectionId @@ -3872,7 +3872,7 @@ public function createProviderConnection(array $data): void draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($connection, $previousProviderConnectionId): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($connection, $previousProviderConnectionId): void { $draft->state = $this->resetDependentOnboardingStateOnConnectionChange( state: array_merge($draft->state ?? [], [ 'provider_connection_id' => (int) $connection->getKey(), @@ -3896,7 +3896,7 @@ public function createProviderConnection(array $data): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingProviderConnectionChanged->value, + action: AuditActionId::ManagedEnvironmentOnboardingProviderConnectionChanged->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -3928,7 +3928,7 @@ private function platformAppClientId(): string private function canManageDedicatedOverride(): bool { - return $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED); + return $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED); } public function startVerification(): void @@ -3939,14 +3939,14 @@ public function startVerification(): void abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START); $this->authorizeEditableDraft($user); try { - $tenant = $this->trustedManagedTenantForUser($user)->fresh(); + $tenant = $this->trustedManagedEnvironmentForUser($user)->fresh(); } catch (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException) { Notification::make() - ->title('Identify a managed tenant first') + ->title('Identify a managed environment first') ->warning() ->send(); @@ -3976,7 +3976,7 @@ public function startVerification(): void draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($tenant, $user, $connection, &$result): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($tenant, $user, $connection, &$result): void { $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: $connection, @@ -3992,7 +3992,7 @@ public function startVerification(): void initiator: $user, extraContext: [ 'wizard' => [ - 'flow' => 'managed_tenant_onboarding', + 'flow' => 'managed_environment_onboarding', 'step' => 'verification', ], ], @@ -4033,7 +4033,7 @@ public function startVerification(): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingVerificationStart->value, + action: AuditActionId::ManagedEnvironmentOnboardingVerificationStart->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -4049,10 +4049,10 @@ public function startVerification(): void resourceId: (string) $result->run->getKey(), ); - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingVerificationPersisted->value, + action: AuditActionId::ManagedEnvironmentOnboardingVerificationPersisted->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -4063,7 +4063,7 @@ public function startVerification(): void ], actor: $user, status: 'success', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $this->onboardingSession->getKey(), ); } @@ -4132,7 +4132,7 @@ public function startBootstrap(array $operationTypes): void $this->authorizeWorkspaceMember($user); $this->authorizeEditableDraft($user); - $tenant = $this->trustedManagedTenantForUser($user)->fresh(); + $tenant = $this->trustedManagedEnvironmentForUser($user)->fresh(); if (! $tenant instanceof ManagedEnvironment) { abort(404); @@ -4195,7 +4195,7 @@ public function startBootstrap(array $operationTypes): void draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($tenant, $connection, $types, $registry, $user, &$result): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($tenant, $connection, $types, $registry, $user, &$result): void { $nextOperationType = $this->nextBootstrapOperationType($draft, $types, (int) $connection->getKey()); if ($nextOperationType === null) { @@ -4230,7 +4230,7 @@ public function startBootstrap(array $operationTypes): void initiator: $user, extraContext: [ 'wizard' => [ - 'flow' => 'managed_tenant_onboarding', + 'flow' => 'managed_environment_onboarding', 'step' => 'bootstrap', ], 'required_capability' => $capability, @@ -4302,7 +4302,7 @@ public function startBootstrap(array $operationTypes): void ? array_values(array_filter($result['remaining_types'], static fn (mixed $value): bool => is_string($value) && $value !== '')) : []; - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $auditStatus = match ($result['status']) { 'started' => 'success', 'deduped' => 'deduped', @@ -4312,7 +4312,7 @@ public function startBootstrap(array $operationTypes): void app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingBootstrapStarted->value, + action: AuditActionId::ManagedEnvironmentOnboardingBootstrapStarted->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -4326,7 +4326,7 @@ public function startBootstrap(array $operationTypes): void ], actor: $user, status: $auditStatus, - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $this->onboardingSession->getKey(), ); } @@ -4383,7 +4383,7 @@ private function dispatchBootstrapJob( /** * @param array $types */ - private function nextBootstrapOperationType(TenantOnboardingSession $draft, array $types, int $providerConnectionId): ?string + private function nextBootstrapOperationType(ManagedEnvironmentOnboardingSession $draft, array $types, int $providerConnectionId): ?string { foreach ($types as $type) { if (! $this->bootstrapOperationSucceeded($draft, $type, $providerConnectionId)) { @@ -4394,7 +4394,7 @@ private function nextBootstrapOperationType(TenantOnboardingSession $draft, arra return null; } - private function bootstrapOperationSucceeded(TenantOnboardingSession $draft, string $type, int $providerConnectionId): bool + private function bootstrapOperationSucceeded(ManagedEnvironmentOnboardingSession $draft, string $type, int $providerConnectionId): bool { $state = is_array($draft->state) ? $draft->state : []; $runMap = $state['bootstrap_operation_runs'] ?? []; @@ -4550,19 +4550,19 @@ public function verificationSucceeded(): bool private function verificationCanProceed(): bool { - return $this->onboardingSession instanceof TenantOnboardingSession + return $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession && $this->lifecycleService()->verificationCanProceed($this->onboardingSession, $this->selectedProviderConnectionId); } private function verificationIsBlocked(): bool { - return $this->onboardingSession instanceof TenantOnboardingSession + return $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession && $this->lifecycleService()->verificationIsBlocked($this->onboardingSession, $this->selectedProviderConnectionId); } private function canCompleteOnboarding(): bool { - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { return false; } @@ -4573,7 +4573,7 @@ private function canCompleteOnboarding(): bool $user = $this->currentUser(); if (! app(TenantOperabilityService::class)->outcomeFor( - tenant: $this->managedTenant, + tenant: $this->managedEnvironment, question: TenantOperabilityQuestion::OnboardingCompletionEligibility, actor: $user instanceof User ? $user : null, workspaceId: isset($this->workspace) ? (int) $this->workspace->getKey() : null, @@ -4583,7 +4583,7 @@ private function canCompleteOnboarding(): bool return false; } - if (! $this->resolveSelectedProviderConnection($this->managedTenant)) { + if (! $this->resolveSelectedProviderConnection($this->managedEnvironment)) { return false; } @@ -4653,8 +4653,8 @@ private function completionSummaryEntitlementDetail(): string $sourceLabel = $this->completionSummaryEntitlementSourceLabel($entitlementDecision); $rationale = is_string($decision['rationale'] ?? null) ? $decision['rationale'] : null; $message = sprintf( - '%s Current usage is %d active managed tenant%s out of %d allowed. Source: %s.', - (string) ($decision['message'] ?? 'Managed-tenant activation is available for this workspace commercial state.'), + '%s Current usage is %d active managed environment%s out of %d allowed. Source: %s.', + (string) ($decision['message'] ?? 'Managed-environment activation is available for this workspace commercial state.'), $currentUsage, $currentUsage === 1 ? '' : 's', $effectiveValue, @@ -4713,7 +4713,7 @@ private function completionSummaryCommercialSourceLabel(array $decision): string private function completionActionTooltip(): ?string { - if (! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE)) { + if (! $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE)) { return 'Owner required to complete onboarding.'; } @@ -4724,9 +4724,9 @@ private function completionActionTooltip(): ?string return null; } - private function completionSummaryTenantLine(): string + private function completionSummaryEnvironmentLine(): string { - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $tenant instanceof ManagedEnvironment) { return '—'; @@ -4740,7 +4740,7 @@ private function completionSummaryTenantLine(): string private function completionSummaryConnectionLabel(): string { - $tenant = $this->currentManagedTenantRecord(); + $tenant = $this->currentManagedEnvironmentRecord(); if (! $tenant instanceof ManagedEnvironment) { return '—'; @@ -4765,11 +4765,11 @@ private function completionSummaryConnectionLabel(): string private function completionSummaryConnectionDetail(): string { - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { return ''; } - $connection = $this->resolveSelectedProviderConnection($this->managedTenant); + $connection = $this->resolveSelectedProviderConnection($this->managedEnvironment); if (! $connection instanceof ProviderConnection) { return ''; @@ -4830,7 +4830,7 @@ private function completionSummaryVerificationDetail(): string private function completionSummaryBootstrapLabel(): string { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return $this->completionSummarySelectedBootstrapTypes() === [] ? 'Skipped' : 'Selected'; @@ -4856,7 +4856,7 @@ private function completionSummaryBootstrapLabel(): string private function completionSummaryBootstrapDetail(): string { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $selectedTypes = $this->completionSummarySelectedBootstrapTypes(); return $selectedTypes === [] @@ -4903,7 +4903,7 @@ private function completionSummaryBootstrapSummary(): string private function completionSummaryBootstrapCompleted(): bool { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return false; } @@ -4989,7 +4989,7 @@ private function completionSummaryBootstrapActionRequiredDetail(): ?string private function completionSummaryBootstrapReasonCode(): ?string { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return null; } @@ -5001,7 +5001,7 @@ private function completionSummaryBootstrapReasonCode(): ?string private function completionSummaryBootstrapFailedRun(): ?OperationRun { return once(function (): ?OperationRun { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return null; } @@ -5052,7 +5052,7 @@ private function completionSummarySelectedBootstrapTypes(): array return $this->normalizeBootstrapOperationTypes($this->selectedBootstrapOperationTypes); } - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return []; } @@ -5071,14 +5071,14 @@ public function completeOnboarding(): void abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE); $this->authorizeEditableDraft($user); - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { abort(404); } - $tenant = $this->trustedManagedTenantForUser($user); + $tenant = $this->trustedManagedEnvironmentForUser($user); $completionOutcome = app(TenantOperabilityService::class)->outcomeFor( tenant: $tenant, @@ -5092,7 +5092,7 @@ public function completeOnboarding(): void if (! $completionOutcome->allowed) { Notification::make() ->title('Onboarding unavailable') - ->body('This tenant can no longer be completed from the current onboarding workflow state.') + ->body('This environment can no longer be completed from the current onboarding workflow state.') ->warning() ->send(); @@ -5171,7 +5171,7 @@ public function completeOnboarding(): void draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft): void { $draft->completed_at = now(); $draft->cancelled_at = null; $draft->current_step = 'complete'; @@ -5203,7 +5203,7 @@ public function completeOnboarding(): void if ($overrideBlocked) { app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingActivationOverrideUsed->value, + action: AuditActionId::ManagedEnvironmentOnboardingActivationOverrideUsed->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -5215,14 +5215,14 @@ public function completeOnboarding(): void ], actor: $user, status: 'override', - resourceType: 'managed_tenant_onboarding_session', + resourceType: 'managed_environment_onboarding_session', resourceId: (string) $this->onboardingSession->getKey(), ); } app(WorkspaceAuditLogger::class)->log( workspace: $this->workspace, - action: AuditActionId::ManagedTenantOnboardingActivation->value, + action: AuditActionId::ManagedEnvironmentOnboardingActivation->value, context: [ 'metadata' => [ 'workspace_id' => (int) $this->workspace->getKey(), @@ -5245,7 +5245,7 @@ public function completeOnboarding(): void private function verificationRun(): ?OperationRun { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return null; } @@ -5273,7 +5273,7 @@ private function verificationRunMatchesSelectedConnection(OperationRun $run): bo { $selectedProviderConnectionId = $this->selectedProviderConnectionId; - if ($selectedProviderConnectionId === null && $this->onboardingSession instanceof TenantOnboardingSession) { + if ($selectedProviderConnectionId === null && $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $candidate = $this->onboardingSession->state['provider_connection_id'] ?? null; $selectedProviderConnectionId = $this->resolvePersistedProviderConnectionId($candidate); } @@ -5300,7 +5300,7 @@ private function verificationRunMatchesSelectedConnection(OperationRun $run): bo */ private function verificationAssistVisibility(): array { - $tenant = $this->managedTenant; + $tenant = $this->managedEnvironment; $user = $this->currentUser(); $run = $this->verificationRun(); @@ -5341,7 +5341,7 @@ private function verificationAssistVisibility(): array */ private function verificationAssistViewModel(): array { - $tenant = $this->managedTenant; + $tenant = $this->managedEnvironment; $user = $this->currentUser(); $run = $this->verificationRun(); @@ -5366,7 +5366,7 @@ private function verificationAssistViewModel(): array verificationStatus: $this->verificationStatus(), isVerificationStale: $this->verificationRunIsStaleForSelectedConnection(), staleReason: $this->verificationAssistStaleReason(), - canAccessProviderConnectionDiagnostics: $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW), + canAccessProviderConnectionDiagnostics: $this->currentUserCan(Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW), ); } @@ -5417,7 +5417,7 @@ private function resetDependentOnboardingStateOnConnectionChange(array $state, ? private function connectionRecentlyUpdated(): bool { - if (! $this->onboardingSession instanceof TenantOnboardingSession) { + if (! $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { return false; } @@ -5435,16 +5435,16 @@ private function inlineEditSelectedConnectionFill(int $providerConnectionId): ar abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE); - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { abort(404); } $connection = ProviderConnection::query() ->with('credential') ->where('workspace_id', (int) $this->workspace->getKey()) - ->where('managed_environment_id', (int) $this->managedTenant->getKey()) + ->where('managed_environment_id', (int) $this->managedEnvironment->getKey()) ->whereKey($providerConnectionId) ->first(); @@ -5474,16 +5474,16 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId abort(403); } - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE); - if (! $this->managedTenant instanceof ManagedEnvironment) { + if (! $this->managedEnvironment instanceof ManagedEnvironment) { abort(404); } $connection = ProviderConnection::query() ->with('credential') ->where('workspace_id', (int) $this->workspace->getKey()) - ->where('managed_environment_id', (int) $this->managedTenant->getKey()) + ->where('managed_environment_id', (int) $this->managedEnvironment->getKey()) ->whereKey($providerConnectionId) ->first(); @@ -5525,7 +5525,7 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId } if ($targetType === ProviderConnectionType::Dedicated) { - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED); if ($clientId === '') { throw ValidationException::withMessages([ @@ -5549,7 +5549,7 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId } if ($targetType === ProviderConnectionType::Platform && $existingType === ProviderConnectionType::Dedicated) { - $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED); + $this->authorizeWorkspaceMutation($user, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED); } DB::transaction(function () use ($connection, $displayName, $clientId, $clientSecret, $targetType, $existingType, $existingClientId): void { @@ -5576,14 +5576,14 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId if (in_array('connection_type', $changedFields, true)) { app(AuditLogger::class)->log( - tenant: $this->managedTenant, + tenant: $this->managedEnvironment, action: 'provider_connection.connection_type_changed', context: [ 'metadata' => $this->providerConnectionTargetScopeAuditMetadata($connection, [ 'workspace_id' => (int) $this->workspace->getKey(), 'from_connection_type' => $existingType->value, 'to_connection_type' => $targetType->value, - 'source' => 'managed_tenant_onboarding_wizard.inline_edit', + 'source' => 'managed_environment_onboarding_wizard.inline_edit', ]), ], actorId: (int) $user->getKey(), @@ -5597,14 +5597,14 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId if ($changedFields !== []) { app(AuditLogger::class)->log( - tenant: $this->managedTenant, + tenant: $this->managedEnvironment, action: 'provider_connection.updated', context: [ 'metadata' => $this->providerConnectionTargetScopeAuditMetadata($connection, [ 'workspace_id' => (int) $this->workspace->getKey(), 'fields' => app(ProviderConnectionTargetScopeNormalizer::class)->auditFieldNames($changedFields), 'connection_type' => $targetType->value, - 'source' => 'managed_tenant_onboarding_wizard.inline_edit', + 'source' => 'managed_environment_onboarding_wizard.inline_edit', ]), ], actorId: (int) $user->getKey(), @@ -5616,13 +5616,13 @@ public function updateSelectedProviderConnectionInline(int $providerConnectionId ); } - if ($this->onboardingSession instanceof TenantOnboardingSession) { + if ($this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { try { $this->setOnboardingSession($this->mutationService()->mutate( draft: $this->onboardingSession, actor: $user, expectedVersion: $this->expectedDraftVersion(), - mutator: function (TenantOnboardingSession $draft) use ($connection): void { + mutator: function (ManagedEnvironmentOnboardingSession $draft) use ($connection): void { $state = is_array($draft->state) ? $draft->state : []; unset( @@ -5697,7 +5697,7 @@ private function resolveSelectedProviderConnection(ManagedEnvironment $tenant): { $providerConnectionId = $this->selectedProviderConnectionId; - if (! is_int($providerConnectionId) && $this->onboardingSession instanceof TenantOnboardingSession) { + if (! is_int($providerConnectionId) && $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $candidate = $this->onboardingSession->state['provider_connection_id'] ?? null; $providerConnectionId = is_int($candidate) ? $candidate : null; } @@ -5727,9 +5727,9 @@ private function resolvePersistedProviderConnectionId(mixed $providerConnectionI return null; } - $tenantId = $this->managedTenant?->getKey(); + $tenantId = $this->managedEnvironment?->getKey(); - if (! is_int($tenantId) && $this->onboardingSession instanceof TenantOnboardingSession) { + if (! is_int($tenantId) && $this->onboardingSession instanceof ManagedEnvironmentOnboardingSession) { $tenantId = is_numeric($this->onboardingSession->managed_environment_id) ? (int) $this->onboardingSession->managed_environment_id : null; } diff --git a/apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php b/apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentsLanding.php similarity index 92% rename from apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php rename to apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentsLanding.php index a7d9fcff..19f8190c 100644 --- a/apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php +++ b/apps/platform/app/Filament/Pages/Workspaces/ManagedEnvironmentsLanding.php @@ -4,7 +4,7 @@ namespace App\Filament\Pages\Workspaces; -use App\Filament\Pages\ChooseTenant; +use App\Filament\Pages\ChooseEnvironment; use App\Models\ManagedEnvironment; use App\Models\User; use App\Models\Workspace; @@ -17,7 +17,7 @@ use Filament\Pages\Page; use Illuminate\Database\Eloquent\Collection; -class ManagedTenantsLanding extends Page +class ManagedEnvironmentsLanding extends Page { protected static bool $shouldRegisterNavigation = false; @@ -25,7 +25,7 @@ class ManagedTenantsLanding extends Page protected static string $layout = 'filament-panels::components.layout.simple'; - protected string $view = 'filament.pages.workspaces.managed-tenants-landing'; + protected string $view = 'filament.pages.workspaces.managed-environments-landing'; public Workspace $workspace; @@ -90,9 +90,9 @@ public function getTenants(): Collection ->values(); } - public function goToChooseTenant(): void + public function goToChooseEnvironment(): void { - $this->redirect(route('admin.workspace.managed-tenants.index', ['workspace' => $this->workspace])); + $this->redirect(route('admin.workspace.managed-environments.index', ['workspace' => $this->workspace])); } public function openTenant(int $tenantId): void diff --git a/apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php b/apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php index a2ae0d97..3c650038 100644 --- a/apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php +++ b/apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php @@ -64,8 +64,8 @@ private function captureAction(): Action : 'Capture baseline'; $modalDescription = $captureMode === BaselineCaptureMode::FullContent - ? 'Select the source tenant. This will capture content evidence on demand (redacted) and may take longer depending on scope.' - : 'Select the source tenant whose current inventory will be captured as the baseline snapshot.'; + ? 'Select the source environment. This will capture content evidence on demand (redacted) and may take longer depending on scope.' + : 'Select the source environment whose current inventory will be captured as the baseline snapshot.'; $action = Action::make('capture') ->label($label) @@ -76,8 +76,8 @@ private function captureAction(): Action ->modalHeading($label) ->modalDescription($modalDescription) ->form([ - Select::make('source_tenant_id') - ->label('Source ManagedEnvironment') + Select::make('source_environment_id') + ->label('Source managed environment') ->options(fn (): array => $this->getWorkspaceTenantOptions()) ->required() ->searchable(), @@ -91,11 +91,11 @@ private function captureAction(): Action /** @var BaselineProfile $profile */ $profile = $this->getRecord(); - $sourceTenant = ManagedEnvironment::query()->find((int) $data['source_tenant_id']); + $sourceTenant = ManagedEnvironment::query()->find((int) $data['source_environment_id']); if (! $sourceTenant instanceof ManagedEnvironment) { Notification::make() - ->title('Source tenant not found') + ->title('Source environment not found') ->danger() ->send(); @@ -175,8 +175,8 @@ private function compareNowAction(): Action : 'Compare now'; $modalDescription = $captureMode === BaselineCaptureMode::FullContent - ? 'Select the target tenant. This will refresh content evidence on demand (redacted) before comparing.' - : 'Select the target tenant to compare its current inventory against the effective current baseline snapshot.'; + ? 'Select the target environment. This will refresh content evidence on demand (redacted) before comparing.' + : 'Select the target environment to compare its current inventory against the effective current baseline snapshot.'; return Action::make('compareNow') ->label($label) @@ -187,8 +187,8 @@ private function compareNowAction(): Action ->modalHeading($label) ->modalDescription($modalDescription) ->form([ - Select::make('target_tenant_id') - ->label('Target ManagedEnvironment') + Select::make('target_environment_id') + ->label('Target managed environment') ->options(fn (): array => $this->getEligibleCompareTenantOptions()) ->required() ->searchable(), @@ -204,11 +204,11 @@ private function compareNowAction(): Action /** @var BaselineProfile $profile */ $profile = $this->getRecord(); - $targetTenant = ManagedEnvironment::query()->find((int) $data['target_tenant_id']); + $targetTenant = ManagedEnvironment::query()->find((int) $data['target_environment_id']); if (! $targetTenant instanceof ManagedEnvironment || (int) $targetTenant->workspace_id !== (int) $profile->workspace_id) { Notification::make() - ->title('Target tenant not found') + ->title('Target environment not found') ->danger() ->send(); diff --git a/apps/platform/app/Filament/Resources/TenantReviewResource.php b/apps/platform/app/Filament/Resources/EnvironmentReviewResource.php similarity index 84% rename from apps/platform/app/Filament/Resources/TenantReviewResource.php rename to apps/platform/app/Filament/Resources/EnvironmentReviewResource.php index 699edbc8..601c59f4 100644 --- a/apps/platform/app/Filament/Resources/TenantReviewResource.php +++ b/apps/platform/app/Filament/Resources/EnvironmentReviewResource.php @@ -8,16 +8,16 @@ use App\Filament\Concerns\ResolvesPanelTenantContext; use App\Filament\Concerns\WorkspaceScopedTenantRoutes; use App\Filament\Pages\Reviews\CustomerReviewWorkspace; -use App\Filament\Resources\TenantReviewResource\Pages; +use App\Filament\Resources\EnvironmentReviewResource\Pages; use App\Exceptions\Entitlements\WorkspaceEntitlementBlockedException; use App\Models\EvidenceSnapshot; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; -use App\Models\TenantReviewSection; +use App\Models\EnvironmentReview; +use App\Models\EnvironmentReviewSection; use App\Models\User; use App\Services\ReviewPackService; -use App\Services\TenantReviews\TenantReviewService; +use App\Services\EnvironmentReviews\EnvironmentReviewService; use App\Support\Auth\Capabilities; use App\Support\Auth\UiTooltips as AuthUiTooltips; use App\Support\Badges\BadgeCatalog; @@ -31,8 +31,8 @@ use App\Support\ReasonTranslation\ReasonPresenter; use App\Support\ReviewPackStatus; use App\Support\Rbac\UiEnforcement; -use App\Support\TenantReviewCompletenessState; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewCompletenessState; +use App\Support\EnvironmentReviewStatus; use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance; use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile; @@ -62,7 +62,7 @@ use Illuminate\Support\Str; use UnitEnum; -class TenantReviewResource extends Resource +class EnvironmentReviewResource extends Resource { use InteractsWithTenantOwnedRecords; use ResolvesPanelTenantContext; @@ -70,7 +70,7 @@ class TenantReviewResource extends Resource protected static bool $isDiscovered = false; - protected static ?string $model = TenantReview::class; + protected static ?string $model = EnvironmentReview::class; protected static ?string $slug = 'reviews'; @@ -95,7 +95,7 @@ public static function shouldRegisterNavigation(): bool public static function getSlug(?Panel $panel = null): string { $slug = $panel?->getId() === 'admin' - ? 'tenant-reviews' + ? 'environment-reviews' : parent::getSlug($panel); return static::workspaceScopedSlug($slug, $panel); @@ -134,7 +134,7 @@ public static function canViewAny(): bool return false; } - return $user->can(Capabilities::TENANT_REVIEW_VIEW, $tenant); + return $user->can(Capabilities::ENVIRONMENT_REVIEW_VIEW, $tenant); } public static function canView(Model $record): bool @@ -142,7 +142,7 @@ public static function canView(Model $record): bool $tenant = static::resolveTenantContextForCurrentPanel(); $user = auth()->user(); - if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User || ! $record instanceof TenantReview) { + if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User || ! $record instanceof EnvironmentReview) { return false; } @@ -194,7 +194,7 @@ public static function infolist(Schema $schema): Schema ViewEntry::make('artifact_truth') ->hiddenLabel() ->view('filament.infolists.entries.governance-artifact-truth') - ->state(fn (TenantReview $record): array => static::truthState($record)) + ->state(fn (EnvironmentReview $record): array => static::truthState($record)) ->columnSpanFull(), ]) ->columnSpanFull(), @@ -202,30 +202,30 @@ public static function infolist(Schema $schema): Schema ->schema([ TextEntry::make('status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewStatus)), + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewStatus)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewStatus)), TextEntry::make('completeness_state') ->label(__('localization.review.completeness')) ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewCompleteness)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewCompleteness)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewCompleteness)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewCompleteness)), + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewCompleteness)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewCompleteness)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewCompleteness)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewCompleteness)), TextEntry::make('tenant.name')->label(__('localization.review.tenant')), TextEntry::make('generated_at')->dateTime()->placeholder('—'), TextEntry::make('published_at')->dateTime()->placeholder('—'), TextEntry::make('evidenceSnapshot.id') ->label(__('localization.review.evidence_snapshot')) ->formatStateUsing(fn (?int $state): string => $state ? '#'.$state : '—') - ->url(fn (TenantReview $record): ?string => $record->evidenceSnapshot + ->url(fn (EnvironmentReview $record): ?string => $record->evidenceSnapshot ? EvidenceSnapshotResource::getUrl('view', ['record' => $record->evidenceSnapshot], tenant: $record->tenant) : null), TextEntry::make('currentExportReviewPack.id') ->label(__('localization.review.current_export')) ->formatStateUsing(fn (?int $state): string => $state ? '#'.$state : '—') - ->url(fn (TenantReview $record): ?string => $record->currentExportReviewPack + ->url(fn (EnvironmentReview $record): ?string => $record->currentExportReviewPack ? ReviewPackResource::getUrl('view', ['record' => $record->currentExportReviewPack], tenant: $record->tenant) : null), TextEntry::make('fingerprint') @@ -242,32 +242,32 @@ public static function infolist(Schema $schema): Schema ->schema([ ViewEntry::make('review_summary') ->hiddenLabel() - ->view('filament.infolists.entries.tenant-review-summary') - ->state(fn (TenantReview $record): array => static::summaryPresentation($record)) + ->view('filament.infolists.entries.environment-review-summary') + ->state(fn (EnvironmentReview $record): array => static::summaryPresentation($record)) ->columnSpanFull(), ]) ->columnSpanFull(), Section::make(__('localization.review.sections')) ->schema([ RepeatableEntry::make('sections') - ->state(fn (TenantReview $record): array => static::visibleSections($record)) + ->state(fn (EnvironmentReview $record): array => static::visibleSections($record)) ->hiddenLabel() ->schema([ TextEntry::make('title'), TextEntry::make('completeness_state') ->label(__('localization.review.completeness')) ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewCompleteness)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewCompleteness)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewCompleteness)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewCompleteness)), + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewCompleteness)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewCompleteness)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewCompleteness)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewCompleteness)), TextEntry::make('measured_at')->dateTime()->placeholder('—'), Section::make(__('localization.review.details')) ->schema([ ViewEntry::make('section_payload') ->hiddenLabel() - ->view('filament.infolists.entries.tenant-review-section') - ->state(fn (TenantReviewSection $record): array => static::sectionPresentation($record)) + ->view('filament.infolists.entries.environment-review-section') + ->state(fn (EnvironmentReviewSection $record): array => static::sectionPresentation($record)) ->columnSpanFull(), ]) ->collapsible() @@ -281,12 +281,12 @@ public static function infolist(Schema $schema): Schema } /** - * @return array + * @return array */ - private static function visibleSections(TenantReview $record): array + private static function visibleSections(EnvironmentReview $record): array { return $record->sections - ->reject(fn (TenantReviewSection $section): bool => static::isCustomerWorkspaceMode() && $section->isControlInterpretation()) + ->reject(fn (EnvironmentReviewSection $section): bool => static::isCustomerWorkspaceMode() && $section->isControlInterpretation()) ->values() ->all(); } @@ -297,43 +297,43 @@ public static function table(Table $table): Table Actions\Action::make('export_executive_pack') ->label(__('localization.review.export_executive_pack')) ->icon('heroicon-o-arrow-down-tray') - ->visible(fn (TenantReview $record): bool => in_array($record->status, [ - TenantReviewStatus::Ready->value, - TenantReviewStatus::Published->value, + ->visible(fn (EnvironmentReview $record): bool => in_array($record->status, [ + EnvironmentReviewStatus::Ready->value, + EnvironmentReviewStatus::Published->value, ], true)) - ->disabled(fn (TenantReview $record): bool => static::reviewPackGenerationBlocked($record->tenant)) - ->action(fn (TenantReview $record): mixed => static::executeExport($record)), - fn (TenantReview $record): TenantReview => $record, + ->disabled(fn (EnvironmentReview $record): bool => static::reviewPackGenerationBlocked($record->tenant)) + ->action(fn (EnvironmentReview $record): mixed => static::executeExport($record)), + fn (EnvironmentReview $record): EnvironmentReview => $record, ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->preserveVisibility() ->preserveDisabled() ->apply(); - $exportExecutivePackAction->tooltip(fn (TenantReview $record): ?string => static::reviewPackGenerationActionTooltip($record->tenant)); + $exportExecutivePackAction->tooltip(fn (EnvironmentReview $record): ?string => static::reviewPackGenerationActionTooltip($record->tenant)); return $table ->defaultSort('generated_at', 'desc') ->persistFiltersInSession() ->persistSearchInSession() ->persistSortInSession() - ->recordUrl(fn (TenantReview $record): string => static::tenantScopedUrl('view', ['record' => $record], $record->tenant)) + ->recordUrl(fn (EnvironmentReview $record): string => static::tenantScopedUrl('view', ['record' => $record], $record->tenant)) ->columns([ Tables\Columns\TextColumn::make('status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewStatus)) + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewStatus)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewStatus)) ->sortable(), Tables\Columns\TextColumn::make('outcome') ->label(__('localization.review.outcome')) ->badge() - ->getStateUsing(fn (TenantReview $record): string => static::compressedOutcome($record)->primaryLabel) - ->color(fn (TenantReview $record): string => static::compressedOutcome($record)->primaryBadge->color) - ->icon(fn (TenantReview $record): ?string => static::compressedOutcome($record)->primaryBadge->icon) - ->iconColor(fn (TenantReview $record): ?string => static::compressedOutcome($record)->primaryBadge->iconColor) - ->description(fn (TenantReview $record): ?string => static::compressedOutcome($record)->primaryReason) + ->getStateUsing(fn (EnvironmentReview $record): string => static::compressedOutcome($record)->primaryLabel) + ->color(fn (EnvironmentReview $record): string => static::compressedOutcome($record)->primaryBadge->color) + ->icon(fn (EnvironmentReview $record): ?string => static::compressedOutcome($record)->primaryBadge->icon) + ->iconColor(fn (EnvironmentReview $record): ?string => static::compressedOutcome($record)->primaryBadge->iconColor) + ->description(fn (EnvironmentReview $record): ?string => static::compressedOutcome($record)->primaryReason) ->wrap(), Tables\Columns\TextColumn::make('generated_at')->dateTime()->placeholder('—')->sortable(), Tables\Columns\TextColumn::make('published_at')->dateTime()->placeholder('—')->sortable(), @@ -342,7 +342,7 @@ public static function table(Table $table): Table ->boolean(), Tables\Columns\TextColumn::make('next_step') ->label(__('localization.review.next_step')) - ->getStateUsing(fn (TenantReview $record): string => static::compressedOutcome($record)->nextActionText) + ->getStateUsing(fn (EnvironmentReview $record): string => static::compressedOutcome($record)->nextActionText) ->wrap(), Tables\Columns\TextColumn::make('fingerprint') ->toggleable(isToggledHiddenByDefault: true) @@ -350,18 +350,18 @@ public static function table(Table $table): Table ]) ->filters([ Tables\Filters\SelectFilter::make('status') - ->options(collect(TenantReviewStatus::cases()) - ->mapWithKeys(fn (TenantReviewStatus $status): array => [$status->value => Str::headline($status->value)]) + ->options(collect(EnvironmentReviewStatus::cases()) + ->mapWithKeys(fn (EnvironmentReviewStatus $status): array => [$status->value => Str::headline($status->value)]) ->all()), Tables\Filters\SelectFilter::make('completeness_state') - ->options(BadgeCatalog::options(BadgeDomain::TenantReviewCompleteness, TenantReviewCompletenessState::values())), + ->options(BadgeCatalog::options(BadgeDomain::EnvironmentReviewCompleteness, EnvironmentReviewCompletenessState::values())), \App\Support\Filament\FilterPresets::dateRange('review_date', __('localization.review.review_date'), 'generated_at'), ]) ->actions([ $exportExecutivePackAction, ]) ->bulkActions([]) - ->emptyStateHeading(__('localization.review.no_tenant_reviews_yet')) + ->emptyStateHeading(__('localization.review.no_environment_reviews_yet')) ->emptyStateDescription(__('localization.review.create_first_review_description')) ->emptyStateActions([ static::makeCreateReviewAction( @@ -375,8 +375,8 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => Pages\ListTenantReviews::route('/'), - 'view' => Pages\ViewTenantReview::route('/{record}'), + 'index' => Pages\ListEnvironmentReviews::route('/'), + 'view' => Pages\ViewEnvironmentReview::route('/{record}'), ]; } @@ -406,7 +406,7 @@ public static function makeCreateReviewAction( ]) ->action(fn (array $data): mixed => static::executeCreateReview($data)), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->apply(); } @@ -428,7 +428,7 @@ public static function executeCreateReview(array $data): void abort(404); } - if (! $user->can(Capabilities::TENANT_REVIEW_MANAGE, $tenant)) { + if (! $user->can(Capabilities::ENVIRONMENT_REVIEW_MANAGE, $tenant)) { abort(403); } @@ -447,7 +447,7 @@ public static function executeCreateReview(array $data): void } try { - $review = app(TenantReviewService::class)->create($tenant, $snapshot, $user); + $review = app(EnvironmentReviewService::class)->create($tenant, $snapshot, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title(__('localization.review.unable_create_review'))->body($throwable->getMessage())->send(); @@ -471,7 +471,7 @@ public static function executeCreateReview(array $data): void return; } - $toast = OperationUxPresenter::queuedToast(OperationRunType::TenantReviewCompose->value) + $toast = OperationUxPresenter::queuedToast(OperationRunType::EnvironmentReviewCompose->value) ->body(__('localization.review.review_composing_background')); if ($review->operation_run_id) { @@ -535,7 +535,7 @@ public static function reviewPackGenerationActionTooltip(?ManagedEnvironment $te $tenant ??= static::panelTenantContext(); $user = auth()->user(); - if ($tenant instanceof ManagedEnvironment && $user instanceof User && ! $user->can(Capabilities::TENANT_REVIEW_MANAGE, $tenant)) { + if ($tenant instanceof ManagedEnvironment && $user instanceof User && ! $user->can(Capabilities::ENVIRONMENT_REVIEW_MANAGE, $tenant)) { return AuthUiTooltips::insufficientPermission(); } @@ -543,7 +543,7 @@ public static function reviewPackGenerationActionTooltip(?ManagedEnvironment $te ?? static::reviewPackGenerationWarningReason($tenant); } - public static function executeExport(TenantReview $review): void + public static function executeExport(EnvironmentReview $review): void { $review->loadMissing(['tenant', 'currentExportReviewPack']); $user = auth()->user(); @@ -654,13 +654,13 @@ private static function evidenceSnapshotOptions(): array private static function reviewCompletenessCountLabel(string $state): string { - return BadgeCatalog::spec(BadgeDomain::TenantReviewCompleteness, $state)->label; + return BadgeCatalog::spec(BadgeDomain::EnvironmentReviewCompleteness, $state)->label; } /** * @return array */ - private static function summaryPresentation(TenantReview $record): array + private static function summaryPresentation(EnvironmentReview $record): array { $summary = is_array($record->summary) ? $record->summary : []; $truthEnvelope = static::truthEnvelope($record); @@ -706,7 +706,7 @@ private static function summaryPresentation(TenantReview $record): array * @param array $packagePresentation * @return array */ - private static function customerWorkspaceMetrics(TenantReview $record, array $summary, array $packagePresentation): array + private static function customerWorkspaceMetrics(EnvironmentReview $record, array $summary, array $packagePresentation): array { $acceptedRisk = is_array($summary['risk_acceptance'] ?? null) ? $summary['risk_acceptance'] : []; @@ -719,9 +719,9 @@ private static function customerWorkspaceMetrics(TenantReview $record, array $su ]; } - private static function customerReviewStatusLabel(TenantReview $record): string + private static function customerReviewStatusLabel(EnvironmentReview $record): string { - if ($record->isPublished() && (string) $record->completeness_state === TenantReviewCompletenessState::Complete->value) { + if ($record->isPublished() && (string) $record->completeness_state === EnvironmentReviewCompletenessState::Complete->value) { return __('localization.review.review_completed'); } @@ -732,7 +732,7 @@ private static function customerReviewStatusLabel(TenantReview $record): string return Str::headline((string) $record->status); } - private static function customerEvidenceStatusLabel(TenantReview $record): string + private static function customerEvidenceStatusLabel(EnvironmentReview $record): string { $snapshot = $record->evidenceSnapshot; $tenant = $record->tenant; @@ -775,7 +775,7 @@ private static function customerAcceptedRiskStatusLabel(array $acceptedRisk): st /** * @return array */ - private static function governancePackagePresentation(TenantReview $record): array + private static function governancePackagePresentation(EnvironmentReview $record): array { $summary = is_array($record->summary) ? $record->summary : []; $package = is_array($summary['governance_package'] ?? null) ? $summary['governance_package'] : []; @@ -793,7 +793,7 @@ private static function governancePackagePresentation(TenantReview $record): arr /** * @return array{state:string,label:string,description:string} */ - private static function governancePackageAvailability(TenantReview $record): array + private static function governancePackageAvailability(EnvironmentReview $record): array { $pack = $record->currentExportReviewPack; $tenant = $record->tenant; @@ -801,8 +801,8 @@ private static function governancePackageAvailability(TenantReview $record): arr $controlInterpretation = $record->controlInterpretation(); $limitations = is_array($controlInterpretation['limitations'] ?? null) ? $controlInterpretation['limitations'] : []; $isPartialReview = in_array((string) $record->completeness_state, [ - TenantReviewCompletenessState::Partial->value, - TenantReviewCompletenessState::Stale->value, + EnvironmentReviewCompletenessState::Partial->value, + EnvironmentReviewCompletenessState::Stale->value, ], true) || $limitations !== []; if (! $pack instanceof ReviewPack) { @@ -855,7 +855,7 @@ private static function governancePackageAvailability(TenantReview $record): arr /** * @return array */ - private static function summaryContextLinks(TenantReview $record, bool $customerWorkspaceMode = false): array + private static function summaryContextLinks(EnvironmentReview $record, bool $customerWorkspaceMode = false): array { $links = []; @@ -913,15 +913,15 @@ private static function summaryContextLinks(TenantReview $record, bool $customer /** * @return array */ - private static function sectionPresentation(TenantReviewSection $section): array + private static function sectionPresentation(EnvironmentReviewSection $section): array { $summary = is_array($section->summary_payload) ? $section->summary_payload : []; $render = is_array($section->render_payload) ? $section->render_payload : []; - $review = $section->tenantReview; + $review = $section->environmentReview; $tenant = $section->tenant; $links = []; - if ($section->isControlInterpretation() && $review instanceof TenantReview && $tenant instanceof ManagedEnvironment && $review->evidenceSnapshot instanceof EvidenceSnapshot) { + if ($section->isControlInterpretation() && $review instanceof EnvironmentReview && $tenant instanceof ManagedEnvironment && $review->evidenceSnapshot instanceof EvidenceSnapshot) { $user = auth()->user(); if ($user instanceof User && $user->can(Capabilities::EVIDENCE_VIEW, $tenant)) { @@ -960,34 +960,34 @@ private static function sectionPresentation(TenantReviewSection $section): array ]; } - private static function truthEnvelope(TenantReview $record, bool $fresh = false): ArtifactTruthEnvelope + private static function truthEnvelope(EnvironmentReview $record, bool $fresh = false): ArtifactTruthEnvelope { $presenter = app(ArtifactTruthPresenter::class); return $fresh - ? $presenter->forTenantReviewFresh($record) - : $presenter->forTenantReview($record); + ? $presenter->forEnvironmentReviewFresh($record) + : $presenter->forEnvironmentReview($record); } /** * @return array */ - private static function truthState(TenantReview $record, bool $fresh = false): array + private static function truthState(EnvironmentReview $record, bool $fresh = false): array { $presenter = app(ArtifactTruthPresenter::class); - return $presenter->surfaceStateFor($record, SurfaceCompressionContext::tenantReview(), $fresh) + return $presenter->surfaceStateFor($record, SurfaceCompressionContext::environmentReview(), $fresh) ?? static::truthEnvelope($record, $fresh)->toArray(static::compressedOutcome($record, $fresh)); } - private static function compressedOutcome(TenantReview $record, bool $fresh = false): CompressedGovernanceOutcome + private static function compressedOutcome(EnvironmentReview $record, bool $fresh = false): CompressedGovernanceOutcome { $presenter = app(ArtifactTruthPresenter::class); - return $presenter->compressedOutcomeFor($record, SurfaceCompressionContext::tenantReview(), $fresh) + return $presenter->compressedOutcomeFor($record, SurfaceCompressionContext::environmentReview(), $fresh) ?? $presenter->compressedOutcomeFromEnvelope( static::truthEnvelope($record, $fresh), - SurfaceCompressionContext::tenantReview(), + SurfaceCompressionContext::environmentReview(), ); } @@ -1013,7 +1013,7 @@ private static function isCustomerWorkspaceMode(): bool /** * @return array */ - private static function customerWorkspaceEvidenceQuery(TenantReview $record): array + private static function customerWorkspaceEvidenceQuery(EnvironmentReview $record): array { return array_filter([ 'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE, diff --git a/apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ListEnvironmentReviews.php b/apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ListEnvironmentReviews.php new file mode 100644 index 00000000..a9f8ea13 --- /dev/null +++ b/apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ListEnvironmentReviews.php @@ -0,0 +1,20 @@ +getRecord(); $user = auth()->user(); - if (! $user instanceof User || ! $tenant instanceof ManagedEnvironment || ! $record instanceof TenantReview) { + if (! $user instanceof User || ! $tenant instanceof ManagedEnvironment || ! $record instanceof EnvironmentReview) { abort(404); } @@ -108,11 +108,11 @@ private function primaryLifecycleActionName(): ?string return null; } - if ((string) $this->record->status === TenantReviewStatus::Published->value) { + if ((string) $this->record->status === EnvironmentReviewStatus::Published->value) { return 'export_executive_pack'; } - if ((string) $this->record->status === TenantReviewStatus::Ready->value) { + if ((string) $this->record->status === EnvironmentReviewStatus::Ready->value) { return 'publish_review'; } @@ -157,8 +157,8 @@ private function secondaryLifecycleActionNames(): array } if (in_array((string) $this->record->status, [ - TenantReviewStatus::Ready->value, - TenantReviewStatus::Published->value, + EnvironmentReviewStatus::Ready->value, + EnvironmentReviewStatus::Published->value, ], true)) { $names[] = 'export_executive_pack'; } @@ -194,7 +194,7 @@ private function refreshReviewAction(): Actions\Action } try { - app(TenantReviewService::class)->refresh($this->record, $user); + app(EnvironmentReviewService::class)->refresh($this->record, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title('Unable to refresh review')->body($throwable->getMessage())->send(); @@ -204,7 +204,7 @@ private function refreshReviewAction(): Actions\Action Notification::make()->success()->title($rule->successTitle)->send(); }), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->apply(); } @@ -236,7 +236,7 @@ private function publishReviewAction(): Actions\Action } try { - app(TenantReviewLifecycleService::class)->publish( + app(EnvironmentReviewLifecycleService::class)->publish( $this->record, $user, (string) ($data['publish_reason'] ?? ''), @@ -251,7 +251,7 @@ private function publishReviewAction(): Actions\Action Notification::make()->success()->title($rule->successTitle)->send(); }), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } @@ -264,18 +264,18 @@ private function exportExecutivePackAction(): Actions\Action ->icon('heroicon-o-arrow-down-tray') ->color('primary') ->hidden(fn (): bool => ! in_array((string) $this->record->status, [ - TenantReviewStatus::Ready->value, - TenantReviewStatus::Published->value, + EnvironmentReviewStatus::Ready->value, + EnvironmentReviewStatus::Published->value, ], true)) - ->disabled(fn (): bool => TenantReviewResource::reviewPackGenerationBlocked($this->record->tenant)) - ->action(fn (): mixed => TenantReviewResource::executeExport($this->record)), + ->disabled(fn (): bool => EnvironmentReviewResource::reviewPackGenerationBlocked($this->record->tenant)) + ->action(fn (): mixed => EnvironmentReviewResource::executeExport($this->record)), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->preserveVisibility() ->preserveDisabled() ->apply(); - $action->tooltip(fn (): ?string => TenantReviewResource::reviewPackGenerationActionTooltip($this->record->tenant)); + $action->tooltip(fn (): ?string => EnvironmentReviewResource::reviewPackGenerationActionTooltip($this->record->tenant)); return $action; } @@ -295,17 +295,17 @@ private function createNextReviewAction(): Actions\Action } try { - $nextReview = app(TenantReviewLifecycleService::class)->createNextReview($this->record, $user); + $nextReview = app(EnvironmentReviewLifecycleService::class)->createNextReview($this->record, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title('Unable to create next review')->body($throwable->getMessage())->send(); return; } - $this->redirect(TenantReviewResource::tenantScopedUrl('view', ['record' => $nextReview], $nextReview->tenant)); + $this->redirect(EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $nextReview], $nextReview->tenant)); }), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } @@ -337,7 +337,7 @@ private function archiveReviewAction(): Actions\Action abort(403); } - app(TenantReviewLifecycleService::class)->archive( + app(EnvironmentReviewLifecycleService::class)->archive( $this->record, $user, (string) ($data['archive_reason'] ?? ''), @@ -347,7 +347,7 @@ private function archiveReviewAction(): Actions\Action Notification::make()->success()->title($rule->successTitle)->send(); }), ) - ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) + ->requireCapability(Capabilities::ENVIRONMENT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } @@ -443,7 +443,7 @@ private function auditCustomerWorkspaceOpen(): void app(WorkspaceAuditLogger::class)->log( workspace: $tenant->workspace, - action: AuditActionId::TenantReviewOpened, + action: AuditActionId::EnvironmentReviewOpened, context: [ 'metadata' => [ 'review_id' => (int) $this->record->getKey(), @@ -453,7 +453,7 @@ private function auditCustomerWorkspaceOpen(): void ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $this->record->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $this->record->getKey()), tenant: $tenant, diff --git a/apps/platform/app/Filament/Resources/FindingExceptionResource.php b/apps/platform/app/Filament/Resources/FindingExceptionResource.php index 37bc51f8..98e3a271 100644 --- a/apps/platform/app/Filament/Resources/FindingExceptionResource.php +++ b/apps/platform/app/Filament/Resources/FindingExceptionResource.php @@ -681,7 +681,7 @@ public static function approvalQueueUrl(?ManagedEnvironment $tenant = null): ?st } return route('admin.finding-exceptions.open-queue', [ - 'tenant' => (string) $tenant->external_id, + 'environment' => (string) $tenant->external_id, ]); } } diff --git a/apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php b/apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php index 972f1351..88fbbae1 100644 --- a/apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php +++ b/apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php @@ -6,7 +6,7 @@ use App\Filament\Resources\FindingExceptionResource; use App\Filament\Resources\FindingResource; -use App\Filament\Widgets\Tenant\FindingExceptionStatsOverview; +use App\Filament\Widgets\ManagedEnvironment\FindingExceptionStatsOverview; use App\Models\FindingException; use Filament\Actions\Action; use Filament\Resources\Pages\ListRecords; diff --git a/apps/platform/app/Filament/Resources/FindingResource/Pages/ListFindings.php b/apps/platform/app/Filament/Resources/FindingResource/Pages/ListFindings.php index b1519a1b..7841e1f9 100644 --- a/apps/platform/app/Filament/Resources/FindingResource/Pages/ListFindings.php +++ b/apps/platform/app/Filament/Resources/FindingResource/Pages/ListFindings.php @@ -4,8 +4,8 @@ use App\Filament\Concerns\ResolvesPanelTenantContext; use App\Filament\Resources\FindingResource; -use App\Filament\Widgets\Tenant\BaselineCompareCoverageBanner; -use App\Filament\Widgets\Tenant\FindingStatsOverview; +use App\Filament\Widgets\ManagedEnvironment\BaselineCompareCoverageBanner; +use App\Filament\Widgets\ManagedEnvironment\FindingStatsOverview; use App\Models\Finding; use App\Models\ManagedEnvironment; use App\Models\User; diff --git a/apps/platform/app/Filament/Resources/TenantResource.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource.php similarity index 95% rename from apps/platform/app/Filament/Resources/TenantResource.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource.php index 6c1654ae..ff55d277 100644 --- a/apps/platform/app/Filament/Resources/TenantResource.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource.php @@ -2,9 +2,9 @@ namespace App\Filament\Resources; -use App\Filament\Pages\CrossTenantComparePage; -use App\Filament\Resources\TenantResource\Pages; -use App\Filament\Resources\TenantResource\RelationManagers; +use App\Filament\Pages\CrossEnvironmentComparePage; +use App\Filament\Resources\ManagedEnvironmentResource\Pages; +use App\Filament\Resources\ManagedEnvironmentResource\RelationManagers; use App\Http\Controllers\RbacDelegatedAuthController; use App\Jobs\BulkTenantSyncJob; use App\Jobs\SyncPoliciesJob; @@ -12,8 +12,8 @@ use App\Models\EntraRoleDefinition; use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentOnboardingSession; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; use App\Models\Workspace; use App\Services\Audit\WorkspaceAuditLogger; @@ -26,7 +26,7 @@ use App\Services\Intune\RbacOnboardingService; use App\Services\OperationRunService; use App\Services\Operations\BulkSelectionIdentity; -use App\Services\PortfolioTriage\TenantTriageReviewService; +use App\Services\PortfolioTriage\ManagedEnvironmentTriageReviewService; use App\Services\Providers\AdminConsentUrlFactory; use App\Services\Tenants\TenantActionPolicySurface; use App\Services\Tenants\TenantOperabilityService; @@ -49,7 +49,7 @@ use App\Support\OpsUx\OpsUxBrowserEvents; use App\Support\Navigation\CanonicalNavigationContext; use App\Support\PortfolioTriage\PortfolioArrivalContextToken; -use App\Support\PortfolioTriage\TenantTriageReviewStateResolver; +use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewStateResolver; use App\Support\Rbac\UiEnforcement; use App\Support\Navigation\RelatedContextEntry; use App\Support\Navigation\UnavailableRelationState; @@ -93,7 +93,7 @@ use Illuminate\Support\Str; use UnitEnum; -class TenantResource extends Resource +class ManagedEnvironmentResource extends Resource { // ... [Properties Omitted for Brevity] ... protected static ?string $model = ManagedEnvironment::class; @@ -119,7 +119,7 @@ class TenantResource extends Resource private const string POSTURE_SNAPSHOT_REQUEST_KEY = 'tenant_resource.posture_snapshot'; - private const string TRIAGE_REVIEW_SNAPSHOT_REQUEST_KEY = 'tenant_resource.triage_review_snapshot'; + private const string TRIAGE_REVIEW_SNAPSHOT_REQUEST_KEY = 'managed_environment_resource.triage_review_snapshot'; /** * @var array @@ -297,7 +297,7 @@ public static function makeTenantViewMarkReviewedAction(): Actions\Action ->modalDescription(fn (ManagedEnvironment $record): string => static::triageReviewActionModalDescription( $record, static::tenantViewTriageState(), - TenantTriageReview::STATE_REVIEWED, + ManagedEnvironmentTriageReview::STATE_REVIEWED, )) ->visible(fn (ManagedEnvironment $record): bool => static::selectedActionTriageReviewRowForTenant( $record, @@ -308,11 +308,11 @@ public static function makeTenantViewMarkReviewedAction(): Actions\Action ->before(function (ManagedEnvironment $record): void { static::authorizeTriageReviewAction($record); }) - ->action(function (ManagedEnvironment $record, TenantTriageReviewService $service): void { + ->action(function (ManagedEnvironment $record, ManagedEnvironmentTriageReviewService $service): void { static::handleTriageReviewMutation( tenant: $record, triageState: static::tenantViewTriageState(), - targetManualState: TenantTriageReview::STATE_REVIEWED, + targetManualState: ManagedEnvironmentTriageReview::STATE_REVIEWED, service: $service, ); }); @@ -329,7 +329,7 @@ public static function makeTenantViewMarkFollowUpNeededAction(): Actions\Action ->modalDescription(fn (ManagedEnvironment $record): string => static::triageReviewActionModalDescription( $record, static::tenantViewTriageState(), - TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, )) ->visible(fn (ManagedEnvironment $record): bool => static::selectedActionTriageReviewRowForTenant( $record, @@ -340,11 +340,11 @@ public static function makeTenantViewMarkFollowUpNeededAction(): Actions\Action ->before(function (ManagedEnvironment $record): void { static::authorizeTriageReviewAction($record); }) - ->action(function (ManagedEnvironment $record, TenantTriageReviewService $service): void { + ->action(function (ManagedEnvironment $record, ManagedEnvironmentTriageReviewService $service): void { static::handleTriageReviewMutation( tenant: $record, triageState: static::tenantViewTriageState(), - targetManualState: TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + targetManualState: ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, service: $service, ); }); @@ -826,10 +826,10 @@ public static function table(Table $table): Table $record, static::currentPortfolioTriageState($livewire), )['derived_state'] ?? null) - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantTriageReviewState)) - ->color(BadgeRenderer::color(BadgeDomain::TenantTriageReviewState)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantTriageReviewState)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantTriageReviewState)) + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::ManagedEnvironmentTriageReviewState)) + ->color(BadgeRenderer::color(BadgeDomain::ManagedEnvironmentTriageReviewState)) + ->icon(BadgeRenderer::icon(BadgeDomain::ManagedEnvironmentTriageReviewState)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::ManagedEnvironmentTriageReviewState)) ->description(fn (ManagedEnvironment $record, mixed $livewire): ?string => static::triageReviewDescriptionForTenant( $record, static::currentPortfolioTriageState($livewire), @@ -953,7 +953,7 @@ public static function table(Table $table): Table return '#'; } - $triageState = $livewire instanceof Pages\ListTenants + $triageState = $livewire instanceof Pages\ListManagedEnvironments ? static::currentPortfolioTriageState($livewire) : []; @@ -976,12 +976,12 @@ public static function table(Table $table): Table ->url(fn (ManagedEnvironment $record): string => static::relatedOnboardingDraftUrl($record) ?? route('admin.onboarding')) ->visible(fn (ManagedEnvironment $record): bool => static::relatedOnboardingDraftAction($record, TenantActionSurface::TenantIndexRow) instanceof TenantActionDescriptor && static::tenantIndexPrimaryAction($record)?->key !== 'related_onboarding'), - Actions\Action::make('compareTenants') + Actions\Action::make('compareEnvironments') ->label('Compare tenants') ->icon('heroicon-o-scale') ->color('gray') ->url(function (ManagedEnvironment $record, mixed $livewire): string { - $triageState = $livewire instanceof Pages\ListTenants + $triageState = $livewire instanceof Pages\ListManagedEnvironments ? static::currentPortfolioTriageState($livewire) : []; @@ -994,9 +994,9 @@ public static function table(Table $table): Table $triageState = static::portfolioReturnFiltersFromRequest(request()->query()); } - return static::crossTenantCompareOpenUrl($record, $triageState); + return static::crossEnvironmentCompareOpenUrl($record, $triageState); }) - ->visible(fn (ManagedEnvironment $record): bool => static::crossTenantCompareActionVisible($record)), + ->visible(fn (ManagedEnvironment $record): bool => static::crossEnvironmentCompareActionVisible($record)), UiEnforcement::forAction( Actions\Action::make('edit') ->label('Edit') @@ -1019,7 +1019,7 @@ public static function table(Table $table): Table ->modalDescription(fn (ManagedEnvironment $record, mixed $livewire): string => static::triageReviewActionModalDescription( $record, static::currentPortfolioTriageState($livewire), - TenantTriageReview::STATE_REVIEWED, + ManagedEnvironmentTriageReview::STATE_REVIEWED, )) ->visible(fn (ManagedEnvironment $record, mixed $livewire): bool => static::selectedTriageReviewRowForTenant( $record, @@ -1033,12 +1033,12 @@ public static function table(Table $table): Table ->action(function ( ManagedEnvironment $record, mixed $livewire, - TenantTriageReviewService $service, + ManagedEnvironmentTriageReviewService $service, ): void { static::handleTriageReviewMutation( tenant: $record, triageState: static::currentPortfolioTriageState($livewire), - targetManualState: TenantTriageReview::STATE_REVIEWED, + targetManualState: ManagedEnvironmentTriageReview::STATE_REVIEWED, service: $service, ); }), @@ -1051,7 +1051,7 @@ public static function table(Table $table): Table ->modalDescription(fn (ManagedEnvironment $record, mixed $livewire): string => static::triageReviewActionModalDescription( $record, static::currentPortfolioTriageState($livewire), - TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, )) ->visible(fn (ManagedEnvironment $record, mixed $livewire): bool => static::selectedTriageReviewRowForTenant( $record, @@ -1065,12 +1065,12 @@ public static function table(Table $table): Table ->action(function ( ManagedEnvironment $record, mixed $livewire, - TenantTriageReviewService $service, + ManagedEnvironmentTriageReviewService $service, ): void { static::handleTriageReviewMutation( tenant: $record, triageState: static::currentPortfolioTriageState($livewire), - targetManualState: TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + targetManualState: ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, service: $service, ); }), @@ -1149,13 +1149,13 @@ public static function table(Table $table): Table ->visible(fn (): bool => auth()->user() instanceof User) ->authorize(fn (): bool => auth()->user() instanceof User) ->extraAttributes(fn (mixed $livewire): array => [ - 'x-bind:aria-disabled' => static::crossTenantCompareBulkClientDisabledExpression($livewire).' ? true : null', - 'x-bind:disabled' => static::crossTenantCompareBulkClientDisabledExpression($livewire), - 'x-bind:title' => static::crossTenantCompareBulkClientTooltipExpression($livewire), - 'x-bind:class' => "{ 'fi-disabled': ".static::crossTenantCompareBulkClientDisabledExpression($livewire).' }', + 'x-bind:aria-disabled' => static::crossEnvironmentCompareBulkClientDisabledExpression($livewire).' ? true : null', + 'x-bind:disabled' => static::crossEnvironmentCompareBulkClientDisabledExpression($livewire), + 'x-bind:title' => static::crossEnvironmentCompareBulkClientTooltipExpression($livewire), + 'x-bind:class' => "{ 'fi-disabled': ".static::crossEnvironmentCompareBulkClientDisabledExpression($livewire).' }', ]) ->action(function (Collection $records, mixed $livewire): void { - $disabledReason = static::crossTenantCompareBulkDisabledReason($records); + $disabledReason = static::crossEnvironmentCompareBulkDisabledReason($records); if ($disabledReason !== null) { Notification::make() @@ -1167,7 +1167,7 @@ public static function table(Table $table): Table } if (method_exists($livewire, 'redirect')) { - $livewire->redirect(static::crossTenantCompareBulkOpenUrl($records, $livewire), navigate: true); + $livewire->redirect(static::crossEnvironmentCompareBulkOpenUrl($records, $livewire), navigate: true); } }), Actions\BulkAction::make('syncSelected') @@ -1324,7 +1324,7 @@ public static function sanitizeReviewStates(mixed $value): array { return static::sanitizeRequestedValues( $value, - TenantTriageReview::DERIVED_STATES, + ManagedEnvironmentTriageReview::DERIVED_STATES, ); } @@ -1366,10 +1366,10 @@ public static function tenantDashboardOpenUrl(ManagedEnvironment $record, array * triage_sort?: string|null * } $triageState */ - public static function crossTenantCompareOpenUrl(ManagedEnvironment $record, array $triageState = []): string + public static function crossEnvironmentCompareOpenUrl(ManagedEnvironment $record, array $triageState = []): string { - return static::crossTenantCompareOpenUrlForSelection( - targetTenant: $record, + return static::crossEnvironmentCompareOpenUrlForSelection( + targetEnvironment: $record, triageState: $triageState, ); } @@ -1382,10 +1382,10 @@ public static function crossTenantCompareOpenUrl(ManagedEnvironment $record, arr * triage_sort?: string|null * } $triageState */ - public static function crossTenantCompareOpenUrlForSelection( - ManagedEnvironment $targetTenant, + public static function crossEnvironmentCompareOpenUrlForSelection( + ManagedEnvironment $targetEnvironment, array $triageState = [], - ?ManagedEnvironment $sourceTenant = null, + ?ManagedEnvironment $sourceEnvironment = null, ): string { $normalizedState = static::portfolioReturnFilters( static::sanitizeBackupPostures($triageState['backup_posture'] ?? []), @@ -1394,12 +1394,12 @@ public static function crossTenantCompareOpenUrlForSelection( static::sanitizeTriageSort($triageState['triage_sort'] ?? null), ); - return CrossTenantComparePage::launchUrl( - sourceTenant: $sourceTenant, - targetTenant: $targetTenant, + return CrossEnvironmentComparePage::launchUrl( + sourceEnvironment: $sourceEnvironment, + targetEnvironment: $targetEnvironment, navigationContext: CanonicalNavigationContext::forTenantRegistry( backLinkUrl: static::getUrl(panel: 'admin', parameters: $normalizedState), - tenantId: $sourceTenant instanceof ManagedEnvironment ? null : (int) $targetTenant->getKey(), + tenantId: $sourceEnvironment instanceof ManagedEnvironment ? null : (int) $targetEnvironment->getKey(), ), ); } @@ -1494,7 +1494,7 @@ private static function portfolioReturnFiltersFromRequest(array $query): array ); } - private static function crossTenantCompareActionVisible(ManagedEnvironment $record): bool + private static function crossEnvironmentCompareActionVisible(ManagedEnvironment $record): bool { if (! $record->isActive()) { return false; @@ -1533,7 +1533,7 @@ private static function crossTenantCompareActionVisible(ManagedEnvironment $reco && $tenantResolver->can($user, $record, Capabilities::TENANT_VIEW); } - private static function crossTenantCompareBulkDisabledReason(Collection $records): ?string + private static function crossEnvironmentCompareBulkDisabledReason(Collection $records): ?string { $user = auth()->user(); @@ -1541,20 +1541,20 @@ private static function crossTenantCompareBulkDisabledReason(Collection $records return UiTooltips::insufficientPermission(); } - $tenants = $records + $environments = $records ->filter(fn ($record): bool => $record instanceof ManagedEnvironment) ->values(); - if ($records->count() !== 2 || $tenants->count() !== 2) { - return 'Select exactly two tenants to compare.'; + if ($records->count() !== 2 || $environments->count() !== 2) { + return 'Select exactly two environments to compare.'; } - if ($tenants->contains(fn (ManagedEnvironment $tenant): bool => ! $tenant->isActive())) { - return 'Only active tenants can be compared.'; + if ($environments->contains(fn (ManagedEnvironment $environment): bool => ! $environment->isActive())) { + return 'Only active environments can be compared.'; } - $workspaceIds = $tenants - ->map(fn (ManagedEnvironment $tenant): int => (int) $tenant->workspace_id) + $workspaceIds = $environments + ->map(fn (ManagedEnvironment $environment): int => (int) $environment->workspace_id) ->unique() ->values(); @@ -1578,32 +1578,32 @@ private static function crossTenantCompareBulkDisabledReason(Collection $records return UiTooltips::insufficientPermission(); } - /** @var CapabilityResolver $tenantResolver */ - $tenantResolver = app(CapabilityResolver::class); + /** @var CapabilityResolver $environmentResolver */ + $environmentResolver = app(CapabilityResolver::class); - $isDenied = $tenants->contains(fn (ManagedEnvironment $tenant): bool => ! $user->canAccessTenant($tenant) - || ! $tenantResolver->can($user, $tenant, Capabilities::TENANT_VIEW)); + $isDenied = $environments->contains(fn (ManagedEnvironment $environment): bool => ! $user->canAccessTenant($environment) + || ! $environmentResolver->can($user, $environment, Capabilities::TENANT_VIEW)); return $isDenied ? UiTooltips::insufficientPermission() : null; } - private static function crossTenantCompareBulkClientDisabledExpression(mixed $livewire): string + private static function crossEnvironmentCompareBulkClientDisabledExpression(mixed $livewire): string { - $containsInactiveSelection = static::crossTenantCompareBulkContainsInactiveSelectionExpression($livewire); + $containsInactiveSelection = static::crossEnvironmentCompareBulkContainsInactiveSelectionExpression($livewire); return "getSelectedRecordsCount() !== 2 || {$containsInactiveSelection}"; } - private static function crossTenantCompareBulkClientTooltipExpression(mixed $livewire): string + private static function crossEnvironmentCompareBulkClientTooltipExpression(mixed $livewire): string { - $containsInactiveSelection = static::crossTenantCompareBulkContainsInactiveSelectionExpression($livewire); + $containsInactiveSelection = static::crossEnvironmentCompareBulkContainsInactiveSelectionExpression($livewire); - return "getSelectedRecordsCount() !== 2 ? 'Select exactly two tenants to compare.' : ({$containsInactiveSelection} ? 'Only active tenants can be compared.' : null)"; + return "getSelectedRecordsCount() !== 2 ? 'Select exactly two environments to compare.' : ({$containsInactiveSelection} ? 'Only active environments can be compared.' : null)"; } - private static function crossTenantCompareBulkContainsInactiveSelectionExpression(mixed $livewire): string + private static function crossEnvironmentCompareBulkContainsInactiveSelectionExpression(mixed $livewire): string { - $inactiveRecordKeys = \Illuminate\Support\Js::from(static::crossTenantCompareInactiveSelectionRecordKeys($livewire)); + $inactiveRecordKeys = \Illuminate\Support\Js::from(static::crossEnvironmentCompareInactiveSelectionRecordKeys($livewire)); return "[...selectedRecords].some((key) => {$inactiveRecordKeys}.includes(key))"; } @@ -1611,7 +1611,7 @@ private static function crossTenantCompareBulkContainsInactiveSelectionExpressio /** * @return list */ - private static function crossTenantCompareInactiveSelectionRecordKeys(mixed $livewire): array + private static function crossEnvironmentCompareInactiveSelectionRecordKeys(mixed $livewire): array { if (! $livewire instanceof HasTable || ! method_exists($livewire, 'getTableRecordKey')) { return []; @@ -1630,9 +1630,9 @@ private static function crossTenantCompareInactiveSelectionRecordKeys(mixed $liv ->all(); } - private static function crossTenantCompareBulkOpenUrl(Collection $records, mixed $livewire): string + private static function crossEnvironmentCompareBulkOpenUrl(Collection $records, mixed $livewire): string { - $triageState = $livewire instanceof Pages\ListTenants + $triageState = $livewire instanceof Pages\ListManagedEnvironments ? static::currentPortfolioTriageState($livewire) : []; @@ -1649,10 +1649,10 @@ private static function crossTenantCompareBulkOpenUrl(Collection $records, mixed ->filter(fn ($record): bool => $record instanceof ManagedEnvironment) ->values(); - return static::crossTenantCompareOpenUrlForSelection( - targetTenant: $tenants->get(1), + return static::crossEnvironmentCompareOpenUrlForSelection( + targetEnvironment: $tenants->get(1), triageState: $triageState, - sourceTenant: $tenants->get(0), + sourceEnvironment: $tenants->get(0), ); } @@ -1808,9 +1808,9 @@ private static function recoveryEvidenceForTenant(ManagedEnvironment $tenant): ? */ private static function reviewStateOptions(): array { - return collect(TenantTriageReview::DERIVED_STATES) + return collect(ManagedEnvironmentTriageReview::DERIVED_STATES) ->mapWithKeys(static fn (string $state): array => [ - $state => BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $state)->label, + $state => BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $state)->label, ]) ->all(); } @@ -1854,7 +1854,7 @@ private static function triageReviewSnapshot(): array return $resolved; } - $resolved = app(TenantTriageReviewStateResolver::class)->resolveMany( + $resolved = app(ManagedEnvironmentTriageReviewStateResolver::class)->resolveMany( workspaceId: $workspaceId, tenantIds: $snapshot['tenant_ids'], backupHealthByTenant: $snapshot['backup_health'], @@ -2035,8 +2035,8 @@ private static function triageReviewActionModalDescription( return 'This triage slice no longer points at a current visible concern.'; } - $currentLabel = BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $row['derived_state'])->label; - $targetLabel = BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $targetManualState)->label; + $currentLabel = BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $row['derived_state'])->label; + $targetLabel = BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $targetManualState)->label; return implode("\n\n", [ 'Concern family: '.$row['concern_family_label'], @@ -2071,7 +2071,7 @@ private static function triageReviewActionIsDisabled(ManagedEnvironment $tenant) return true; } - return ! $resolver->can($user, $tenant, Capabilities::TENANT_TRIAGE_REVIEW_MANAGE); + return ! $resolver->can($user, $tenant, Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE); } private static function triageReviewActionTooltip(ManagedEnvironment $tenant): ?string @@ -2084,7 +2084,7 @@ private static function triageReviewActionTooltip(ManagedEnvironment $tenant): ? $resolver = app(CapabilityResolver::class); - if ($resolver->isMember($user, $tenant) && ! $resolver->can($user, $tenant, Capabilities::TENANT_TRIAGE_REVIEW_MANAGE)) { + if ($resolver->isMember($user, $tenant) && ! $resolver->can($user, $tenant, Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE)) { return UiTooltips::insufficientPermission(); } @@ -2105,7 +2105,7 @@ private static function authorizeTriageReviewAction(ManagedEnvironment $tenant): abort(404); } - if (! $resolver->can($user, $tenant, Capabilities::TENANT_TRIAGE_REVIEW_MANAGE)) { + if (! $resolver->can($user, $tenant, Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE)) { abort(403); } } @@ -2122,7 +2122,7 @@ private static function handleTriageReviewMutation( ManagedEnvironment $tenant, array $triageState, string $targetManualState, - TenantTriageReviewService $service, + ManagedEnvironmentTriageReviewService $service, ): void { $row = static::selectedActionTriageReviewRowForTenant($tenant, $triageState); @@ -2141,14 +2141,14 @@ private static function handleTriageReviewMutation( $recoveryEvidence = static::recoveryEvidenceForTenant($tenant); $review = match ($targetManualState) { - TenantTriageReview::STATE_REVIEWED => $service->markReviewed( + ManagedEnvironmentTriageReview::STATE_REVIEWED => $service->markReviewed( tenant: $tenant, concernFamily: (string) $row['concern_family'], backupHealth: $backupHealth, recoveryEvidence: $recoveryEvidence, actor: $actor instanceof User ? $actor : null, ), - TenantTriageReview::STATE_FOLLOW_UP_NEEDED => $service->markFollowUpNeeded( + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED => $service->markFollowUpNeeded( tenant: $tenant, concernFamily: (string) $row['concern_family'], backupHealth: $backupHealth, @@ -2158,7 +2158,7 @@ private static function handleTriageReviewMutation( default => null, }; - if (! $review instanceof TenantTriageReview) { + if (! $review instanceof ManagedEnvironmentTriageReview) { return; } @@ -2169,7 +2169,7 @@ private static function handleTriageReviewMutation( ->body(sprintf( '%s is now %s for %s.', $tenant->name, - BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $review->current_state)->label, + BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $review->current_state)->label, static::triageConcernFamilyLabel((string) $review->concern_family), )) ->success() @@ -2197,7 +2197,7 @@ private static function selectedActionTriageReviewRowForTenant(ManagedEnvironmen $backupHealth = app(TenantBackupHealthResolver::class)->assess($tenant); $recoveryEvidence = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant); - $rows = app(TenantTriageReviewStateResolver::class)->resolveMany( + $rows = app(ManagedEnvironmentTriageReviewStateResolver::class)->resolveMany( workspaceId: $workspaceId, tenantIds: [$tenantId], backupHealthByTenant: [$tenantId => $backupHealth], @@ -2640,10 +2640,10 @@ public static function infolist(Schema $schema): Schema ->formatStateUsing(fn ($state) => is_array($state) ? implode(', ', $state) : (string) $state), Infolists\Components\TextEntry::make('status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantPermissionStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantPermissionStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantPermissionStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantPermissionStatus)), + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->color(BadgeRenderer::color(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::ManagedEnvironmentPermissionStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::ManagedEnvironmentPermissionStatus)), ]) ->columnSpanFull(), ]) @@ -2730,7 +2730,7 @@ public static function tenantIndexPrimaryAction(ManagedEnvironment $tenant): ?Te return $catalog[1] ?? null; } - public static function relatedOnboardingDraft(ManagedEnvironment $tenant): ?TenantOnboardingSession + public static function relatedOnboardingDraft(ManagedEnvironment $tenant): ?ManagedEnvironmentOnboardingSession { return static::tenantActionPolicy()->relatedOnboardingDraft($tenant); } @@ -2749,7 +2749,7 @@ public static function relatedOnboardingDraftUrl(ManagedEnvironment $tenant): ?s { $draft = static::relatedOnboardingDraft($tenant); - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return null; } @@ -3119,17 +3119,17 @@ private static function validatedLifecycleReason(string $reason, string $field): public static function getPages(): array { return [ - 'index' => Pages\ListTenants::route('/'), - 'view' => Pages\ViewTenant::route('/{record}'), - 'edit' => Pages\EditTenant::route('/{record}/edit'), - 'memberships' => Pages\ManageTenantMemberships::route('/{record}/memberships'), + 'index' => Pages\ListManagedEnvironments::route('/'), + 'view' => Pages\ViewManagedEnvironment::route('/{record}'), + 'edit' => Pages\EditManagedEnvironment::route('/{record}/edit'), + 'memberships' => Pages\ManageEnvironmentAccessScopes::route('/{record}/memberships'), ]; } public static function getRelations(): array { return [ - RelationManagers\TenantMembershipsRelationManager::class, + RelationManagers\ManagedEnvironmentMembershipsRelationManager::class, ]; } diff --git a/apps/platform/app/Filament/Resources/TenantResource/Pages/EditTenant.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/EditManagedEnvironment.php similarity index 64% rename from apps/platform/app/Filament/Resources/TenantResource/Pages/EditTenant.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/EditManagedEnvironment.php index 75d0ed9f..15adde8e 100644 --- a/apps/platform/app/Filament/Resources/TenantResource/Pages/EditTenant.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/EditManagedEnvironment.php @@ -1,26 +1,26 @@ color('gray') ->visible(fn (): bool => $this->getRecord() instanceof ManagedEnvironment && in_array( - TenantResource::lifecycleActionDescriptor($this->getRecord(), TenantActionSurface::TenantEditHeader)?->key, + ManagedEnvironmentResource::lifecycleActionDescriptor($this->getRecord(), TenantActionSurface::TenantEditHeader)?->key, ['archive', 'restore'], true, )), diff --git a/apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ListManagedEnvironments.php similarity index 77% rename from apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ListManagedEnvironments.php index 162f8fe5..9e09f312 100644 --- a/apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ListManagedEnvironments.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace App\Filament\Resources\TenantResource\Pages; +namespace App\Filament\Resources\ManagedEnvironmentResource\Pages; -use App\Filament\Resources\TenantResource; +use App\Filament\Resources\ManagedEnvironmentResource; use App\Models\User; use App\Models\Workspace; use App\Services\Onboarding\OnboardingDraftResolver; @@ -13,9 +13,9 @@ use Filament\Actions; use Filament\Resources\Pages\ListRecords; -class ListTenants extends ListRecords +class ListManagedEnvironments extends ListRecords { - protected static string $resource = TenantResource::class; + protected static string $resource = ManagedEnvironmentResource::class; public function mount(): void { @@ -64,7 +64,7 @@ protected function getTableEmptyStateDescription(): ?string private function makeOnboardingEntryAction(): Actions\Action { - $descriptor = TenantResource::tenantActionPolicy()->onboardingEntryDescriptor($this->accessibleResumableDraftCount()); + $descriptor = ManagedEnvironmentResource::tenantActionPolicy()->onboardingEntryDescriptor($this->accessibleResumableDraftCount()); return Actions\Action::make('add_tenant') ->label($descriptor->label) @@ -92,10 +92,10 @@ private function applyRequestedTriageIntent(): void return; } - $backupPostures = TenantResource::sanitizeBackupPostures(request()->query('backup_posture')); - $recoveryEvidence = TenantResource::sanitizeRecoveryEvidenceStates(request()->query('recovery_evidence')); - $reviewStates = TenantResource::sanitizeReviewStates(request()->query('review_state')); - $triageSort = TenantResource::sanitizeTriageSort(request()->query('triage_sort')); + $backupPostures = ManagedEnvironmentResource::sanitizeBackupPostures(request()->query('backup_posture')); + $recoveryEvidence = ManagedEnvironmentResource::sanitizeRecoveryEvidenceStates(request()->query('recovery_evidence')); + $reviewStates = ManagedEnvironmentResource::sanitizeReviewStates(request()->query('review_state')); + $triageSort = ManagedEnvironmentResource::sanitizeTriageSort(request()->query('triage_sort')); foreach (['backup_posture', 'recovery_evidence', 'review_state', 'triage_sort'] as $filterName) { data_forget($this->tableFilters, $filterName); @@ -139,10 +139,10 @@ private function hasActiveTriageEmptyState(): bool public function currentPortfolioTriageReturnState(): array { return [ - 'backup_posture' => TenantResource::sanitizeBackupPostures(data_get($this->tableFilters, 'backup_posture.values', [])), - 'recovery_evidence' => TenantResource::sanitizeRecoveryEvidenceStates(data_get($this->tableFilters, 'recovery_evidence.values', [])), - 'review_state' => TenantResource::sanitizeReviewStates(data_get($this->tableFilters, 'review_state.values', [])), - 'triage_sort' => TenantResource::sanitizeTriageSort(data_get($this->tableFilters, 'triage_sort.value')), + 'backup_posture' => ManagedEnvironmentResource::sanitizeBackupPostures(data_get($this->tableFilters, 'backup_posture.values', [])), + 'recovery_evidence' => ManagedEnvironmentResource::sanitizeRecoveryEvidenceStates(data_get($this->tableFilters, 'recovery_evidence.values', [])), + 'review_state' => ManagedEnvironmentResource::sanitizeReviewStates(data_get($this->tableFilters, 'review_state.values', [])), + 'triage_sort' => ManagedEnvironmentResource::sanitizeTriageSort(data_get($this->tableFilters, 'triage_sort.value')), ]; } diff --git a/apps/platform/app/Filament/Resources/TenantResource/Pages/ManageTenantMemberships.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ManageEnvironmentAccessScopes.php similarity index 76% rename from apps/platform/app/Filament/Resources/TenantResource/Pages/ManageTenantMemberships.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ManageEnvironmentAccessScopes.php index b238f59e..58517792 100644 --- a/apps/platform/app/Filament/Resources/TenantResource/Pages/ManageTenantMemberships.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ManageEnvironmentAccessScopes.php @@ -1,18 +1,18 @@ getRouteKey() : $tenant); + parent::mount($environment instanceof ManagedEnvironment ? (string) $environment->getRouteKey() : $environment); } public function getSubheading(): ?string diff --git a/apps/platform/app/Filament/Resources/TenantResource/Pages/ViewTenant.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ViewManagedEnvironment.php similarity index 72% rename from apps/platform/app/Filament/Resources/TenantResource/Pages/ViewTenant.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ViewManagedEnvironment.php index bec06f66..7ae1fdf4 100644 --- a/apps/platform/app/Filament/Resources/TenantResource/Pages/ViewTenant.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/Pages/ViewManagedEnvironment.php @@ -1,12 +1,12 @@ label('External links') ->icon('heroicon-o-arrow-top-right-on-square') ->color('gray') ->visible(fn (): bool => $this->getRecord() instanceof ManagedEnvironment - && TenantResource::tenantViewExternalGroupVisible($this->getRecord())), + && ManagedEnvironmentResource::tenantViewExternalGroupVisible($this->getRecord())), Actions\ActionGroup::make([ - TenantResource::makeSyncTenantAction(), - TenantResource::makeVerifyConfigurationAction('tenant_view_header'), - TenantResource::rbacAction(), + ManagedEnvironmentResource::makeSyncTenantAction(), + ManagedEnvironmentResource::makeVerifyConfigurationAction('tenant_view_header'), + ManagedEnvironmentResource::rbacAction(), UiEnforcement::forAction( Actions\Action::make('refresh_rbac') ->label('Refresh RBAC status') ->icon('heroicon-o-arrow-path') ->color('primary') ->requiresConfirmation() - ->visible(fn (ManagedEnvironment $record): bool => TenantResource::tenantSetupMutationVisible($record)) + ->visible(fn (ManagedEnvironment $record): bool => ManagedEnvironmentResource::tenantSetupMutationVisible($record)) ->action(function (ManagedEnvironment $record): void { $user = auth()->user(); @@ -140,27 +140,27 @@ protected function getHeaderActions(): array ->icon('heroicon-o-wrench-screwdriver') ->color('gray') ->visible(fn (): bool => $this->getRecord() instanceof ManagedEnvironment - && TenantResource::tenantViewSetupGroupVisible($this->getRecord())), + && ManagedEnvironmentResource::tenantViewSetupGroupVisible($this->getRecord())), Actions\ActionGroup::make([ - TenantResource::makeTenantViewMarkReviewedAction(), - TenantResource::makeTenantViewMarkFollowUpNeededAction(), + ManagedEnvironmentResource::makeTenantViewMarkReviewedAction(), + ManagedEnvironmentResource::makeTenantViewMarkFollowUpNeededAction(), ]) ->label('Triage') ->icon('heroicon-o-check-circle') ->color('gray') ->visible(fn (): bool => $this->getRecord() instanceof ManagedEnvironment - && TenantResource::tenantViewTriageGroupVisible($this->getRecord())), + && ManagedEnvironmentResource::tenantViewTriageGroupVisible($this->getRecord())), Actions\ActionGroup::make([ - TenantResource::makeRestoreTenantAction(TenantActionSurface::TenantViewHeader), - TenantResource::makeRestoreTenantToWorkspaceAction(), - TenantResource::makeRemoveTenantFromWorkspaceAction(), - TenantResource::makeArchiveTenantAction(TenantActionSurface::TenantViewHeader), + ManagedEnvironmentResource::makeRestoreTenantAction(TenantActionSurface::TenantViewHeader), + ManagedEnvironmentResource::makeRestoreTenantToWorkspaceAction(), + ManagedEnvironmentResource::makeRemoveTenantFromWorkspaceAction(), + ManagedEnvironmentResource::makeArchiveTenantAction(TenantActionSurface::TenantViewHeader), ]) ->label('Lifecycle') ->icon('heroicon-o-archive-box') ->color('gray') ->visible(fn (): bool => $this->getRecord() instanceof ManagedEnvironment - && TenantResource::tenantViewLifecycleGroupVisible($this->getRecord())), + && ManagedEnvironmentResource::tenantViewLifecycleGroupVisible($this->getRecord())), ])); } } diff --git a/apps/platform/app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/RelationManagers/ManagedEnvironmentMembershipsRelationManager.php similarity index 94% rename from apps/platform/app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php rename to apps/platform/app/Filament/Resources/ManagedEnvironmentResource/RelationManagers/ManagedEnvironmentMembershipsRelationManager.php index d43b6ae7..8b71affd 100644 --- a/apps/platform/app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php +++ b/apps/platform/app/Filament/Resources/ManagedEnvironmentResource/RelationManagers/ManagedEnvironmentMembershipsRelationManager.php @@ -1,13 +1,13 @@ searchable() ->options(fn (): array => $this->workspaceMemberOptions()), ]) - ->action(function (array $data, TenantMembershipManager $manager): void { + ->action(function (array $data, ManagedEnvironmentMembershipManager $manager): void { $tenant = $this->getOwnerRecord(); if (! $tenant instanceof ManagedEnvironment) { @@ -155,7 +155,7 @@ public function table(Table $table): Table ->color('danger') ->icon('heroicon-o-x-mark') ->requiresConfirmation() - ->action(function (ManagedEnvironmentMembership $record, TenantMembershipManager $manager): void { + ->action(function (ManagedEnvironmentMembership $record, ManagedEnvironmentMembershipManager $manager): void { $tenant = $this->getOwnerRecord(); if (! $tenant instanceof ManagedEnvironment) { diff --git a/apps/platform/app/Filament/Resources/ReviewPackResource.php b/apps/platform/app/Filament/Resources/ReviewPackResource.php index f5e9ecee..fe9798d4 100644 --- a/apps/platform/app/Filament/Resources/ReviewPackResource.php +++ b/apps/platform/app/Filament/Resources/ReviewPackResource.php @@ -200,11 +200,11 @@ public static function infolist(Schema $schema): Schema Section::make('Metadata') ->schema([ TextEntry::make('initiator.name')->label('Initiated by')->placeholder('—'), - TextEntry::make('tenantReview.id') + TextEntry::make('environmentReview.id') ->label('ManagedEnvironment review') ->formatStateUsing(fn (?int $state): string => $state ? '#'.$state : '—') - ->url(fn (ReviewPack $record): ?string => $record->tenantReview && $record->tenant - ? TenantReviewResource::tenantScopedUrl('view', ['record' => $record->tenantReview], $record->tenant) + ->url(fn (ReviewPack $record): ?string => $record->environmentReview && $record->tenant + ? EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $record->environmentReview], $record->tenant) : null) ->placeholder('—'), TextEntry::make('customer_workspace') @@ -217,10 +217,10 @@ public static function infolist(Schema $schema): Schema TextEntry::make('summary.review_status') ->label('Review status') ->badge() - ->formatStateUsing(BadgeRenderer::label(BadgeDomain::TenantReviewStatus)) - ->color(BadgeRenderer::color(BadgeDomain::TenantReviewStatus)) - ->icon(BadgeRenderer::icon(BadgeDomain::TenantReviewStatus)) - ->iconColor(BadgeRenderer::iconColor(BadgeDomain::TenantReviewStatus)) + ->formatStateUsing(BadgeRenderer::label(BadgeDomain::EnvironmentReviewStatus)) + ->color(BadgeRenderer::color(BadgeDomain::EnvironmentReviewStatus)) + ->icon(BadgeRenderer::icon(BadgeDomain::EnvironmentReviewStatus)) + ->iconColor(BadgeRenderer::iconColor(BadgeDomain::EnvironmentReviewStatus)) ->placeholder('—'), TextEntry::make('operationRun.id') ->label('Operation') @@ -306,7 +306,7 @@ public static function table(Table $table): Table ->dateTime() ->sortable() ->placeholder('—'), - Tables\Columns\TextColumn::make('tenantReview.id') + Tables\Columns\TextColumn::make('environmentReview.id') ->label('Review') ->formatStateUsing(fn (?int $state): string => $state ? '#'.$state : '—') ->toggleable(isToggledHiddenByDefault: true), @@ -429,7 +429,7 @@ public static function getEloquentQuery(): Builder } return parent::getEloquentQuery() - ->with(['tenant', 'operationRun', 'evidenceSnapshot', 'tenantReview']) + ->with(['tenant', 'operationRun', 'evidenceSnapshot', 'environmentReview']) ->where('managed_environment_id', (int) $tenant->getKey()); } @@ -575,7 +575,7 @@ public static function executeGeneration(array $data): void return; } - OperationUxPresenter::queuedToast('tenant.review_pack.generate')->send(); + OperationUxPresenter::queuedToast('environment.review_pack.generate')->send(); } /** diff --git a/apps/platform/app/Filament/Resources/TenantReviewResource/Pages/ListTenantReviews.php b/apps/platform/app/Filament/Resources/TenantReviewResource/Pages/ListTenantReviews.php deleted file mode 100644 index 4db3d139..00000000 --- a/apps/platform/app/Filament/Resources/TenantReviewResource/Pages/ListTenantReviews.php +++ /dev/null @@ -1,20 +0,0 @@ - + * @return Collection */ - public function tenantPermissions(): Collection + public function managedEnvironmentPermissions(): Collection { - return TenantPermission::query() + return ManagedEnvironmentPermission::query() ->where('managed_environment_id', (int) $this->tenant->getKey()) ->orderBy('permission_key') ->limit(20) diff --git a/apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php b/apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php index 6cae2688..0c105d34 100644 --- a/apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php +++ b/apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php @@ -6,7 +6,7 @@ use App\Models\ManagedEnvironment; use App\Support\OpsUx\ActiveRuns; -use App\Support\TenantDashboard\TenantDashboardSummaryBuilder; +use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder; use Filament\Facades\Filament; use Filament\Widgets\StatsOverviewWidget; use Filament\Widgets\StatsOverviewWidget\Stat; @@ -32,7 +32,7 @@ protected function getStats(): array return []; } - $summary = app(TenantDashboardSummaryBuilder::class)->build($tenant, auth()->user()); + $summary = app(EnvironmentDashboardSummaryBuilder::class)->build($tenant, auth()->user()); $stats = []; diff --git a/apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardContextChips.php b/apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardContextChips.php similarity index 76% rename from apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardContextChips.php rename to apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardContextChips.php index d06bcea8..c025ab95 100644 --- a/apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardContextChips.php +++ b/apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardContextChips.php @@ -5,17 +5,17 @@ namespace App\Filament\Widgets\Dashboard; use App\Models\ManagedEnvironment; -use App\Support\TenantDashboard\TenantDashboardSummaryBuilder; +use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder; use Filament\Facades\Filament; use Filament\Widgets\Widget; -class TenantDashboardContextChips extends Widget +class EnvironmentDashboardContextChips extends Widget { protected static bool $isLazy = false; protected int|string|array $columnSpan = 'full'; - protected string $view = 'filament.widgets.dashboard.tenant-dashboard-context-chips'; + protected string $view = 'filament.widgets.dashboard.environment-dashboard-context-chips'; /** * @return array @@ -37,11 +37,11 @@ protected function getViewData(): array ]; } - $summary = app(TenantDashboardSummaryBuilder::class)->build($tenant, auth()->user()); + $summary = app(EnvironmentDashboardSummaryBuilder::class)->build($tenant, auth()->user()); return [ 'context' => $summary->context, 'pollingInterval' => $summary->pollingInterval, ]; } -} \ No newline at end of file +} diff --git a/apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardOverview.php b/apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardOverview.php similarity index 85% rename from apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardOverview.php rename to apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardOverview.php index a01a3b79..77bb9149 100644 --- a/apps/platform/app/Filament/Widgets/Dashboard/TenantDashboardOverview.php +++ b/apps/platform/app/Filament/Widgets/Dashboard/EnvironmentDashboardOverview.php @@ -5,17 +5,17 @@ namespace App\Filament\Widgets\Dashboard; use App\Models\ManagedEnvironment; -use App\Support\TenantDashboard\TenantDashboardSummaryBuilder; +use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder; use Filament\Facades\Filament; use Filament\Widgets\Widget; -class TenantDashboardOverview extends Widget +class EnvironmentDashboardOverview extends Widget { protected static bool $isLazy = false; protected int|string|array $columnSpan = 'full'; - protected string $view = 'filament.widgets.dashboard.tenant-dashboard-overview'; + protected string $view = 'filament.widgets.dashboard.environment-dashboard-overview'; /** * @return array @@ -49,8 +49,8 @@ protected function getViewData(): array ]; } - return app(TenantDashboardSummaryBuilder::class) + return app(EnvironmentDashboardSummaryBuilder::class) ->build($tenant) ->toArray(); } -} \ No newline at end of file +} diff --git a/apps/platform/app/Filament/Widgets/Tenant/AdminRolesSummaryWidget.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/AdminRolesSummaryWidget.php similarity index 97% rename from apps/platform/app/Filament/Widgets/Tenant/AdminRolesSummaryWidget.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/AdminRolesSummaryWidget.php index d3e073c8..b62b3655 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/AdminRolesSummaryWidget.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/AdminRolesSummaryWidget.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Filament\Resources\StoredReportResource; use App\Jobs\ScanEntraAdminRolesJob; @@ -22,7 +22,7 @@ class AdminRolesSummaryWidget extends Widget { protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.admin-roles-summary'; + protected string $view = 'filament.widgets.managed-environment.admin-roles-summary'; public ?ManagedEnvironment $record = null; diff --git a/apps/platform/app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/BaselineCompareCoverageBanner.php similarity index 93% rename from apps/platform/app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/BaselineCompareCoverageBanner.php index 7ca8733f..1c777a82 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/BaselineCompareCoverageBanner.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Filament\Pages\BaselineCompareLanding; use App\Models\ManagedEnvironment; @@ -16,7 +16,7 @@ class BaselineCompareCoverageBanner extends Widget { protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.baseline-compare-coverage-banner'; + protected string $view = 'filament.widgets.managed-environment.baseline-compare-coverage-banner'; /** * @return array diff --git a/apps/platform/app/Filament/Widgets/Tenant/FindingExceptionStatsOverview.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingExceptionStatsOverview.php similarity index 95% rename from apps/platform/app/Filament/Widgets/Tenant/FindingExceptionStatsOverview.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingExceptionStatsOverview.php index 0793e910..358291b5 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/FindingExceptionStatsOverview.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingExceptionStatsOverview.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Filament\Resources\FindingExceptionResource; use Filament\Widgets\StatsOverviewWidget as BaseWidget; diff --git a/apps/platform/app/Filament/Widgets/Tenant/FindingStatsOverview.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingStatsOverview.php similarity index 95% rename from apps/platform/app/Filament/Widgets/Tenant/FindingStatsOverview.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingStatsOverview.php index 62411b25..3fc13d6f 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/FindingStatsOverview.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/FindingStatsOverview.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Filament\Resources\FindingResource; use Filament\Widgets\StatsOverviewWidget as BaseWidget; diff --git a/apps/platform/app/Filament/Widgets/Tenant/TenantArchivedBanner.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentArchivedBanner.php similarity index 74% rename from apps/platform/app/Filament/Widgets/Tenant/TenantArchivedBanner.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentArchivedBanner.php index 99e39eb4..a033a05d 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/TenantArchivedBanner.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentArchivedBanner.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Models\ManagedEnvironment; use App\Support\Tenants\TenantLifecyclePresentation; use Filament\Facades\Filament; use Filament\Widgets\Widget; -class TenantArchivedBanner extends Widget +class ManagedEnvironmentArchivedBanner extends Widget { protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.tenant-archived-banner'; + protected string $view = 'filament.widgets.managed-environment.managed-environment-archived-banner'; /** * @return array diff --git a/apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentReviewPackCard.php similarity index 95% rename from apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentReviewPackCard.php index 14a0231b..b7705d89 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentReviewPackCard.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Exceptions\Entitlements\WorkspaceEntitlementBlockedException; use App\Filament\Pages\Reviews\CustomerReviewWorkspace; @@ -23,13 +23,13 @@ use Filament\Notifications\Notification; use Filament\Widgets\Widget; -class TenantReviewPackCard extends Widget +class ManagedEnvironmentReviewPackCard extends Widget { private const string ACTIVE_POLLING_INTERVAL = '10s'; protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.tenant-review-pack-card'; + protected string $view = 'filament.widgets.managed-environment.managed-environment-review-pack-card'; public ?ManagedEnvironment $record = null; @@ -176,7 +176,7 @@ protected function getViewData(): array : null; $latestPack = ReviewPack::query() - ->with(['tenantReview', 'operationRun']) + ->with(['environmentReview', 'operationRun']) ->where('managed_environment_id', (int) $tenant->getKey()) ->orderByDesc('created_at') ->orderByDesc('id') @@ -210,8 +210,8 @@ protected function getViewData(): array } $reviewUrl = null; - if ($latestPack->tenantReview && $canView) { - $reviewUrl = \App\Filament\Resources\TenantReviewResource::tenantScopedUrl('view', ['record' => $latestPack->tenantReview], $tenant); + if ($latestPack->environmentReview && $canView) { + $reviewUrl = \App\Filament\Resources\EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $latestPack->environmentReview], $tenant); } $failedReason = null; diff --git a/apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php similarity index 84% rename from apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php index 8f2da846..4398f9e9 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Models\ManagedEnvironment; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; -use App\Services\PortfolioTriage\TenantTriageReviewService; +use App\Services\PortfolioTriage\ManagedEnvironmentTriageReviewService; use App\Support\Auth\Capabilities; use App\Support\BackupHealth\TenantBackupHealthResolver; use App\Support\Badges\BadgeDomain; @@ -15,7 +15,7 @@ use App\Support\PortfolioTriage\PortfolioArrivalContext; use App\Support\PortfolioTriage\PortfolioArrivalContextResolver; use App\Support\PortfolioTriage\PortfolioArrivalContextToken; -use App\Support\PortfolioTriage\TenantTriageReviewStateResolver; +use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewStateResolver; use App\Support\Rbac\UiEnforcement; use App\Support\RestoreSafety\RestoreSafetyResolver; use Filament\Actions\Action; @@ -27,7 +27,7 @@ use Filament\Schemas\Contracts\HasSchemas; use Filament\Widgets\Widget; -class TenantTriageArrivalContinuity extends Widget implements HasActions, HasSchemas +class ManagedEnvironmentTriageArrivalContinuity extends Widget implements HasActions, HasSchemas { use InteractsWithActions; use InteractsWithSchemas; @@ -59,7 +59,7 @@ class TenantTriageArrivalContinuity extends Widget implements HasActions, HasSch protected int|string|array $columnSpan = 'full'; - protected string $view = 'filament.widgets.tenant.triage-arrival-continuity'; + protected string $view = 'filament.widgets.managed-environment.triage-arrival-continuity'; public function mount(): void { @@ -100,14 +100,14 @@ public function markReviewedAction(): Action ->color('success') ->requiresConfirmation() ->modalHeading('Mark reviewed') - ->modalDescription($this->reviewModalDescription(TenantTriageReview::STATE_REVIEWED)) + ->modalDescription($this->reviewModalDescription(ManagedEnvironmentTriageReview::STATE_REVIEWED)) ->visible(fn (): bool => $this->canShowReviewActions()) - ->action(function (TenantTriageReviewService $service): void { - $this->handleReviewMutation(TenantTriageReview::STATE_REVIEWED, $service); + ->action(function (ManagedEnvironmentTriageReviewService $service): void { + $this->handleReviewMutation(ManagedEnvironmentTriageReview::STATE_REVIEWED, $service); }), ) ->preserveVisibility() - ->requireCapability(Capabilities::TENANT_TRIAGE_REVIEW_MANAGE) + ->requireCapability(Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE) ->apply(); } @@ -120,14 +120,14 @@ public function markFollowUpNeededAction(): Action ->color('warning') ->requiresConfirmation() ->modalHeading('Mark follow-up needed') - ->modalDescription($this->reviewModalDescription(TenantTriageReview::STATE_FOLLOW_UP_NEEDED)) + ->modalDescription($this->reviewModalDescription(ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED)) ->visible(fn (): bool => $this->canShowReviewActions()) - ->action(function (TenantTriageReviewService $service): void { - $this->handleReviewMutation(TenantTriageReview::STATE_FOLLOW_UP_NEEDED, $service); + ->action(function (ManagedEnvironmentTriageReviewService $service): void { + $this->handleReviewMutation(ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, $service); }), ) ->preserveVisibility() - ->requireCapability(Capabilities::TENANT_TRIAGE_REVIEW_MANAGE) + ->requireCapability(Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE) ->apply(); } @@ -170,10 +170,10 @@ private function reviewModalDescription(string $targetManualState): \Closure } $currentLabel = BadgeRenderer::spec( - BadgeDomain::TenantTriageReviewState, - (string) ($reviewState['derived_state'] ?? TenantTriageReview::DERIVED_STATE_NOT_REVIEWED), + BadgeDomain::ManagedEnvironmentTriageReviewState, + (string) ($reviewState['derived_state'] ?? ManagedEnvironmentTriageReview::DERIVED_STATE_NOT_REVIEWED), )->label; - $targetLabel = BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $targetManualState)->label; + $targetLabel = BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $targetManualState)->label; return implode("\n\n", [ 'Concern family: '.$this->concernFamilyLabel($context->concernFamily), @@ -184,7 +184,7 @@ private function reviewModalDescription(string $targetManualState): \Closure }; } - private function handleReviewMutation(string $targetManualState, TenantTriageReviewService $service): void + private function handleReviewMutation(string $targetManualState, ManagedEnvironmentTriageReviewService $service): void { $tenant = Filament::getTenant(); @@ -219,14 +219,14 @@ private function handleReviewMutation(string $targetManualState, TenantTriageRev $actor = auth()->user(); $review = match ($targetManualState) { - TenantTriageReview::STATE_REVIEWED => $service->markReviewed( + ManagedEnvironmentTriageReview::STATE_REVIEWED => $service->markReviewed( tenant: $tenant, concernFamily: $context->concernFamily, backupHealth: $concernTruth['backupHealth'], recoveryEvidence: $concernTruth['recoveryEvidence'], actor: $actor instanceof User ? $actor : null, ), - TenantTriageReview::STATE_FOLLOW_UP_NEEDED => $service->markFollowUpNeeded( + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED => $service->markFollowUpNeeded( tenant: $tenant, concernFamily: $context->concernFamily, backupHealth: $concernTruth['backupHealth'], @@ -236,7 +236,7 @@ private function handleReviewMutation(string $targetManualState, TenantTriageRev default => null, }; - if (! $review instanceof TenantTriageReview) { + if (! $review instanceof ManagedEnvironmentTriageReview) { return; } @@ -247,7 +247,7 @@ private function handleReviewMutation(string $targetManualState, TenantTriageRev ->body(sprintf( '%s is now %s for %s.', $tenant->name, - BadgeRenderer::spec(BadgeDomain::TenantTriageReviewState, $review->current_state)->label, + BadgeRenderer::spec(BadgeDomain::ManagedEnvironmentTriageReviewState, $review->current_state)->label, $this->concernFamilyLabel($context->concernFamily), )) ->success() @@ -268,7 +268,7 @@ private function currentReviewStateFor(ManagedEnvironment $tenant, string $conce $concernTruth = $this->concernTruthFor($tenant); - $reviewState = app(TenantTriageReviewStateResolver::class)->resolveMany( + $reviewState = app(ManagedEnvironmentTriageReviewStateResolver::class)->resolveMany( workspaceId: (int) $tenant->workspace_id, tenantIds: [$tenantId], backupHealthByTenant: [$tenantId => $concernTruth['backupHealth']], diff --git a/apps/platform/app/Filament/Widgets/Tenant/TenantVerificationReport.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentVerificationReport.php similarity index 94% rename from apps/platform/app/Filament/Widgets/Tenant/TenantVerificationReport.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentVerificationReport.php index 7a62fa39..e1a51593 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/TenantVerificationReport.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentVerificationReport.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; -use App\Filament\Resources\TenantResource\Pages\ViewTenant; +use App\Filament\Resources\ManagedEnvironmentResource\Pages\ViewManagedEnvironment; use App\Filament\Support\VerificationReportChangeIndicator; use App\Filament\Support\VerificationReportViewer; use App\Models\OperationRun; @@ -24,11 +24,11 @@ use Filament\Notifications\Notification; use Filament\Widgets\Widget; -class TenantVerificationReport extends Widget +class ManagedEnvironmentVerificationReport extends Widget { protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.tenant-verification-report'; + protected string $view = 'filament.widgets.managed-environment.managed-environment-verification-report'; public ?ManagedEnvironment $record = null; @@ -203,7 +203,7 @@ protected function getViewData(): array 'startTooltip' => $isTenantMember && $canOperate && ! $canStart ? UiTooltips::insufficientPermission() : null, 'lifecycleNotice' => $lifecycleNotice, 'rerunHint' => $run instanceof OperationRun && $canStart - ? ViewTenant::verificationHeaderActionHint() + ? ViewManagedEnvironment::verificationHeaderActionHint() : null, ]; } diff --git a/apps/platform/app/Filament/Widgets/Tenant/RecentOperationsSummary.php b/apps/platform/app/Filament/Widgets/ManagedEnvironment/RecentOperationsSummary.php similarity index 93% rename from apps/platform/app/Filament/Widgets/Tenant/RecentOperationsSummary.php rename to apps/platform/app/Filament/Widgets/ManagedEnvironment/RecentOperationsSummary.php index a85259d7..f56b0d14 100644 --- a/apps/platform/app/Filament/Widgets/Tenant/RecentOperationsSummary.php +++ b/apps/platform/app/Filament/Widgets/ManagedEnvironment/RecentOperationsSummary.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Filament\Widgets\Tenant; +namespace App\Filament\Widgets\ManagedEnvironment; use App\Models\OperationRun; use App\Models\ManagedEnvironment; @@ -15,7 +15,7 @@ class RecentOperationsSummary extends Widget { protected static bool $isLazy = false; - protected string $view = 'filament.widgets.tenant.recent-operations-summary'; + protected string $view = 'filament.widgets.managed-environment.recent-operations-summary'; public ?ManagedEnvironment $record = null; diff --git a/apps/platform/app/Http/Controllers/AdminConsentCallbackController.php b/apps/platform/app/Http/Controllers/AdminConsentCallbackController.php index 07e94015..06c4d2f8 100644 --- a/apps/platform/app/Http/Controllers/AdminConsentCallbackController.php +++ b/apps/platform/app/Http/Controllers/AdminConsentCallbackController.php @@ -4,7 +4,7 @@ use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Services\Intune\AuditLogger; use App\Support\Providers\ProviderConnectionType; use App\Support\Providers\ProviderConsentStatus; @@ -23,8 +23,8 @@ public function __invoke( Request $request, AuditLogger $auditLogger, ): View { - $expectedState = $request->session()->pull('tenant_onboard_state'); - $workspaceId = $request->session()->pull('tenant_onboard_workspace_id'); + $expectedState = $request->session()->pull('environment_onboard_state'); + $workspaceId = $request->session()->pull('environment_onboard_workspace_id'); $tenantKey = $request->string('tenant')->toString(); $state = $request->string('state')->toString(); $tenantIdentifier = $tenantKey ?: $this->parseState($state); @@ -219,10 +219,10 @@ private function verificationStateLabel(ProviderConnection $connection): string private function invalidateResumableOnboardingVerificationState(ManagedEnvironment $tenant, ProviderConnection $connection): void { - TenantOnboardingSession::query() + ManagedEnvironmentOnboardingSession::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->resumable() - ->each(function (TenantOnboardingSession $draft) use ($connection): void { + ->each(function (ManagedEnvironmentOnboardingSession $draft) use ($connection): void { $state = is_array($draft->state) ? $draft->state : []; $providerConnectionId = $state['provider_connection_id'] ?? null; $providerConnectionId = is_numeric($providerConnectionId) ? (int) $providerConnectionId : null; diff --git a/apps/platform/app/Http/Controllers/ClearTenantContextController.php b/apps/platform/app/Http/Controllers/ClearEnvironmentContextController.php similarity index 93% rename from apps/platform/app/Http/Controllers/ClearTenantContextController.php rename to apps/platform/app/Http/Controllers/ClearEnvironmentContextController.php index 79c9484c..1175ddb7 100644 --- a/apps/platform/app/Http/Controllers/ClearTenantContextController.php +++ b/apps/platform/app/Http/Controllers/ClearEnvironmentContextController.php @@ -11,7 +11,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; -final class ClearTenantContextController +final class ClearEnvironmentContextController { public function __invoke(Request $request): RedirectResponse { @@ -38,13 +38,13 @@ public function __invoke(Request $request): RedirectResponse $workspace = $workspaceContext->currentWorkspace($request); if ($workspace !== null) { - return redirect()->route('admin.workspace.managed-tenants.index', ['workspace' => $workspace]); + return redirect()->route('admin.workspace.managed-environments.index', ['workspace' => $workspace]); } return redirect()->route('admin.home'); } - if ($previousPath === '' || $previousPath === '/admin/clear-tenant-context') { + if ($previousPath === '' || $previousPath === '/admin/clear-environment-context') { return redirect()->to(OperationRunLinks::index()); } diff --git a/apps/platform/app/Http/Controllers/TenantOnboardingController.php b/apps/platform/app/Http/Controllers/ManagedEnvironmentOnboardingController.php similarity index 95% rename from apps/platform/app/Http/Controllers/TenantOnboardingController.php rename to apps/platform/app/Http/Controllers/ManagedEnvironmentOnboardingController.php index 8cca10c4..315ae710 100644 --- a/apps/platform/app/Http/Controllers/TenantOnboardingController.php +++ b/apps/platform/app/Http/Controllers/ManagedEnvironmentOnboardingController.php @@ -16,7 +16,7 @@ use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Response as ResponseAlias; -class TenantOnboardingController extends Controller +class ManagedEnvironmentOnboardingController extends Controller { public function __invoke( Request $request, @@ -27,12 +27,12 @@ public function __invoke( abort_if($tenantIdentifier === '', ResponseAlias::HTTP_NOT_FOUND); $state = Str::uuid()->toString(); - $request->session()->put('tenant_onboard_state', $state); + $request->session()->put('environment_onboard_state', $state); $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId($request); if ($workspaceId !== null) { - $request->session()->put('tenant_onboard_workspace_id', (int) $workspaceId); + $request->session()->put('environment_onboard_workspace_id', (int) $workspaceId); } $tenant = $this->resolveTenant($tenantIdentifier, is_numeric($workspaceId) ? (int) $workspaceId : null); diff --git a/apps/platform/app/Http/Controllers/OpenFindingExceptionsQueueController.php b/apps/platform/app/Http/Controllers/OpenFindingExceptionsQueueController.php index 185007a6..5f3d9b9b 100644 --- a/apps/platform/app/Http/Controllers/OpenFindingExceptionsQueueController.php +++ b/apps/platform/app/Http/Controllers/OpenFindingExceptionsQueueController.php @@ -16,7 +16,7 @@ final class OpenFindingExceptionsQueueController extends Controller { - public function __invoke(Request $request, ManagedEnvironment $tenant): RedirectResponse + public function __invoke(Request $request, ManagedEnvironment $environment): RedirectResponse { $user = auth()->user(); @@ -24,13 +24,13 @@ public function __invoke(Request $request, ManagedEnvironment $tenant): Redirect abort(403); } - $workspace = Workspace::query()->whereKey($tenant->workspace_id)->first(); + $workspace = Workspace::query()->whereKey($environment->workspace_id)->first(); if (! $workspace instanceof Workspace) { abort(404); } - if (! $user->canAccessTenant($tenant)) { + if (! $user->canAccessTenant($environment)) { abort(404); } @@ -49,12 +49,12 @@ public function __invoke(Request $request, ManagedEnvironment $tenant): Redirect $workspaceContext->setCurrentWorkspace($workspace, $user, $request); - if (! $workspaceContext->rememberTenantContext($tenant, $request)) { + if (! $workspaceContext->rememberTenantContext($environment, $request)) { abort(404); } return redirect()->to(FindingExceptionsQueue::getUrl([ - 'tenant' => (string) $tenant->external_id, + 'tenant' => (string) $environment->external_id, ], panel: 'admin')); } } diff --git a/apps/platform/app/Http/Controllers/ReviewPackDownloadController.php b/apps/platform/app/Http/Controllers/ReviewPackDownloadController.php index acf7e8e4..4c9738f2 100644 --- a/apps/platform/app/Http/Controllers/ReviewPackDownloadController.php +++ b/apps/platform/app/Http/Controllers/ReviewPackDownloadController.php @@ -55,8 +55,8 @@ public function __invoke(Request $request, ReviewPack $reviewPack): StreamedResp context: [ 'metadata' => [ 'review_pack_id' => (int) $reviewPack->getKey(), - 'tenant_review_id' => $reviewPack->tenant_review_id !== null - ? (int) $reviewPack->tenant_review_id + 'environment_review_id' => $reviewPack->environment_review_id !== null + ? (int) $reviewPack->environment_review_id : null, 'source_surface' => (string) $request->query('source_surface', 'review_pack'), 'review_id' => $request->query('review_id'), diff --git a/apps/platform/app/Http/Controllers/SelectTenantController.php b/apps/platform/app/Http/Controllers/SelectEnvironmentController.php similarity index 98% rename from apps/platform/app/Http/Controllers/SelectTenantController.php rename to apps/platform/app/Http/Controllers/SelectEnvironmentController.php index ff9ff7f9..be83360a 100644 --- a/apps/platform/app/Http/Controllers/SelectTenantController.php +++ b/apps/platform/app/Http/Controllers/SelectEnvironmentController.php @@ -16,7 +16,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Schema; -final class SelectTenantController +final class SelectEnvironmentController { public function __invoke(Request $request): RedirectResponse { diff --git a/apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php b/apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php index 8904cba7..1ffa7756 100644 --- a/apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php +++ b/apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php @@ -204,7 +204,7 @@ private function isLivewireUpdatePath(string $path): bool private function isChooserFirstPath(string $path): bool { - return in_array($path, ['/admin', '/admin/choose-tenant'], true); + return in_array($path, ['/admin', '/admin/choose-environment'], true); } private function requestHasExplicitTenantContext(Request $request): bool diff --git a/apps/platform/app/Jobs/BulkTenantSyncJob.php b/apps/platform/app/Jobs/BulkTenantSyncJob.php index 1f202975..871dce26 100644 --- a/apps/platform/app/Jobs/BulkTenantSyncJob.php +++ b/apps/platform/app/Jobs/BulkTenantSyncJob.php @@ -69,9 +69,9 @@ public function handle(OperationRunService $runs): void $chunkSize = max(1, $chunkSize); foreach (array_chunk($ids, $chunkSize) as $chunk) { - foreach ($chunk as $targetTenantId) { + foreach ($chunk as $targetEnvironmentId) { dispatch(new TenantSyncWorkerJob( - tenantId: $targetTenantId, + tenantId: $targetEnvironmentId, userId: $this->userId, operationRun: $this->operationRun, context: $this->context, diff --git a/apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php b/apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php index c3ec4d7c..2378224a 100644 --- a/apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php +++ b/apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php @@ -100,7 +100,7 @@ public function handle( $context = is_array($this->operationRun->context) ? $this->operationRun->context : []; $profileId = (int) ($context['baseline_profile_id'] ?? 0); - $sourceTenantId = (int) ($context['source_tenant_id'] ?? 0); + $sourceEnvironmentId = (int) ($context['source_environment_id'] ?? 0); $profile = BaselineProfile::query()->find($profileId); @@ -108,10 +108,10 @@ public function handle( throw new RuntimeException("BaselineProfile #{$profileId} not found."); } - $sourceTenant = ManagedEnvironment::query()->find($sourceTenantId); + $sourceTenant = ManagedEnvironment::query()->find($sourceEnvironmentId); if (! $sourceTenant instanceof ManagedEnvironment) { - throw new RuntimeException("Source ManagedEnvironment #{$sourceTenantId} not found."); + throw new RuntimeException("Source ManagedEnvironment #{$sourceEnvironmentId} not found."); } $initiator = $this->operationRun->user_id diff --git a/apps/platform/app/Jobs/ComposeTenantReviewJob.php b/apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php similarity index 73% rename from apps/platform/app/Jobs/ComposeTenantReviewJob.php rename to apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php index ac8d9726..3c418efe 100644 --- a/apps/platform/app/Jobs/ComposeTenantReviewJob.php +++ b/apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php @@ -6,17 +6,17 @@ use App\Jobs\Concerns\BridgesFailedOperationRun; use App\Models\OperationRun; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Services\OperationRunService; -use App\Services\TenantReviews\TenantReviewService; +use App\Services\EnvironmentReviews\EnvironmentReviewService; use App\Support\OperationRunOutcome; use App\Support\OperationRunStatus; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewStatus; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; use Throwable; -class ComposeTenantReviewJob implements ShouldQueue +class ComposeEnvironmentReviewJob implements ShouldQueue { use BridgesFailedOperationRun; use Queueable; @@ -26,21 +26,21 @@ class ComposeTenantReviewJob implements ShouldQueue public bool $failOnTimeout = true; public function __construct( - public int $tenantReviewId, + public int $environmentReviewId, public int $operationRunId, ) {} - public function handle(TenantReviewService $service, OperationRunService $operationRuns): void + public function handle(EnvironmentReviewService $service, OperationRunService $operationRuns): void { - $review = TenantReview::query()->with(['tenant', 'evidenceSnapshot.items'])->find($this->tenantReviewId); + $review = EnvironmentReview::query()->with(['tenant', 'evidenceSnapshot.items'])->find($this->environmentReviewId); $operationRun = OperationRun::query()->find($this->operationRunId); - if (! $review instanceof TenantReview || ! $operationRun instanceof OperationRun || ! $review->tenant) { + if (! $review instanceof EnvironmentReview || ! $operationRun instanceof OperationRun || ! $review->tenant) { return; } $operationRuns->updateRun($operationRun, OperationRunStatus::Running->value, OperationRunOutcome::Pending->value); - $review->update(['status' => TenantReviewStatus::Draft->value]); + $review->update(['status' => EnvironmentReviewStatus::Draft->value]); try { $review = $service->compose($review); @@ -61,7 +61,7 @@ public function handle(TenantReviewService $service, OperationRunService $operat ); } catch (Throwable $throwable) { $review->update([ - 'status' => TenantReviewStatus::Failed->value, + 'status' => EnvironmentReviewStatus::Failed->value, 'summary' => array_merge(is_array($review->summary) ? $review->summary : [], [ 'error' => $throwable->getMessage(), ]), @@ -73,7 +73,7 @@ public function handle(TenantReviewService $service, OperationRunService $operat outcome: OperationRunOutcome::Failed->value, failures: [ [ - 'code' => 'tenant_review_compose.failed', + 'code' => 'environment_review_compose.failed', 'message' => $throwable->getMessage(), ], ], diff --git a/apps/platform/app/Jobs/GenerateReviewPackJob.php b/apps/platform/app/Jobs/GenerateReviewPackJob.php index 7c6d8a4b..fe920fb4 100644 --- a/apps/platform/app/Jobs/GenerateReviewPackJob.php +++ b/apps/platform/app/Jobs/GenerateReviewPackJob.php @@ -9,7 +9,7 @@ use App\Models\OperationRun; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Services\Intune\SecretClassificationService; use App\Services\OperationRunService; use App\Services\ReviewPackService; @@ -39,7 +39,7 @@ public function __construct( public function handle(OperationRunService $operationRunService): void { - $reviewPack = ReviewPack::query()->with(['tenant', 'evidenceSnapshot.items', 'tenantReview.sections'])->find($this->reviewPackId); + $reviewPack = ReviewPack::query()->with(['tenant', 'evidenceSnapshot.items', 'environmentReview.sections'])->find($this->reviewPackId); $operationRun = OperationRun::query()->find($this->operationRunId); if (! $reviewPack instanceof ReviewPack || ! $operationRun instanceof OperationRun) { @@ -82,9 +82,9 @@ public function handle(OperationRunService $operationRunService): void private function executeGeneration(ReviewPack $reviewPack, OperationRun $operationRun, ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, OperationRunService $operationRunService): void { - $review = $reviewPack->tenantReview; + $review = $reviewPack->environmentReview; - if ($review instanceof TenantReview) { + if ($review instanceof EnvironmentReview) { $this->executeReviewDerivedGeneration($reviewPack, $review, $operationRun, $tenant, $snapshot, $operationRunService); return; @@ -216,7 +216,7 @@ private function executeGeneration(ReviewPack $reviewPack, OperationRun $operati private function executeReviewDerivedGeneration( ReviewPack $reviewPack, - TenantReview $review, + EnvironmentReview $review, OperationRun $operationRun, ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, @@ -280,7 +280,7 @@ private function executeReviewDerivedGeneration( $fingerprint = app(ReviewPackService::class)->computeFingerprintForReview($review, $options); $reviewSummary = is_array($review->summary) ? $review->summary : []; $summary = [ - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'review_status' => (string) $review->status, 'review_completeness_state' => (string) $review->completeness_state, 'section_count' => $review->sections->count(), @@ -636,7 +636,7 @@ private function assembleZip(string $tempFile, array $fileMap, ?callable $afterW */ private function buildReviewDerivedFileMap( ReviewPack $reviewPack, - TenantReview $review, + EnvironmentReview $review, ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, bool $includePii, @@ -662,7 +662,7 @@ private function buildReviewDerivedFileMap( 'tenant_name' => $includePii ? $tenant->name : '[REDACTED]', 'generated_at' => $generatedAt->toIso8601String(), 'delivery_bundle' => $deliveryMetadata, - 'tenant_review' => [ + 'environment_review' => [ 'id' => (int) $review->getKey(), 'status' => (string) $review->status, 'completeness_state' => (string) $review->completeness_state, @@ -686,7 +686,7 @@ private function buildReviewDerivedFileMap( ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR), 'summary.json' => json_encode($this->redactReportPayload(array_merge( [ - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'review_status' => (string) $review->status, 'review_completeness_state' => (string) $review->completeness_state, ], @@ -738,7 +738,7 @@ private function buildReviewDerivedFileMap( /** * @return array */ - private function deliveryBundleSummary(TenantReview $review): array + private function deliveryBundleSummary(EnvironmentReview $review): array { return [ 'contract' => ReviewPackService::REVIEW_DERIVED_DELIVERY_CONTRACT, @@ -753,7 +753,7 @@ private function deliveryBundleSummary(TenantReview $review): array */ private function deliveryBundleMetadata( ReviewPack $reviewPack, - TenantReview $review, + EnvironmentReview $review, EvidenceSnapshot $snapshot, \Carbon\CarbonInterface $generatedAt, ): array { @@ -805,7 +805,7 @@ private function deliveryBundleMetadata( * @param array $reviewSummary */ private function buildExecutiveEntrypoint( - TenantReview $review, + EnvironmentReview $review, ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, array $reviewSummary, diff --git a/apps/platform/app/Jobs/Operations/CrossTenantPromotionExecutionJob.php b/apps/platform/app/Jobs/Operations/CrossEnvironmentPromotionExecutionJob.php similarity index 89% rename from apps/platform/app/Jobs/Operations/CrossTenantPromotionExecutionJob.php rename to apps/platform/app/Jobs/Operations/CrossEnvironmentPromotionExecutionJob.php index 0ef3507f..2109b146 100644 --- a/apps/platform/app/Jobs/Operations/CrossTenantPromotionExecutionJob.php +++ b/apps/platform/app/Jobs/Operations/CrossEnvironmentPromotionExecutionJob.php @@ -28,7 +28,7 @@ use RuntimeException; use Throwable; -final class CrossTenantPromotionExecutionJob implements ShouldQueue +final class CrossEnvironmentPromotionExecutionJob implements ShouldQueue { use Dispatchable; use InteractsWithQueue; @@ -73,16 +73,16 @@ public function handle( return; } - $tenant = $this->operationRun->tenant; + $targetEnvironment = $this->operationRun->tenant; - if (! $tenant instanceof ManagedEnvironment) { - throw new RuntimeException('Promotion execution target tenant is missing.'); + if (! $targetEnvironment instanceof ManagedEnvironment) { + throw new RuntimeException('Promotion execution target environment is missing.'); } $context = is_array($this->operationRun->context) ? $this->operationRun->context : []; $targetScope = is_array($context['target_scope'] ?? null) ? $context['target_scope'] : []; - $lock = $limiter->acquireSlot((int) $tenant->getKey(), $targetScope); + $lock = $limiter->acquireSlot((int) $targetEnvironment->getKey(), $targetScope); if (! $lock) { $this->release(max(1, (int) config('tenantpilot.bulk_operations.poll_interval_seconds', 3))); @@ -114,7 +114,7 @@ public function handle( $summary['total'] = count($items); [$backupSet, $selectedItemIds, $preRestoreSummary, $preRestoreFailures] = $this->buildRestoreInputs( - tenant: $tenant, + targetEnvironment: $targetEnvironment, operationRun: $this->operationRun, items: $items, ); @@ -126,7 +126,7 @@ public function handle( if ($selectedItemIds !== []) { $restoreRun = RestoreRun::withoutEvents(fn (): RestoreRun => $restoreService->execute( - tenant: $tenant, + tenant: $targetEnvironment, backupSet: $backupSet, selectedItemIds: $selectedItemIds, dryRun: false, @@ -160,10 +160,10 @@ public function handle( failures: $failures, ); - $auditLogger->logCrossTenantPromotionExecutionCompleted( + $auditLogger->logCrossEnvironmentPromotionExecutionCompleted( operationRun: $updated, - sourceTenantId: is_numeric($context['source_tenant_id'] ?? null) ? (int) $context['source_tenant_id'] : null, - targetTenant: $tenant, + sourceEnvironmentId: is_numeric($context['source_environment_id'] ?? null) ? (int) $context['source_environment_id'] : null, + targetEnvironment: $targetEnvironment, summaryCounts: $summary, restoreRun: $restoreRun, ); @@ -183,7 +183,7 @@ public function getOperationRun(): ?OperationRun * @param list> $items * @return array{0: ?BackupSet, 1: list, 2: array, 3: list} */ - private function buildRestoreInputs(ManagedEnvironment $tenant, OperationRun $operationRun, array $items): array + private function buildRestoreInputs(ManagedEnvironment $targetEnvironment, OperationRun $operationRun, array $items): array { $summary = [ 'processed' => 0, @@ -195,14 +195,14 @@ private function buildRestoreInputs(ManagedEnvironment $tenant, OperationRun $op ]; $failures = []; $backupSet = BackupSet::query()->create([ - 'managed_environment_id' => (int) $tenant->getKey(), - 'name' => 'Cross-tenant promotion • Operation #'.$operationRun->getKey(), + 'managed_environment_id' => (int) $targetEnvironment->getKey(), + 'name' => 'Cross-environment promotion • Operation #'.$operationRun->getKey(), 'created_by' => $operationRun->user?->email, 'status' => 'completed', 'item_count' => 0, 'completed_at' => CarbonImmutable::now(), 'metadata' => [ - 'source' => 'cross_tenant_promotion', + 'source' => 'cross_environment_promotion', 'operation_run_id' => (int) $operationRun->getKey(), ], ]); @@ -219,13 +219,13 @@ private function buildRestoreInputs(ManagedEnvironment $tenant, OperationRun $op } $versionId = data_get($item, 'source.policy_version_id'); - $sourceTenantId = data_get($item, 'source.managed_environment_id'); + $sourceEnvironmentId = data_get($item, 'source.managed_environment_id'); - $version = is_numeric($versionId) && is_numeric($sourceTenantId) + $version = is_numeric($versionId) && is_numeric($sourceEnvironmentId) ? PolicyVersion::query() ->with('policy') ->whereKey((int) $versionId) - ->where('managed_environment_id', (int) $sourceTenantId) + ->where('managed_environment_id', (int) $sourceEnvironmentId) ->first() : null; @@ -248,13 +248,13 @@ private function buildRestoreInputs(ManagedEnvironment $tenant, OperationRun $op : (is_string($sourceExternalId) && trim($sourceExternalId) !== '' ? trim($sourceExternalId) : (string) $sourcePolicy->external_id); $targetPolicy = Policy::query() - ->where('managed_environment_id', (int) $tenant->getKey()) + ->where('managed_environment_id', (int) $targetEnvironment->getKey()) ->where('policy_type', (string) $sourcePolicy->policy_type) ->where('external_id', $policyIdentifier) ->first(); $backupItem = BackupItem::query()->create([ - 'managed_environment_id' => (int) $tenant->getKey(), + 'managed_environment_id' => (int) $targetEnvironment->getKey(), 'backup_set_id' => (int) $backupSet->getKey(), 'policy_id' => $targetPolicy?->getKey(), 'policy_identifier' => $policyIdentifier, @@ -263,10 +263,10 @@ private function buildRestoreInputs(ManagedEnvironment $tenant, OperationRun $op 'captured_at' => $version->captured_at ?? CarbonImmutable::now(), 'payload' => is_array($version->snapshot) ? $version->snapshot : [], 'metadata' => [ - 'source' => 'cross_tenant_promotion', + 'source' => 'cross_environment_promotion', 'display_name' => (string) $sourcePolicy->display_name, 'operation_run_id' => (int) $operationRun->getKey(), - 'source_tenant_id' => (int) $sourcePolicy->managed_environment_id, + 'source_environment_id' => (int) $sourcePolicy->managed_environment_id, 'source_policy_id' => (int) $sourcePolicy->getKey(), 'source_policy_version_id' => (int) $version->getKey(), 'source_subject_key' => (string) ($item['subject_key'] ?? ''), diff --git a/apps/platform/app/Jobs/ProviderConnectionHealthCheckJob.php b/apps/platform/app/Jobs/ProviderConnectionHealthCheckJob.php index c0056a37..3c692f77 100644 --- a/apps/platform/app/Jobs/ProviderConnectionHealthCheckJob.php +++ b/apps/platform/app/Jobs/ProviderConnectionHealthCheckJob.php @@ -10,7 +10,7 @@ use App\Models\User; use App\Services\Audit\WorkspaceAuditLogger; use App\Services\Intune\AuditLogger as TenantAuditLogger; -use App\Services\Intune\TenantPermissionService; +use App\Services\Intune\ManagedEnvironmentPermissionService; use App\Services\OperationRunService; use App\Services\Providers\Contracts\HealthResult; use App\Services\Providers\MicrosoftProviderHealthCheck; @@ -24,7 +24,7 @@ use App\Support\Providers\ProviderNextStepsRegistry; use App\Support\Providers\ProviderReasonCodes; use App\Support\Providers\TargetScope\ProviderConnectionTargetScopeNormalizer; -use App\Support\Verification\TenantPermissionCheckClusters; +use App\Support\Verification\ManagedEnvironmentPermissionCheckClusters; use App\Support\Verification\VerificationReportWriter; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -99,7 +99,7 @@ public function handle( $this->updateRunTargetScope($this->operationRun, $connection, $entraTenantName); - $permissionService = app(TenantPermissionService::class); + $permissionService = app(ManagedEnvironmentPermissionService::class); $graphOptions = null; @@ -178,7 +178,7 @@ public function handle( ]; } - $permissionChecks = TenantPermissionCheckClusters::buildChecks($tenant, $permissionRows, $inventory); + $permissionChecks = ManagedEnvironmentPermissionCheckClusters::buildChecks($tenant, $permissionRows, $inventory); $targetScope = app(ProviderConnectionTargetScopeNormalizer::class) ->descriptorForConnection($connection) ->toArray(); diff --git a/apps/platform/app/Models/TenantReview.php b/apps/platform/app/Models/EnvironmentReview.php similarity index 85% rename from apps/platform/app/Models/TenantReview.php rename to apps/platform/app/Models/EnvironmentReview.php index 02be9743..7feb0f61 100644 --- a/apps/platform/app/Models/TenantReview.php +++ b/apps/platform/app/Models/EnvironmentReview.php @@ -6,15 +6,15 @@ use App\Support\Concerns\DerivesWorkspaceIdFromTenant; use App\Support\Governance\Controls\ComplianceEvidenceMappingV1; -use App\Support\TenantReviewCompletenessState; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewCompletenessState; +use App\Support\EnvironmentReviewStatus; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -class TenantReview extends Model +class EnvironmentReview extends Model { use DerivesWorkspaceIdFromTenant; use HasFactory; @@ -107,11 +107,11 @@ public function supersededReviews(): HasMany } /** - * @return HasMany + * @return HasMany */ public function sections(): HasMany { - return $this->hasMany(TenantReviewSection::class)->orderBy('sort_order')->orderBy('id'); + return $this->hasMany(EnvironmentReviewSection::class)->orderBy('sort_order')->orderBy('id'); } /** @@ -146,7 +146,7 @@ public function scopeForWorkspace(Builder $query, int $workspaceId): Builder */ public function scopePublished(Builder $query): Builder { - return $query->where('status', TenantReviewStatus::Published->value); + return $query->where('status', EnvironmentReviewStatus::Published->value); } /** @@ -156,21 +156,21 @@ public function scopePublished(Builder $query): Builder public function scopeMutable(Builder $query): Builder { return $query->whereIn('status', [ - TenantReviewStatus::Draft->value, - TenantReviewStatus::Ready->value, - TenantReviewStatus::Failed->value, + EnvironmentReviewStatus::Draft->value, + EnvironmentReviewStatus::Ready->value, + EnvironmentReviewStatus::Failed->value, ]); } - public function statusEnum(): TenantReviewStatus + public function statusEnum(): EnvironmentReviewStatus { - return TenantReviewStatus::from((string) $this->status); + return EnvironmentReviewStatus::from((string) $this->status); } - public function completenessEnum(): TenantReviewCompletenessState + public function completenessEnum(): EnvironmentReviewCompletenessState { - return TenantReviewCompletenessState::tryFrom((string) $this->completeness_state) - ?? TenantReviewCompletenessState::Missing; + return EnvironmentReviewCompletenessState::tryFrom((string) $this->completeness_state) + ?? EnvironmentReviewCompletenessState::Missing; } public function isPublished(): bool @@ -253,12 +253,12 @@ public function controlInterpretationLimitationCounts(): array ->all(); } - public function controlInterpretationSection(): ?TenantReviewSection + public function controlInterpretationSection(): ?EnvironmentReviewSection { if ($this->relationLoaded('sections')) { $section = $this->sections->firstWhere('section_key', ComplianceEvidenceMappingV1::SECTION_KEY); - return $section instanceof TenantReviewSection ? $section : null; + return $section instanceof EnvironmentReviewSection ? $section : null; } return $this->sections() diff --git a/apps/platform/app/Models/TenantReviewSection.php b/apps/platform/app/Models/EnvironmentReviewSection.php similarity index 79% rename from apps/platform/app/Models/TenantReviewSection.php rename to apps/platform/app/Models/EnvironmentReviewSection.php index b5704e43..6529004e 100644 --- a/apps/platform/app/Models/TenantReviewSection.php +++ b/apps/platform/app/Models/EnvironmentReviewSection.php @@ -4,14 +4,14 @@ namespace App\Models; -use App\Support\TenantReviewCompletenessState; +use App\Support\EnvironmentReviewCompletenessState; use App\Support\Governance\Controls\ComplianceEvidenceMappingV1; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -class TenantReviewSection extends Model +class EnvironmentReviewSection extends Model { use HasFactory; @@ -31,11 +31,11 @@ protected function casts(): array } /** - * @return BelongsTo + * @return BelongsTo */ - public function tenantReview(): BelongsTo + public function environmentReview(): BelongsTo { - return $this->belongsTo(TenantReview::class); + return $this->belongsTo(EnvironmentReview::class); } /** @@ -63,10 +63,10 @@ public function scopeRequired(Builder $query): Builder return $query->where('required', true); } - public function completenessEnum(): TenantReviewCompletenessState + public function completenessEnum(): EnvironmentReviewCompletenessState { - return TenantReviewCompletenessState::tryFrom((string) $this->completeness_state) - ?? TenantReviewCompletenessState::Missing; + return EnvironmentReviewCompletenessState::tryFrom((string) $this->completeness_state) + ?? EnvironmentReviewCompletenessState::Missing; } public function isControlInterpretation(): bool diff --git a/apps/platform/app/Models/EvidenceSnapshot.php b/apps/platform/app/Models/EvidenceSnapshot.php index fe0d9f93..c171e67d 100644 --- a/apps/platform/app/Models/EvidenceSnapshot.php +++ b/apps/platform/app/Models/EvidenceSnapshot.php @@ -81,11 +81,11 @@ public function reviewPacks(): HasMany } /** - * @return HasMany + * @return HasMany */ - public function tenantReviews(): HasMany + public function environmentReviews(): HasMany { - return $this->hasMany(TenantReview::class); + return $this->hasMany(EnvironmentReview::class); } /** diff --git a/apps/platform/app/Models/ManagedEnvironment.php b/apps/platform/app/Models/ManagedEnvironment.php index c4d83ec3..dd4d3454 100644 --- a/apps/platform/app/Models/ManagedEnvironment.php +++ b/apps/platform/app/Models/ManagedEnvironment.php @@ -411,9 +411,9 @@ public function evidenceSnapshots(): HasMany return $this->hasMany(EvidenceSnapshot::class); } - public function tenantReviews(): HasMany + public function environmentReviews(): HasMany { - return $this->hasMany(TenantReview::class); + return $this->hasMany(EnvironmentReview::class); } public function settings(): HasMany @@ -423,7 +423,7 @@ public function settings(): HasMany public function permissions(): HasMany { - return $this->hasMany(TenantPermission::class); + return $this->hasMany(ManagedEnvironmentPermission::class); } public function providerConnections(): HasMany diff --git a/apps/platform/app/Models/TenantOnboardingSession.php b/apps/platform/app/Models/ManagedEnvironmentOnboardingSession.php similarity index 93% rename from apps/platform/app/Models/TenantOnboardingSession.php rename to apps/platform/app/Models/ManagedEnvironmentOnboardingSession.php index a7c5259d..745f02cd 100644 --- a/apps/platform/app/Models/TenantOnboardingSession.php +++ b/apps/platform/app/Models/ManagedEnvironmentOnboardingSession.php @@ -12,12 +12,12 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -class TenantOnboardingSession extends Model +class ManagedEnvironmentOnboardingSession extends Model { - /** @use HasFactory<\Database\Factories\TenantOnboardingSessionFactory> */ + /** @use HasFactory<\Database\Factories\ManagedEnvironmentOnboardingSessionFactory> */ use HasFactory; - protected $table = 'managed_tenant_onboarding_sessions'; + protected $table = 'managed_environment_onboarding_sessions'; /** * @var array @@ -25,7 +25,7 @@ class TenantOnboardingSession extends Model public const STATE_ALLOWED_KEYS = [ 'entra_tenant_id', 'managed_environment_id', - 'tenant_name', + 'environment_name', 'environment', 'primary_domain', 'notes', @@ -80,11 +80,19 @@ public function workspace(): BelongsTo /** * @return BelongsTo */ - public function tenant(): BelongsTo + public function managedEnvironment(): BelongsTo { return $this->belongsTo(ManagedEnvironment::class, 'managed_environment_id')->withTrashed(); } + /** + * @return BelongsTo + */ + public function tenant(): BelongsTo + { + return $this->managedEnvironment(); + } + /** * @return BelongsTo */ diff --git a/apps/platform/app/Models/TenantPermission.php b/apps/platform/app/Models/ManagedEnvironmentPermission.php similarity index 92% rename from apps/platform/app/Models/TenantPermission.php rename to apps/platform/app/Models/ManagedEnvironmentPermission.php index 5c1f0238..73c1e80f 100644 --- a/apps/platform/app/Models/TenantPermission.php +++ b/apps/platform/app/Models/ManagedEnvironmentPermission.php @@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -class TenantPermission extends Model +class ManagedEnvironmentPermission extends Model { use DerivesWorkspaceIdFromTenant; use HasFactory; diff --git a/apps/platform/app/Models/TenantTriageReview.php b/apps/platform/app/Models/ManagedEnvironmentTriageReview.php similarity index 98% rename from apps/platform/app/Models/TenantTriageReview.php rename to apps/platform/app/Models/ManagedEnvironmentTriageReview.php index 5321d237..1eeaa063 100644 --- a/apps/platform/app/Models/TenantTriageReview.php +++ b/apps/platform/app/Models/ManagedEnvironmentTriageReview.php @@ -10,7 +10,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -class TenantTriageReview extends Model +class ManagedEnvironmentTriageReview extends Model { use HasFactory; diff --git a/apps/platform/app/Models/ReviewPack.php b/apps/platform/app/Models/ReviewPack.php index 3a573d7e..a5dadc68 100644 --- a/apps/platform/app/Models/ReviewPack.php +++ b/apps/platform/app/Models/ReviewPack.php @@ -80,11 +80,11 @@ public function evidenceSnapshot(): BelongsTo } /** - * @return BelongsTo + * @return BelongsTo */ - public function tenantReview(): BelongsTo + public function environmentReview(): BelongsTo { - return $this->belongsTo(TenantReview::class); + return $this->belongsTo(EnvironmentReview::class); } /** diff --git a/apps/platform/app/Policies/TenantReviewPolicy.php b/apps/platform/app/Policies/EnvironmentReviewPolicy.php similarity index 70% rename from apps/platform/app/Policies/TenantReviewPolicy.php rename to apps/platform/app/Policies/EnvironmentReviewPolicy.php index 8211615d..bd6893e6 100644 --- a/apps/platform/app/Policies/TenantReviewPolicy.php +++ b/apps/platform/app/Policies/EnvironmentReviewPolicy.php @@ -5,14 +5,14 @@ namespace App\Policies; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Services\Auth\CapabilityResolver; use App\Support\Auth\Capabilities; use Illuminate\Auth\Access\HandlesAuthorization; use Illuminate\Auth\Access\Response; -class TenantReviewPolicy +class EnvironmentReviewPolicy { use HandlesAuthorization; @@ -24,10 +24,10 @@ public function viewAny(User $user): bool return false; } - return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::TENANT_REVIEW_VIEW); + return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_VIEW); } - public function view(User $user, TenantReview $review): Response|bool + public function view(User $user, EnvironmentReview $review): Response|bool { $tenant = $this->authorizedTenantOrNull($user, $review); @@ -35,7 +35,7 @@ public function view(User $user, TenantReview $review): Response|bool return Response::denyAsNotFound(); } - return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::TENANT_REVIEW_VIEW) + return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_VIEW) ? true : Response::deny(); } @@ -48,35 +48,35 @@ public function create(User $user): bool return false; } - return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::TENANT_REVIEW_MANAGE); + return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_MANAGE); } - public function refresh(User $user, TenantReview $review): Response|bool + public function refresh(User $user, EnvironmentReview $review): Response|bool { return $this->authorizeManageAction($user, $review); } - public function publish(User $user, TenantReview $review): Response|bool + public function publish(User $user, EnvironmentReview $review): Response|bool { return $this->authorizeManageAction($user, $review); } - public function archive(User $user, TenantReview $review): Response|bool + public function archive(User $user, EnvironmentReview $review): Response|bool { return $this->authorizeManageAction($user, $review); } - public function export(User $user, TenantReview $review): Response|bool + public function export(User $user, EnvironmentReview $review): Response|bool { return $this->authorizeManageAction($user, $review); } - public function createNextReview(User $user, TenantReview $review): Response|bool + public function createNextReview(User $user, EnvironmentReview $review): Response|bool { return $this->authorizeManageAction($user, $review); } - private function authorizeManageAction(User $user, TenantReview $review): Response|bool + private function authorizeManageAction(User $user, EnvironmentReview $review): Response|bool { $tenant = $this->authorizedTenantOrNull($user, $review); @@ -84,12 +84,12 @@ private function authorizeManageAction(User $user, TenantReview $review): Respon return Response::denyAsNotFound(); } - return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::TENANT_REVIEW_MANAGE) + return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_MANAGE) ? true : Response::deny(); } - private function authorizedTenantOrNull(User $user, TenantReview $review): ?ManagedEnvironment + private function authorizedTenantOrNull(User $user, EnvironmentReview $review): ?ManagedEnvironment { $tenant = $review->tenant; diff --git a/apps/platform/app/Policies/TenantOnboardingSessionPolicy.php b/apps/platform/app/Policies/ManagedEnvironmentOnboardingSessionPolicy.php similarity index 73% rename from apps/platform/app/Policies/TenantOnboardingSessionPolicy.php rename to apps/platform/app/Policies/ManagedEnvironmentOnboardingSessionPolicy.php index 5b01e9fc..a630756b 100644 --- a/apps/platform/app/Policies/TenantOnboardingSessionPolicy.php +++ b/apps/platform/app/Policies/ManagedEnvironmentOnboardingSessionPolicy.php @@ -5,7 +5,7 @@ namespace App\Policies; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\Workspace; use App\Services\Auth\WorkspaceCapabilityResolver; @@ -17,7 +17,7 @@ use Illuminate\Auth\Access\Response; use Illuminate\Support\Facades\Gate; -class TenantOnboardingSessionPolicy +class ManagedEnvironmentOnboardingSessionPolicy { public function viewAny(User $user): bool|Response { @@ -27,33 +27,33 @@ public function viewAny(User $user): bool|Response return Response::denyAsNotFound(); } - return $this->authorizeForWorkspace($user, $workspace, Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD); + return $this->authorizeForWorkspace($user, $workspace, Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD); } - public function view(User $user, TenantOnboardingSession $tenantOnboardingSession): bool|Response + public function view(User $user, ManagedEnvironmentOnboardingSession $environmentOnboardingSession): bool|Response { return $this->authorizeForDraft( user: $user, - tenantOnboardingSession: $tenantOnboardingSession, - capability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, + environmentOnboardingSession: $environmentOnboardingSession, + capability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD, ); } - public function update(User $user, TenantOnboardingSession $tenantOnboardingSession): bool|Response + public function update(User $user, ManagedEnvironmentOnboardingSession $environmentOnboardingSession): bool|Response { return $this->authorizeForDraft( user: $user, - tenantOnboardingSession: $tenantOnboardingSession, - capability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, + environmentOnboardingSession: $environmentOnboardingSession, + capability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD, ); } - public function cancel(User $user, TenantOnboardingSession $tenantOnboardingSession): bool|Response + public function cancel(User $user, ManagedEnvironmentOnboardingSession $environmentOnboardingSession): bool|Response { return $this->authorizeForDraft( user: $user, - tenantOnboardingSession: $tenantOnboardingSession, - capability: Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL, + environmentOnboardingSession: $environmentOnboardingSession, + capability: Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL, ); } @@ -83,7 +83,7 @@ private function currentWorkspace(User $user): ?Workspace private function authorizeForDraft( User $user, - TenantOnboardingSession $tenantOnboardingSession, + ManagedEnvironmentOnboardingSession $environmentOnboardingSession, string $capability, ): bool|Response { $workspace = $this->currentWorkspace($user); @@ -92,11 +92,11 @@ private function authorizeForDraft( return Response::denyAsNotFound(); } - if ((int) $tenantOnboardingSession->workspace_id !== (int) $workspace->getKey()) { + if ((int) $environmentOnboardingSession->workspace_id !== (int) $workspace->getKey()) { return Response::denyAsNotFound(); } - $tenant = $tenantOnboardingSession->tenant; + $tenant = $environmentOnboardingSession->managedEnvironment; if ($tenant instanceof ManagedEnvironment) { if ((int) $tenant->workspace_id !== (int) $workspace->getKey()) { @@ -140,7 +140,7 @@ private function authorizeForWorkspace(User $user, Workspace $workspace, string private function forbiddenCapabilityMessage(string $capability): string { return match ($capability) { - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL => 'You do not have permission to cancel this onboarding draft.', + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL => 'You do not have permission to cancel this onboarding draft.', default => 'You do not have permission to continue this onboarding draft.', }; } diff --git a/apps/platform/app/Providers/AuthServiceProvider.php b/apps/platform/app/Providers/AuthServiceProvider.php index 272b151c..e1fa0ba9 100644 --- a/apps/platform/app/Providers/AuthServiceProvider.php +++ b/apps/platform/app/Providers/AuthServiceProvider.php @@ -8,8 +8,8 @@ use App\Models\PlatformUser; use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; -use App\Models\TenantReview; +use App\Models\ManagedEnvironmentOnboardingSession; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; use App\Models\WorkspaceSetting; @@ -17,8 +17,8 @@ use App\Policies\AlertDestinationPolicy; use App\Policies\AlertRulePolicy; use App\Policies\ProviderConnectionPolicy; -use App\Policies\TenantOnboardingSessionPolicy; -use App\Policies\TenantReviewPolicy; +use App\Policies\ManagedEnvironmentOnboardingSessionPolicy; +use App\Policies\EnvironmentReviewPolicy; use App\Policies\WorkspaceSettingPolicy; use App\Services\Auth\CapabilityResolver; use App\Services\Auth\WorkspaceCapabilityResolver; @@ -31,8 +31,8 @@ class AuthServiceProvider extends ServiceProvider { protected $policies = [ ProviderConnection::class => ProviderConnectionPolicy::class, - TenantOnboardingSession::class => TenantOnboardingSessionPolicy::class, - TenantReview::class => TenantReviewPolicy::class, + ManagedEnvironmentOnboardingSession::class => ManagedEnvironmentOnboardingSessionPolicy::class, + EnvironmentReview::class => EnvironmentReviewPolicy::class, WorkspaceSetting::class => WorkspaceSettingPolicy::class, AlertDestination::class => AlertDestinationPolicy::class, AlertDelivery::class => AlertDeliveryPolicy::class, diff --git a/apps/platform/app/Providers/Filament/AdminPanelProvider.php b/apps/platform/app/Providers/Filament/AdminPanelProvider.php index 1c5ffce5..60b491f7 100644 --- a/apps/platform/app/Providers/Filament/AdminPanelProvider.php +++ b/apps/platform/app/Providers/Filament/AdminPanelProvider.php @@ -4,9 +4,9 @@ use App\Filament\Pages\Auth\Login; use App\Filament\Pages\BaselineCompareLanding; -use App\Filament\Pages\ChooseTenant; +use App\Filament\Pages\ChooseEnvironment; use App\Filament\Pages\ChooseWorkspace; -use App\Filament\Pages\CrossTenantComparePage; +use App\Filament\Pages\CrossEnvironmentComparePage; use App\Filament\Pages\Findings\FindingsHygieneReport; use App\Filament\Pages\Findings\FindingsIntakeQueue; use App\Filament\Pages\Governance\DecisionRegister; @@ -18,7 +18,7 @@ use App\Filament\Pages\Reviews\ReviewRegister; use App\Filament\Pages\Reviews\CustomerReviewWorkspace; use App\Filament\Pages\Settings\WorkspaceSettings; -use App\Filament\Pages\TenantRequiredPermissions; +use App\Filament\Pages\EnvironmentRequiredPermissions; use App\Filament\Pages\WorkspaceOverview; use App\Filament\Resources\AlertDeliveryResource; use App\Filament\Resources\AlertDestinationResource; @@ -28,7 +28,7 @@ use App\Filament\Resources\InventoryItemResource; use App\Filament\Resources\PolicyResource; use App\Filament\Resources\ProviderConnectionResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Filament\Resources\Workspaces\WorkspaceResource; use App\Models\User; use App\Models\Workspace; @@ -75,7 +75,7 @@ public function panel(Panel $panel): Panel ->font(null, provider: LocalFontProvider::class, preload: []) ->authenticatedRoutes(function (Panel $panel): void { ChooseWorkspace::registerRoutes($panel); - ChooseTenant::registerRoutes($panel); + ChooseEnvironment::registerRoutes($panel); NoAccess::registerRoutes($panel); }) ->colors([ @@ -166,7 +166,7 @@ public function panel(Panel $panel): Panel ) ->renderHook( PanelsRenderHook::PAGE_START, - fn (): string => request()->routeIs('admin.workspace.managed-tenants.index', 'admin.onboarding', 'admin.onboarding.draft', 'filament.admin.pages.choose-tenant') + fn (): string => request()->routeIs('admin.workspace.managed-environments.index', 'admin.onboarding', 'admin.onboarding.draft', 'filament.admin.pages.choose-environment') ? '' : ((bool) config('tenantpilot.bulk_operations.progress_widget_enabled', true) ? view('livewire.bulk-operation-progress-wrapper')->render() @@ -182,16 +182,16 @@ public function panel(Panel $panel): Panel WorkspaceResource::class, BaselineProfileResource::class, BaselineSnapshotResource::class, - TenantReviewResource::class, + EnvironmentReviewResource::class, ]) ->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\\Filament\\Clusters') ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->pages([ BaselineCompareLanding::class, InventoryCoverage::class, - TenantRequiredPermissions::class, + EnvironmentRequiredPermissions::class, WorkspaceSettings::class, - CrossTenantComparePage::class, + CrossEnvironmentComparePage::class, GovernanceInbox::class, DecisionRegister::class, FindingsHygieneReport::class, diff --git a/apps/platform/app/Services/Audit/WorkspaceAuditLogger.php b/apps/platform/app/Services/Audit/WorkspaceAuditLogger.php index 2d58c9d9..10b33996 100644 --- a/apps/platform/app/Services/Audit/WorkspaceAuditLogger.php +++ b/apps/platform/app/Services/Audit/WorkspaceAuditLogger.php @@ -143,10 +143,10 @@ public function logSupportDiagnosticsOpened( /** * @param array $preflight */ - public function logCrossTenantPromotionPreflightGenerated( + public function logCrossEnvironmentPromotionPreflightGenerated( Workspace $workspace, - ManagedEnvironment $sourceTenant, - ManagedEnvironment $targetTenant, + ManagedEnvironment $sourceEnvironment, + ManagedEnvironment $targetEnvironment, array $preflight, User|PlatformUser|null $actor = null, ): \App\Models\AuditLog { @@ -154,12 +154,12 @@ public function logCrossTenantPromotionPreflightGenerated( return $this->log( workspace: $workspace, - action: AuditActionId::CrossTenantPromotionPreflightGenerated, + action: AuditActionId::CrossEnvironmentPromotionPreflightGenerated, context: [ - 'source_tenant_id' => (int) $sourceTenant->getKey(), - 'source_tenant_name' => (string) $sourceTenant->name, - 'target_tenant_id' => (int) $targetTenant->getKey(), - 'target_tenant_name' => (string) $targetTenant->name, + 'source_environment_id' => (int) $sourceEnvironment->getKey(), + 'source_environment_name' => (string) $sourceEnvironment->name, + 'target_environment_id' => (int) $targetEnvironment->getKey(), + 'target_environment_name' => (string) $targetEnvironment->name, 'ready_count' => (int) ($summary['ready'] ?? 0), 'blocked_count' => (int) ($summary['blocked'] ?? 0), 'manual_mapping_required_count' => (int) ($summary['manual_mapping_required'] ?? 0), @@ -170,20 +170,20 @@ public function logCrossTenantPromotionPreflightGenerated( ], actor: $actor, status: 'success', - resourceType: 'cross_tenant_promotion_preflight', - resourceId: sprintf('%s:%s', $sourceTenant->getKey(), $targetTenant->getKey()), - targetLabel: $sourceTenant->name.' -> '.$targetTenant->name, - summary: 'Cross-tenant promotion preflight generated for '.$sourceTenant->name.' -> '.$targetTenant->name, + resourceType: 'cross_environment_promotion_preflight', + resourceId: sprintf('%s:%s', $sourceEnvironment->getKey(), $targetEnvironment->getKey()), + targetLabel: $sourceEnvironment->name.' -> '.$targetEnvironment->name, + summary: 'Cross-environment promotion preflight generated for '.$sourceEnvironment->name.' -> '.$targetEnvironment->name, ); } /** * @param array $plan */ - public function logCrossTenantPromotionExecutionQueued( + public function logCrossEnvironmentPromotionExecutionQueued( Workspace $workspace, - ManagedEnvironment $sourceTenant, - ManagedEnvironment $targetTenant, + ManagedEnvironment $sourceEnvironment, + ManagedEnvironment $targetEnvironment, OperationRun $operationRun, array $plan, User|PlatformUser|null $actor = null, @@ -192,12 +192,12 @@ public function logCrossTenantPromotionExecutionQueued( return $this->log( workspace: $workspace, - action: AuditActionId::CrossTenantPromotionExecutionQueued, + action: AuditActionId::CrossEnvironmentPromotionExecutionQueued, context: [ - 'source_tenant_id' => (int) $sourceTenant->getKey(), - 'source_tenant_name' => (string) $sourceTenant->name, - 'target_tenant_id' => (int) $targetTenant->getKey(), - 'target_tenant_name' => (string) $targetTenant->name, + 'source_environment_id' => (int) $sourceEnvironment->getKey(), + 'source_environment_name' => (string) $sourceEnvironment->name, + 'target_environment_id' => (int) $targetEnvironment->getKey(), + 'target_environment_name' => (string) $targetEnvironment->name, 'selection' => is_array($plan['selection'] ?? null) ? $plan['selection'] : [], 'ready_count' => (int) ($summary['ready'] ?? 0), 'excluded_count' => (int) ($summary['excluded'] ?? 0), @@ -208,36 +208,36 @@ public function logCrossTenantPromotionExecutionQueued( status: 'queued', resourceType: 'operation_run', resourceId: (string) $operationRun->getKey(), - targetLabel: $sourceTenant->name.' -> '.$targetTenant->name, - summary: 'Cross-tenant promotion execution queued for '.$sourceTenant->name.' -> '.$targetTenant->name, + targetLabel: $sourceEnvironment->name.' -> '.$targetEnvironment->name, + summary: 'Cross-environment promotion execution queued for '.$sourceEnvironment->name.' -> '.$targetEnvironment->name, operationRunId: (int) $operationRun->getKey(), - tenant: $targetTenant, + tenant: $targetEnvironment, ); } /** * @param array $summaryCounts */ - public function logCrossTenantPromotionExecutionCompleted( + public function logCrossEnvironmentPromotionExecutionCompleted( OperationRun $operationRun, - ?int $sourceTenantId, - ManagedEnvironment $targetTenant, + ?int $sourceEnvironmentId, + ManagedEnvironment $targetEnvironment, array $summaryCounts, ?RestoreRun $restoreRun = null, ): \App\Models\AuditLog { $context = is_array($operationRun->context) ? $operationRun->context : []; - $sourceTenantName = is_string($context['source_tenant_name'] ?? null) - ? (string) $context['source_tenant_name'] + $sourceEnvironmentName = is_string($context['source_environment_name'] ?? null) + ? (string) $context['source_environment_name'] : null; return $this->log( - workspace: $targetTenant->workspace, - action: AuditActionId::CrossTenantPromotionExecutionCompleted, + workspace: $targetEnvironment->workspace, + action: AuditActionId::CrossEnvironmentPromotionExecutionCompleted, context: [ - 'source_tenant_id' => $sourceTenantId, - 'source_tenant_name' => $sourceTenantName, - 'target_tenant_id' => (int) $targetTenant->getKey(), - 'target_tenant_name' => (string) $targetTenant->name, + 'source_environment_id' => $sourceEnvironmentId, + 'source_environment_name' => $sourceEnvironmentName, + 'target_environment_id' => (int) $targetEnvironment->getKey(), + 'target_environment_name' => (string) $targetEnvironment->name, 'summary_counts' => $summaryCounts, 'restore_run_id' => $restoreRun?->getKey(), 'operation_outcome' => (string) $operationRun->outcome, @@ -249,10 +249,10 @@ public function logCrossTenantPromotionExecutionCompleted( }, resourceType: 'operation_run', resourceId: (string) $operationRun->getKey(), - targetLabel: ($sourceTenantName !== null ? $sourceTenantName.' -> ' : '').$targetTenant->name, - summary: 'Cross-tenant promotion execution completed for '.(($sourceTenantName !== null ? $sourceTenantName.' -> ' : '')).$targetTenant->name, + targetLabel: ($sourceEnvironmentName !== null ? $sourceEnvironmentName.' -> ' : '').$targetEnvironment->name, + summary: 'Cross-environment promotion execution completed for '.(($sourceEnvironmentName !== null ? $sourceEnvironmentName.' -> ' : '')).$targetEnvironment->name, operationRunId: (int) $operationRun->getKey(), - tenant: $targetTenant, + tenant: $targetEnvironment, ); } diff --git a/apps/platform/app/Services/Auth/TenantDiagnosticsService.php b/apps/platform/app/Services/Auth/ManagedEnvironmentDiagnosticsService.php similarity index 98% rename from apps/platform/app/Services/Auth/TenantDiagnosticsService.php rename to apps/platform/app/Services/Auth/ManagedEnvironmentDiagnosticsService.php index 1343b2c0..8cc18cd9 100644 --- a/apps/platform/app/Services/Auth/TenantDiagnosticsService.php +++ b/apps/platform/app/Services/Auth/ManagedEnvironmentDiagnosticsService.php @@ -11,7 +11,7 @@ use App\Support\Audit\AuditActionId; use Illuminate\Support\Facades\DB; -class TenantDiagnosticsService +class ManagedEnvironmentDiagnosticsService { public function __construct(public AuditLogger $auditLogger) {} diff --git a/apps/platform/app/Services/Auth/TenantMembershipManager.php b/apps/platform/app/Services/Auth/ManagedEnvironmentMembershipManager.php similarity index 99% rename from apps/platform/app/Services/Auth/TenantMembershipManager.php rename to apps/platform/app/Services/Auth/ManagedEnvironmentMembershipManager.php index 0043cb77..b540e3b4 100644 --- a/apps/platform/app/Services/Auth/TenantMembershipManager.php +++ b/apps/platform/app/Services/Auth/ManagedEnvironmentMembershipManager.php @@ -13,7 +13,7 @@ use DomainException; use Illuminate\Support\Facades\DB; -class TenantMembershipManager +class ManagedEnvironmentMembershipManager { private const string SCOPE_PLACEHOLDER_ROLE = 'readonly'; diff --git a/apps/platform/app/Services/Auth/RoleCapabilityMap.php b/apps/platform/app/Services/Auth/RoleCapabilityMap.php index b48e8925..7019297e 100644 --- a/apps/platform/app/Services/Auth/RoleCapabilityMap.php +++ b/apps/platform/app/Services/Auth/RoleCapabilityMap.php @@ -55,9 +55,9 @@ class RoleCapabilityMap Capabilities::REVIEW_PACK_VIEW, Capabilities::REVIEW_PACK_MANAGE, - Capabilities::TENANT_REVIEW_VIEW, - Capabilities::TENANT_REVIEW_MANAGE, - Capabilities::TENANT_TRIAGE_REVIEW_MANAGE, + Capabilities::ENVIRONMENT_REVIEW_VIEW, + Capabilities::ENVIRONMENT_REVIEW_MANAGE, + Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE, Capabilities::EVIDENCE_VIEW, Capabilities::EVIDENCE_MANAGE, ], @@ -99,9 +99,9 @@ class RoleCapabilityMap Capabilities::REVIEW_PACK_VIEW, Capabilities::REVIEW_PACK_MANAGE, - Capabilities::TENANT_REVIEW_VIEW, - Capabilities::TENANT_REVIEW_MANAGE, - Capabilities::TENANT_TRIAGE_REVIEW_MANAGE, + Capabilities::ENVIRONMENT_REVIEW_VIEW, + Capabilities::ENVIRONMENT_REVIEW_MANAGE, + Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE, Capabilities::EVIDENCE_VIEW, Capabilities::EVIDENCE_MANAGE, ], @@ -131,8 +131,8 @@ class RoleCapabilityMap Capabilities::PERMISSION_POSTURE_VIEW, Capabilities::REVIEW_PACK_VIEW, - Capabilities::TENANT_REVIEW_VIEW, - Capabilities::TENANT_TRIAGE_REVIEW_MANAGE, + Capabilities::ENVIRONMENT_REVIEW_VIEW, + Capabilities::MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE, Capabilities::EVIDENCE_VIEW, ], @@ -153,7 +153,7 @@ class RoleCapabilityMap Capabilities::PERMISSION_POSTURE_VIEW, Capabilities::REVIEW_PACK_VIEW, - Capabilities::TENANT_REVIEW_VIEW, + Capabilities::ENVIRONMENT_REVIEW_VIEW, Capabilities::EVIDENCE_VIEW, ], ]; diff --git a/apps/platform/app/Services/Auth/WorkspaceRoleCapabilityMap.php b/apps/platform/app/Services/Auth/WorkspaceRoleCapabilityMap.php index 99f0acba..8735bdd2 100644 --- a/apps/platform/app/Services/Auth/WorkspaceRoleCapabilityMap.php +++ b/apps/platform/app/Services/Auth/WorkspaceRoleCapabilityMap.php @@ -23,17 +23,17 @@ class WorkspaceRoleCapabilityMap Capabilities::WORKSPACE_ARCHIVE, Capabilities::WORKSPACE_MEMBERSHIP_VIEW, Capabilities::WORKSPACE_MEMBERSHIP_MANAGE, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_IDENTIFY, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_POLICY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_IDENTIFY, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_POLICY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE, Capabilities::WORKSPACE_SETTINGS_VIEW, Capabilities::WORKSPACE_SETTINGS_MANAGE, Capabilities::ALERTS_VIEW, @@ -48,15 +48,15 @@ class WorkspaceRoleCapabilityMap Capabilities::WORKSPACE_VIEW, Capabilities::WORKSPACE_MEMBERSHIP_VIEW, Capabilities::WORKSPACE_MEMBERSHIP_MANAGE, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_IDENTIFY, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_POLICY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_IDENTIFY, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_POLICY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, Capabilities::WORKSPACE_SETTINGS_VIEW, Capabilities::WORKSPACE_SETTINGS_MANAGE, Capabilities::ALERTS_VIEW, @@ -70,11 +70,11 @@ class WorkspaceRoleCapabilityMap WorkspaceRole::Operator->value => [ Capabilities::WORKSPACE_VIEW, Capabilities::WORKSPACE_MEMBERSHIP_VIEW, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_POLICY_SYNC, - Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_POLICY_SYNC, + Capabilities::WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP, Capabilities::WORKSPACE_SETTINGS_VIEW, Capabilities::ALERTS_VIEW, Capabilities::WORKSPACE_BASELINES_VIEW, diff --git a/apps/platform/app/Services/Baselines/BaselineCaptureService.php b/apps/platform/app/Services/Baselines/BaselineCaptureService.php index a0d1cfe9..31bb14e1 100644 --- a/apps/platform/app/Services/Baselines/BaselineCaptureService.php +++ b/apps/platform/app/Services/Baselines/BaselineCaptureService.php @@ -91,7 +91,7 @@ public function startCapture( ], ], 'baseline_profile_id' => (int) $profile->getKey(), - 'source_tenant_id' => (int) $sourceTenant->getKey(), + 'source_environment_id' => (int) $sourceTenant->getKey(), 'effective_scope' => $effectiveScope->toEffectiveScopeContext($this->capabilityGuard, 'capture'), 'capture_mode' => $captureMode->value, 'baseline_capture' => [ diff --git a/apps/platform/app/Services/Baselines/BaselineEvidenceCaptureResumeService.php b/apps/platform/app/Services/Baselines/BaselineEvidenceCaptureResumeService.php index a3eb45b2..6877f53e 100644 --- a/apps/platform/app/Services/Baselines/BaselineEvidenceCaptureResumeService.php +++ b/apps/platform/app/Services/Baselines/BaselineEvidenceCaptureResumeService.php @@ -94,7 +94,7 @@ public function resume(OperationRun $priorRun, User $initiator): array $newContext = []; - foreach (['target_scope', 'baseline_profile_id', 'baseline_snapshot_id', 'source_tenant_id', 'effective_scope', 'capture_mode'] as $key) { + foreach (['target_scope', 'baseline_profile_id', 'baseline_snapshot_id', 'source_environment_id', 'effective_scope', 'capture_mode'] as $key) { if (array_key_exists($key, $context)) { $newContext[$key] = $context[$key]; } diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewComposer.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.php similarity index 95% rename from apps/platform/app/Services/TenantReviews/TenantReviewComposer.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.php index 22bffc57..79d680f9 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewComposer.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; use App\Models\EvidenceSnapshot; -use App\Models\TenantReview; -use App\Support\TenantReviewStatus; +use App\Models\EnvironmentReview; +use App\Support\EnvironmentReviewStatus; -final class TenantReviewComposer +final class EnvironmentReviewComposer { public function __construct( - private readonly TenantReviewFingerprint $fingerprint, - private readonly TenantReviewSectionFactory $sectionFactory, - private readonly TenantReviewReadinessGate $readinessGate, + private readonly EnvironmentReviewFingerprint $fingerprint, + private readonly EnvironmentReviewSectionFactory $sectionFactory, + private readonly EnvironmentReviewReadinessGate $readinessGate, ) {} /** @@ -25,7 +25,7 @@ public function __construct( * sections: list> * } */ - public function compose(EvidenceSnapshot $snapshot, ?TenantReview $review = null): array + public function compose(EvidenceSnapshot $snapshot, ?EnvironmentReview $review = null): array { $tenant = $snapshot->tenant; @@ -49,8 +49,8 @@ public function compose(EvidenceSnapshot $snapshot, ?TenantReview $review = null $operationsSection = collect($sections) ->firstWhere('section_key', 'operations_health'); - if ($review instanceof TenantReview && $review->isPublished()) { - $status = TenantReviewStatus::Published; + if ($review instanceof EnvironmentReview && $review->isPublished()) { + $status = EnvironmentReviewStatus::Published; } return [ diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewFingerprint.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewFingerprint.php similarity index 94% rename from apps/platform/app/Services/TenantReviews/TenantReviewFingerprint.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewFingerprint.php index d3e43e4e..83bcb066 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewFingerprint.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewFingerprint.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; use App\Models\EvidenceSnapshot; use App\Models\ManagedEnvironment; use Illuminate\Support\Arr; -final class TenantReviewFingerprint +final class EnvironmentReviewFingerprint { public function forSnapshot(ManagedEnvironment $tenant, EvidenceSnapshot $snapshot): string { diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewLifecycleService.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.php similarity index 78% rename from apps/platform/app/Services/TenantReviews/TenantReviewLifecycleService.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.php index 14f8663f..f7ca3e42 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewLifecycleService.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.php @@ -2,31 +2,31 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; use App\Models\EvidenceSnapshot; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Services\Audit\WorkspaceAuditLogger; use App\Support\Audit\AuditActionId; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewStatus; use App\Support\Ui\DerivedState\DerivedStateFamily; use App\Support\Ui\DerivedState\RequestScopedDerivedStateStore; use Illuminate\Support\Facades\DB; use InvalidArgumentException; -final class TenantReviewLifecycleService +final class EnvironmentReviewLifecycleService { public function __construct( - private readonly TenantReviewReadinessGate $readinessGate, - private readonly TenantReviewService $reviewService, + private readonly EnvironmentReviewReadinessGate $readinessGate, + private readonly EnvironmentReviewService $reviewService, private readonly WorkspaceAuditLogger $auditLogger, private readonly RequestScopedDerivedStateStore $derivedStateStore, ) {} - public function publish(TenantReview $review, User $user, string $reason): TenantReview + public function publish(EnvironmentReview $review, User $user, string $reason): EnvironmentReview { $review->loadMissing(['tenant', 'sections', 'currentExportReviewPack']); $tenant = $review->tenant; @@ -44,7 +44,7 @@ public function publish(TenantReview $review, User $user, string $reason): Tenan } $review->forceFill([ - 'status' => TenantReviewStatus::Published->value, + 'status' => EnvironmentReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), 'summary' => array_merge(is_array($review->summary) ? $review->summary : [], [ @@ -54,17 +54,17 @@ public function publish(TenantReview $review, User $user, string $reason): Tenan $this->auditLogger->log( workspace: $tenant->workspace, - action: AuditActionId::TenantReviewPublished, + action: AuditActionId::EnvironmentReviewPublished, context: [ 'metadata' => [ 'review_id' => (int) $review->getKey(), 'before_status' => $beforeStatus, - 'after_status' => TenantReviewStatus::Published->value, + 'after_status' => EnvironmentReviewStatus::Published->value, 'reason' => $reason, ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $review->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $review->getKey()), tenant: $tenant, @@ -75,7 +75,7 @@ public function publish(TenantReview $review, User $user, string $reason): Tenan return $review->refresh()->load(['tenant', 'sections', 'currentExportReviewPack']); } - public function archive(TenantReview $review, User $user, string $reason): TenantReview + public function archive(EnvironmentReview $review, User $user, string $reason): EnvironmentReview { $review->loadMissing('tenant'); $tenant = $review->tenant; @@ -92,23 +92,23 @@ public function archive(TenantReview $review, User $user, string $reason): Tenan } $review->forceFill([ - 'status' => TenantReviewStatus::Archived->value, + 'status' => EnvironmentReviewStatus::Archived->value, 'archived_at' => now(), ])->save(); $this->auditLogger->log( workspace: $tenant->workspace, - action: AuditActionId::TenantReviewArchived, + action: AuditActionId::EnvironmentReviewArchived, context: [ 'metadata' => [ 'review_id' => (int) $review->getKey(), 'before_status' => $beforeStatus, - 'after_status' => TenantReviewStatus::Archived->value, + 'after_status' => EnvironmentReviewStatus::Archived->value, 'reason' => $reason, ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $review->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $review->getKey()), tenant: $tenant, @@ -119,7 +119,7 @@ public function archive(TenantReview $review, User $user, string $reason): Tenan return $review->refresh()->load(['tenant', 'sections', 'currentExportReviewPack']); } - public function createNextReview(TenantReview $review, User $user, ?EvidenceSnapshot $snapshot = null): TenantReview + public function createNextReview(EnvironmentReview $review, User $user, ?EvidenceSnapshot $snapshot = null): EnvironmentReview { $review->loadMissing(['tenant', 'evidenceSnapshot']); $tenant = $review->tenant; @@ -138,29 +138,29 @@ public function createNextReview(TenantReview $review, User $user, ?EvidenceSnap throw new InvalidArgumentException('An eligible evidence snapshot is required to create the next review.'); } - $nextReview = DB::transaction(function () use ($review, $user, $snapshot, $tenant): TenantReview { + $nextReview = DB::transaction(function () use ($review, $user, $snapshot, $tenant): EnvironmentReview { $nextReview = $this->reviewService->create($tenant, $snapshot, $user); if ((int) $nextReview->getKey() !== (int) $review->getKey()) { $review->forceFill([ - 'status' => TenantReviewStatus::Superseded->value, + 'status' => EnvironmentReviewStatus::Superseded->value, 'superseded_by_review_id' => (int) $nextReview->getKey(), ])->save(); } $this->auditLogger->log( workspace: $tenant->workspace, - action: AuditActionId::TenantReviewSuccessorCreated, + action: AuditActionId::EnvironmentReviewSuccessorCreated, context: [ 'metadata' => [ 'review_id' => (int) $review->getKey(), 'next_review_id' => (int) $nextReview->getKey(), - 'before_status' => TenantReviewStatus::Published->value, - 'after_status' => TenantReviewStatus::Superseded->value, + 'before_status' => EnvironmentReviewStatus::Published->value, + 'after_status' => EnvironmentReviewStatus::Superseded->value, ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $nextReview->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $nextReview->getKey()), tenant: $tenant, @@ -194,9 +194,9 @@ private function validatedReason(mixed $reason, string $field): string return $resolved; } - private function invalidateArtifactTruthCache(TenantReview $review): void + private function invalidateArtifactTruthCache(EnvironmentReview $review): void { - $this->derivedStateStore->invalidateModel(DerivedStateFamily::ArtifactTruth, $review, 'tenant_review'); + $this->derivedStateStore->invalidateModel(DerivedStateFamily::ArtifactTruth, $review, 'environment_review'); $review->loadMissing('currentExportReviewPack'); diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewReadinessGate.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewReadinessGate.php similarity index 55% rename from apps/platform/app/Services/TenantReviews/TenantReviewReadinessGate.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewReadinessGate.php index 49392232..70080c99 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewReadinessGate.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewReadinessGate.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; -use App\Models\TenantReview; -use App\Support\TenantReviewCompletenessState; -use App\Support\TenantReviewStatus; +use App\Models\EnvironmentReview; +use App\Support\EnvironmentReviewCompletenessState; +use App\Support\EnvironmentReviewStatus; use Illuminate\Support\Collection; -final class TenantReviewReadinessGate +final class EnvironmentReviewReadinessGate { /** * @param iterable> $sections @@ -21,18 +21,18 @@ public function blockersForSections(iterable $sections): array foreach ($sections as $section) { $required = (bool) ($section['required'] ?? false); - $state = (string) ($section['completeness_state'] ?? TenantReviewCompletenessState::Missing->value); + $state = (string) ($section['completeness_state'] ?? EnvironmentReviewCompletenessState::Missing->value); $title = (string) ($section['title'] ?? 'Review section'); if (! $required) { continue; } - if ($state === TenantReviewCompletenessState::Missing->value) { + if ($state === EnvironmentReviewCompletenessState::Missing->value) { $blockers[] = sprintf('%s is missing.', $title); } - if ($state === TenantReviewCompletenessState::Stale->value) { + if ($state === EnvironmentReviewCompletenessState::Stale->value) { $blockers[] = sprintf('%s is stale and must be refreshed before publication.', $title); } } @@ -43,45 +43,45 @@ public function blockersForSections(iterable $sections): array /** * @param iterable> $sections */ - public function completenessForSections(iterable $sections): TenantReviewCompletenessState + public function completenessForSections(iterable $sections): EnvironmentReviewCompletenessState { $states = collect($sections) - ->map(static fn (array $section): string => (string) ($section['completeness_state'] ?? TenantReviewCompletenessState::Missing->value)) + ->map(static fn (array $section): string => (string) ($section['completeness_state'] ?? EnvironmentReviewCompletenessState::Missing->value)) ->values(); if ($states->isEmpty()) { - return TenantReviewCompletenessState::Missing; + return EnvironmentReviewCompletenessState::Missing; } - if ($states->contains(TenantReviewCompletenessState::Missing->value)) { - return TenantReviewCompletenessState::Missing; + if ($states->contains(EnvironmentReviewCompletenessState::Missing->value)) { + return EnvironmentReviewCompletenessState::Missing; } - if ($states->contains(TenantReviewCompletenessState::Stale->value)) { - return TenantReviewCompletenessState::Stale; + if ($states->contains(EnvironmentReviewCompletenessState::Stale->value)) { + return EnvironmentReviewCompletenessState::Stale; } - if ($states->contains(TenantReviewCompletenessState::Partial->value)) { - return TenantReviewCompletenessState::Partial; + if ($states->contains(EnvironmentReviewCompletenessState::Partial->value)) { + return EnvironmentReviewCompletenessState::Partial; } - return TenantReviewCompletenessState::Complete; + return EnvironmentReviewCompletenessState::Complete; } /** * @param iterable> $sections */ - public function statusForSections(iterable $sections): TenantReviewStatus + public function statusForSections(iterable $sections): EnvironmentReviewStatus { return $this->blockersForSections($sections) === [] - ? TenantReviewStatus::Ready - : TenantReviewStatus::Draft; + ? EnvironmentReviewStatus::Ready + : EnvironmentReviewStatus::Draft; } /** * @return list */ - public function blockersForReview(TenantReview $review): array + public function blockersForReview(EnvironmentReview $review): array { $sections = $review->relationLoaded('sections') ? $review->sections @@ -96,7 +96,7 @@ public function blockersForReview(TenantReview $review): array })->all()); } - public function canPublish(TenantReview $review): bool + public function canPublish(EnvironmentReview $review): bool { if (! $review->isMutable()) { return false; @@ -105,11 +105,11 @@ public function canPublish(TenantReview $review): bool return $this->blockersForReview($review) === []; } - public function canExport(TenantReview $review): bool + public function canExport(EnvironmentReview $review): bool { if (! in_array($review->statusEnum(), [ - TenantReviewStatus::Ready, - TenantReviewStatus::Published, + EnvironmentReviewStatus::Ready, + EnvironmentReviewStatus::Published, ], true)) { return false; } @@ -124,14 +124,14 @@ public function canExport(TenantReview $review): bool public function sectionStateCounts(iterable $sections): array { $counts = collect($sections) - ->groupBy(static fn (array $section): string => (string) ($section['completeness_state'] ?? TenantReviewCompletenessState::Missing->value)) + ->groupBy(static fn (array $section): string => (string) ($section['completeness_state'] ?? EnvironmentReviewCompletenessState::Missing->value)) ->map(static fn (Collection $group): int => $group->count()); return [ - 'complete' => (int) ($counts[TenantReviewCompletenessState::Complete->value] ?? 0), - 'partial' => (int) ($counts[TenantReviewCompletenessState::Partial->value] ?? 0), - 'missing' => (int) ($counts[TenantReviewCompletenessState::Missing->value] ?? 0), - 'stale' => (int) ($counts[TenantReviewCompletenessState::Stale->value] ?? 0), + 'complete' => (int) ($counts[EnvironmentReviewCompletenessState::Complete->value] ?? 0), + 'partial' => (int) ($counts[EnvironmentReviewCompletenessState::Partial->value] ?? 0), + 'missing' => (int) ($counts[EnvironmentReviewCompletenessState::Missing->value] ?? 0), + 'stale' => (int) ($counts[EnvironmentReviewCompletenessState::Stale->value] ?? 0), ]; } } diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewRegisterService.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewRegisterService.php similarity index 82% rename from apps/platform/app/Services/TenantReviews/TenantReviewRegisterService.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewRegisterService.php index 04686e9e..7c738b77 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewRegisterService.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewRegisterService.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; use App\Models\WorkspaceMembership; @@ -15,7 +15,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; -final class TenantReviewRegisterService +final class EnvironmentReviewRegisterService { public function __construct( private readonly CapabilityResolver $capabilityResolver, @@ -44,7 +44,7 @@ public function authorizedTenants(User $user, Workspace $workspace): array $this->capabilityResolver->primeMemberships($user, $tenants->modelKeys()); return $tenants - ->filter(fn (ManagedEnvironment $tenant): bool => $this->capabilityResolver->can($user, $tenant, Capabilities::TENANT_REVIEW_VIEW)) + ->filter(fn (ManagedEnvironment $tenant): bool => $this->capabilityResolver->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_VIEW)) ->keyBy(static fn (ManagedEnvironment $tenant): int => (int) $tenant->getKey()) ->all(); } @@ -53,7 +53,7 @@ public function query(User $user, Workspace $workspace): Builder { $tenantIds = array_keys($this->authorizedTenants($user, $workspace)); - return TenantReview::query() + return EnvironmentReview::query() ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack']) ->forWorkspace((int) $workspace->getKey()) ->whereIn('managed_environment_id', $tenantIds === [] ? [-1] : $tenantIds) @@ -65,12 +65,12 @@ public function latestPublishedQuery(User $user, Workspace $workspace): Builder { $tenantIds = array_keys($this->authorizedTenants($user, $workspace)); - $rankedReviews = TenantReview::query() + $rankedReviews = EnvironmentReview::query() ->select([ - 'tenant_reviews.id', - 'tenant_reviews.managed_environment_id', - 'tenant_reviews.published_at', - 'tenant_reviews.generated_at', + 'environment_reviews.id', + 'environment_reviews.managed_environment_id', + 'environment_reviews.published_at', + 'environment_reviews.generated_at', ]) ->selectRaw('ROW_NUMBER() OVER (PARTITION BY managed_environment_id ORDER BY published_at DESC, generated_at DESC, id DESC) as rn') ->forWorkspace((int) $workspace->getKey()) @@ -78,14 +78,14 @@ public function latestPublishedQuery(User $user, Workspace $workspace): Builder ->published(); $latestPublishedIds = DB::query() - ->fromSub($rankedReviews, 'ranked_tenant_reviews') + ->fromSub($rankedReviews, 'ranked_environment_reviews') ->where('rn', 1) ->select('id'); - return TenantReview::query() + return EnvironmentReview::query() ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack']) ->forWorkspace((int) $workspace->getKey()) - ->whereIn('tenant_reviews.id', $latestPublishedIds) + ->whereIn('environment_reviews.id', $latestPublishedIds) ->orderByDesc('published_at') ->orderByDesc('generated_at') ->orderByDesc('id'); @@ -98,9 +98,9 @@ public function customerWorkspaceTenantQuery(User $user, Workspace $workspace): return ManagedEnvironment::query() ->where('workspace_id', (int) $workspace->getKey()) ->whereIn('id', $tenantIds === [] ? [-1] : $tenantIds) - ->whereHas('tenantReviews', fn ($query) => $query->published()) + ->whereHas('environmentReviews', fn ($query) => $query->published()) ->with([ - 'tenantReviews' => fn ($query) => $query + 'environmentReviews' => fn ($query) => $query ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack']) ->published() ->orderByDesc('published_at') diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewSectionFactory.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewSectionFactory.php similarity index 94% rename from apps/platform/app/Services/TenantReviews/TenantReviewSectionFactory.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewSectionFactory.php index 302a61c8..f60fc3c2 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewSectionFactory.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewSectionFactory.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; use App\Models\EvidenceSnapshot; use App\Models\EvidenceSnapshotItem; use App\Support\Findings\FindingOutcomeSemantics; use App\Support\Governance\Controls\ComplianceEvidenceMappingV1; -use App\Support\TenantReviewCompletenessState; +use App\Support\EnvironmentReviewCompletenessState; use Illuminate\Support\Arr; use Illuminate\Support\Collection; -final class TenantReviewSectionFactory +final class EnvironmentReviewSectionFactory { public function __construct( private readonly FindingOutcomeSemantics $findingOutcomeSemantics, @@ -333,10 +333,10 @@ private function summary(?EvidenceSnapshotItem $item): array return is_array($item?->summary_payload) ? $item->summary_payload : []; } - private function state(?EvidenceSnapshotItem $item): TenantReviewCompletenessState + private function state(?EvidenceSnapshotItem $item): EnvironmentReviewCompletenessState { - return TenantReviewCompletenessState::tryFrom((string) $item?->state) - ?? TenantReviewCompletenessState::Missing; + return EnvironmentReviewCompletenessState::tryFrom((string) $item?->state) + ?? EnvironmentReviewCompletenessState::Missing; } private function sourceFingerprint(?EvidenceSnapshotItem $item): ?string @@ -361,23 +361,23 @@ private function canonicalControlsFromEntries(array $entries): array } /** - * @param array $states + * @param array $states */ - private function maxState(array $states): TenantReviewCompletenessState + private function maxState(array $states): EnvironmentReviewCompletenessState { - if (in_array(TenantReviewCompletenessState::Missing, $states, true)) { - return TenantReviewCompletenessState::Missing; + if (in_array(EnvironmentReviewCompletenessState::Missing, $states, true)) { + return EnvironmentReviewCompletenessState::Missing; } - if (in_array(TenantReviewCompletenessState::Stale, $states, true)) { - return TenantReviewCompletenessState::Stale; + if (in_array(EnvironmentReviewCompletenessState::Stale, $states, true)) { + return EnvironmentReviewCompletenessState::Stale; } - if (in_array(TenantReviewCompletenessState::Partial, $states, true)) { - return TenantReviewCompletenessState::Partial; + if (in_array(EnvironmentReviewCompletenessState::Partial, $states, true)) { + return EnvironmentReviewCompletenessState::Partial; } - return TenantReviewCompletenessState::Complete; + return EnvironmentReviewCompletenessState::Complete; } /** diff --git a/apps/platform/app/Services/TenantReviews/TenantReviewService.php b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.php similarity index 87% rename from apps/platform/app/Services/TenantReviews/TenantReviewService.php rename to apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.php index f90450c1..b5bf8eff 100644 --- a/apps/platform/app/Services/TenantReviews/TenantReviewService.php +++ b/apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.php @@ -2,43 +2,43 @@ declare(strict_types=1); -namespace App\Services\TenantReviews; +namespace App\Services\EnvironmentReviews; -use App\Jobs\ComposeTenantReviewJob; +use App\Jobs\ComposeEnvironmentReviewJob; use App\Models\EvidenceSnapshot; use App\Models\OperationRun; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Services\Audit\WorkspaceAuditLogger; use App\Services\OperationRunService; use App\Support\Audit\AuditActionId; use App\Support\OperationRunType; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewStatus; use Illuminate\Support\Facades\DB; use InvalidArgumentException; -final class TenantReviewService +final class EnvironmentReviewService { public function __construct( private readonly OperationRunService $operationRuns, private readonly WorkspaceAuditLogger $auditLogger, - private readonly TenantReviewComposer $composer, - private readonly TenantReviewFingerprint $fingerprint, + private readonly EnvironmentReviewComposer $composer, + private readonly EnvironmentReviewFingerprint $fingerprint, ) {} - public function create(ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, User $user): TenantReview + public function create(ManagedEnvironment $tenant, EvidenceSnapshot $snapshot, User $user): EnvironmentReview { return $this->queueComposition( tenant: $tenant, snapshot: $snapshot, user: $user, existingReview: null, - auditAction: AuditActionId::TenantReviewCreated, + auditAction: AuditActionId::EnvironmentReviewCreated, ); } - public function refresh(TenantReview $review, User $user, ?EvidenceSnapshot $snapshot = null): TenantReview + public function refresh(EnvironmentReview $review, User $user, ?EvidenceSnapshot $snapshot = null): EnvironmentReview { $tenant = $review->tenant; @@ -53,11 +53,11 @@ public function refresh(TenantReview $review, User $user, ?EvidenceSnapshot $sna snapshot: $snapshot, user: $user, existingReview: $review, - auditAction: AuditActionId::TenantReviewRefreshed, + auditAction: AuditActionId::EnvironmentReviewRefreshed, ); } - public function compose(TenantReview $review): TenantReview + public function compose(EnvironmentReview $review): EnvironmentReview { $review->loadMissing(['tenant', 'evidenceSnapshot.items']); @@ -121,7 +121,7 @@ public function activeCompositionRun(ManagedEnvironment $tenant, ?EvidenceSnapsh return $this->operationRuns->findCanonicalRunWithIdentity( tenant: $tenant, - type: OperationRunType::TenantReviewCompose->value, + type: OperationRunType::EnvironmentReviewCompose->value, identityInputs: [ 'managed_environment_id' => (int) $tenant->getKey(), 'snapshot_id' => (int) $snapshot->getKey(), @@ -134,9 +134,9 @@ private function queueComposition( ManagedEnvironment $tenant, ?EvidenceSnapshot $snapshot, User $user, - ?TenantReview $existingReview, + ?EnvironmentReview $existingReview, AuditActionId $auditAction, - ): TenantReview { + ): EnvironmentReview { if (! $snapshot instanceof EvidenceSnapshot) { throw new InvalidArgumentException('An eligible evidence snapshot is required.'); } @@ -148,17 +148,17 @@ private function queueComposition( $fingerprint = $this->fingerprint->forSnapshot($tenant, $snapshot); $review = $existingReview; - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { $existing = $this->findExistingMutableReview($tenant, $fingerprint); - if ($existing instanceof TenantReview) { + if ($existing instanceof EnvironmentReview) { return $existing->load(['tenant', 'evidenceSnapshot', 'sections', 'operationRun', 'initiator', 'publisher']); } } $operationRun = $this->operationRuns->ensureRunWithIdentity( tenant: $tenant, - type: OperationRunType::TenantReviewCompose->value, + type: OperationRunType::EnvironmentReviewCompose->value, identityInputs: [ 'managed_environment_id' => (int) $tenant->getKey(), 'snapshot_id' => (int) $snapshot->getKey(), @@ -177,14 +177,14 @@ private function queueComposition( initiator: $user, ); - $review ??= TenantReview::query()->create([ + $review ??= EnvironmentReview::query()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'operation_run_id' => (int) $operationRun->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'fingerprint' => $fingerprint, - 'status' => TenantReviewStatus::Draft->value, + 'status' => EnvironmentReviewStatus::Draft->value, 'completeness_state' => (string) $snapshot->completeness_state, 'summary' => [ 'evidence_basis' => [ @@ -199,12 +199,12 @@ private function queueComposition( ], ]); - if ($existingReview instanceof TenantReview) { + if ($existingReview instanceof EnvironmentReview) { $existingReview->forceFill([ 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'operation_run_id' => (int) $operationRun->getKey(), 'fingerprint' => $fingerprint, - 'status' => TenantReviewStatus::Draft->value, + 'status' => EnvironmentReviewStatus::Draft->value, ])->save(); $review = $existingReview->refresh(); @@ -212,8 +212,8 @@ private function queueComposition( if ($operationRun->wasRecentlyCreated) { $this->operationRuns->dispatchOrFail($operationRun, function () use ($review, $operationRun): void { - ComposeTenantReviewJob::dispatch( - tenantReviewId: (int) $review->getKey(), + ComposeEnvironmentReviewJob::dispatch( + environmentReviewId: (int) $review->getKey(), operationRunId: (int) $operationRun->getKey(), ); }); @@ -231,7 +231,7 @@ private function queueComposition( ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $review->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $review->getKey()), operationRunId: (int) $operationRun->getKey(), @@ -241,9 +241,9 @@ private function queueComposition( return $review->load(['tenant', 'evidenceSnapshot', 'sections', 'operationRun', 'initiator', 'publisher']); } - private function findExistingMutableReview(ManagedEnvironment $tenant, string $fingerprint): ?TenantReview + private function findExistingMutableReview(ManagedEnvironment $tenant, string $fingerprint): ?EnvironmentReview { - return TenantReview::query() + return EnvironmentReview::query() ->forTenant((int) $tenant->getKey()) ->mutable() ->where('fingerprint', $fingerprint) diff --git a/apps/platform/app/Services/Intune/TenantPermissionService.php b/apps/platform/app/Services/Intune/ManagedEnvironmentPermissionService.php similarity index 96% rename from apps/platform/app/Services/Intune/TenantPermissionService.php rename to apps/platform/app/Services/Intune/ManagedEnvironmentPermissionService.php index 21fd67b6..07a00693 100644 --- a/apps/platform/app/Services/Intune/TenantPermissionService.php +++ b/apps/platform/app/Services/Intune/ManagedEnvironmentPermissionService.php @@ -3,13 +3,13 @@ namespace App\Services\Intune; use App\Models\ManagedEnvironment; -use App\Models\TenantPermission; +use App\Models\ManagedEnvironmentPermission; use App\Services\Graph\GraphClientInterface; use App\Services\Providers\MicrosoftGraphOptionsResolver; use DateTimeInterface; use Illuminate\Support\Carbon; -class TenantPermissionService +class ManagedEnvironmentPermissionService { public function __construct( private readonly GraphClientInterface $graphClient, @@ -32,11 +32,11 @@ public function getRequiredPermissions(): array */ public function getGrantedPermissions(ManagedEnvironment $tenant): array { - return TenantPermission::query() + return ManagedEnvironmentPermission::query() ->where('managed_environment_id', $tenant->id) ->get() ->keyBy('permission_key') - ->map(fn (TenantPermission $permission) => [ + ->map(fn (ManagedEnvironmentPermission $permission) => [ 'status' => $permission->status, 'details' => $permission->details, 'last_checked_at' => $permission->last_checked_at, @@ -46,7 +46,7 @@ public function getGrantedPermissions(ManagedEnvironment $tenant): array /** * @param array|null}|string>|null $grantedStatuses - * @param bool $persist Persist comparison results to tenant_permissions + * @param bool $persist Persist comparison results to managed_environment_permissions * @param bool $liveCheck If true, fetch actual permissions from Graph API * @param bool $useConfiguredStub Include configured stub permissions when no live check is used * @param array{tenant?:string|null,client_id?:string|null,client_secret?:string|null,client_request_id?:string|null}|null $graphOptions @@ -165,7 +165,7 @@ public function compare( if (! $shouldPersistErrorSnapshot) { $canPersist = false; } else { - $hasStoredStatuses = TenantPermission::query() + $hasStoredStatuses = ManagedEnvironmentPermission::query() ->where('managed_environment_id', $tenant->id) ->exists(); @@ -189,7 +189,7 @@ public function compare( : ($granted[$key]['details'] ?? null); if ($canPersist) { - TenantPermission::updateOrCreate( + ManagedEnvironmentPermission::updateOrCreate( [ 'managed_environment_id' => $tenant->id, 'permission_key' => $key, @@ -433,7 +433,7 @@ private function fetchLivePermissions(ManagedEnvironment $tenant, ?array $graphO private function lastRefreshedAtIso(ManagedEnvironment $tenant): ?string { - $lastCheckedAt = TenantPermission::query() + $lastCheckedAt = ManagedEnvironmentPermission::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->max('last_checked_at'); diff --git a/apps/platform/app/Services/Intune/TenantRequiredPermissionsViewModelBuilder.php b/apps/platform/app/Services/Intune/ManagedEnvironmentRequiredPermissionsViewModelBuilder.php similarity index 93% rename from apps/platform/app/Services/Intune/TenantRequiredPermissionsViewModelBuilder.php rename to apps/platform/app/Services/Intune/ManagedEnvironmentRequiredPermissionsViewModelBuilder.php index 879e478a..26ed7916 100644 --- a/apps/platform/app/Services/Intune/TenantRequiredPermissionsViewModelBuilder.php +++ b/apps/platform/app/Services/Intune/ManagedEnvironmentRequiredPermissionsViewModelBuilder.php @@ -6,15 +6,15 @@ use App\Support\Providers\Capabilities\ProviderCapabilityDefinition; use App\Support\Providers\Capabilities\ProviderCapabilityRegistry; use App\Support\Providers\Capabilities\ProviderCapabilityStatus; -use App\Support\Verification\TenantPermissionCheckClusters; +use App\Support\Verification\ManagedEnvironmentPermissionCheckClusters; use App\Support\Verification\VerificationReportOverall; use Carbon\CarbonInterface; use Illuminate\Support\Carbon; -class TenantRequiredPermissionsViewModelBuilder +class ManagedEnvironmentRequiredPermissionsViewModelBuilder { /** - * @phpstan-type TenantPermissionRow array{key:string,type:'application'|'delegated',description:?string,features:array,status:'granted'|'missing'|'error',details:array|null} + * @phpstan-type ManagedEnvironmentPermissionRow array{key:string,type:'application'|'delegated',description:?string,features:array,status:'granted'|'missing'|'error',details:array|null} * @phpstan-type FeatureImpact array{feature:string,missing:int,required_application:int,required_delegated:int,blocked:bool} * @phpstan-type CapabilityGroup array{provider_capability_key:string,label:string,status:string,provider_requirement_keys:array,missing_requirement_keys:array,evidence_counts:array{requirements:int,missing:int,errors:int},message:string} * @phpstan-type FilterState array{status:'missing'|'present'|'all',type:'application'|'delegated'|'all',features:array,search:string} @@ -28,12 +28,12 @@ class TenantRequiredPermissionsViewModelBuilder * primary_capability_group: CapabilityGroup|null, * freshness: array{last_refreshed_at:?string,is_stale:bool} * }, - * permissions: array, + * permissions: array, * filters: FilterState, * copy: array{application:string,delegated:string} * } */ - public function __construct(private readonly TenantPermissionService $permissionService) {} + public function __construct(private readonly ManagedEnvironmentPermissionService $permissionService) {} /** * @param array $filters @@ -48,7 +48,7 @@ public function build(ManagedEnvironment $tenant, array $filters = []): array useConfiguredStub: false, ); - /** @var array $allPermissions */ + /** @var array $allPermissions */ $allPermissions = collect($comparison['permissions'] ?? []) ->filter(fn (mixed $row): bool => is_array($row)) ->map(fn (array $row): array => self::normalizePermissionRow($row)) @@ -87,7 +87,7 @@ public function build(ManagedEnvironment $tenant, array $filters = []): array } /** - * @param array $permissions + * @param array $permissions * @param array{last_refreshed_at:?string,is_stale:bool} $freshness * @return array */ @@ -127,7 +127,7 @@ public static function primaryCapabilityGroup(array $groups): ?array } /** - * @param array $permissions + * @param array $permissions * @return CapabilityGroup */ private static function deriveCapabilityGroup( @@ -138,7 +138,7 @@ private static function deriveCapabilityGroup( $rowsByRequirement = []; foreach ($definition->providerRequirementKeys as $requirementKey) { - $rowsByRequirement[$requirementKey] = TenantPermissionCheckClusters::rowsForRequirementKey($permissions, $requirementKey); + $rowsByRequirement[$requirementKey] = ManagedEnvironmentPermissionCheckClusters::rowsForRequirementKey($permissions, $requirementKey); } $rows = array_values(array_merge(...array_values($rowsByRequirement ?: [[]]))); @@ -193,7 +193,7 @@ private static function deriveCapabilityGroup( } /** - * @param array $permissions + * @param array $permissions */ public static function deriveOverallStatus(array $permissions, bool $hasStaleFreshness = false): string { @@ -243,7 +243,7 @@ public static function deriveFreshness(?CarbonInterface $lastRefreshedAt, ?Carbo } /** - * @param array $permissions + * @param array $permissions * @return array{missing_application:int,missing_delegated:int,present:int,error:int} */ public static function deriveCounts(array $permissions): array @@ -281,7 +281,7 @@ public static function deriveCounts(array $permissions): array } /** - * @param array $permissions + * @param array $permissions * @return array */ public static function deriveFeatureImpacts(array $permissions): array @@ -345,7 +345,7 @@ public static function deriveFeatureImpacts(array $permissions): array * - Respects Feature filter only * - Ignores Search * - * @param array $permissions + * @param array $permissions * @param 'application'|'delegated' $type * @param array $featureFilter */ @@ -383,8 +383,8 @@ public static function deriveCopyPayload(array $permissions, string $type, array } /** - * @param array $permissions - * @return array + * @param array $permissions + * @return array */ public static function applyFilterState(array $permissions, array $state): array { @@ -489,7 +489,7 @@ public static function normalizeFilterState(array $filters): array /** * @param array $row - * @return TenantPermissionRow + * @return ManagedEnvironmentPermissionRow */ private static function normalizePermissionRow(array $row): array { diff --git a/apps/platform/app/Services/Onboarding/OnboardingDraftMutationService.php b/apps/platform/app/Services/Onboarding/OnboardingDraftMutationService.php index 24d403ed..d05bc456 100644 --- a/apps/platform/app/Services/Onboarding/OnboardingDraftMutationService.php +++ b/apps/platform/app/Services/Onboarding/OnboardingDraftMutationService.php @@ -6,7 +6,7 @@ use App\Exceptions\Onboarding\OnboardingDraftConflictException; use App\Exceptions\Onboarding\OnboardingDraftImmutableException; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\Workspace; use Illuminate\Support\Facades\DB; @@ -19,25 +19,25 @@ public function __construct( ) {} /** - * @param callable(TenantOnboardingSession):void $mutator + * @param callable(ManagedEnvironmentOnboardingSession):void $mutator */ public function createOrResume( Workspace $workspace, User $actor, string $entraTenantId, callable $mutator, - ?TenantOnboardingSession $preferredDraft = null, + ?ManagedEnvironmentOnboardingSession $preferredDraft = null, ?int $expectedVersion = null, bool $incrementVersion = true, ?bool &$wasCreated = null, - ): TenantOnboardingSession { - return DB::transaction(function () use ($workspace, $actor, $entraTenantId, $mutator, $preferredDraft, $expectedVersion, $incrementVersion, &$wasCreated): TenantOnboardingSession { + ): ManagedEnvironmentOnboardingSession { + return DB::transaction(function () use ($workspace, $actor, $entraTenantId, $mutator, $preferredDraft, $expectedVersion, $incrementVersion, &$wasCreated): ManagedEnvironmentOnboardingSession { $draft = $this->resolveDraftForIdentity($workspace, $entraTenantId, $preferredDraft); - $isNew = ! $draft instanceof TenantOnboardingSession; + $isNew = ! $draft instanceof ManagedEnvironmentOnboardingSession; $wasCreated = $isNew; if ($isNew) { - $draft = new TenantOnboardingSession; + $draft = new ManagedEnvironmentOnboardingSession; $draft->workspace_id = (int) $workspace->getKey(); $draft->entra_tenant_id = $entraTenantId; $draft->started_by_user_id = (int) $actor->getKey(); @@ -61,18 +61,18 @@ public function createOrResume( } /** - * @param callable(TenantOnboardingSession):void $mutator + * @param callable(ManagedEnvironmentOnboardingSession):void $mutator */ public function mutate( - TenantOnboardingSession $draft, + ManagedEnvironmentOnboardingSession $draft, User $actor, callable $mutator, ?int $expectedVersion = null, bool $incrementVersion = true, bool $allowTerminal = false, - ): TenantOnboardingSession { - return DB::transaction(function () use ($draft, $actor, $mutator, $expectedVersion, $incrementVersion, $allowTerminal): TenantOnboardingSession { - $lockedDraft = TenantOnboardingSession::query() + ): ManagedEnvironmentOnboardingSession { + return DB::transaction(function () use ($draft, $actor, $mutator, $expectedVersion, $incrementVersion, $allowTerminal): ManagedEnvironmentOnboardingSession { + $lockedDraft = ManagedEnvironmentOnboardingSession::query() ->whereKey($draft->getKey()) ->lockForUpdate() ->firstOrFail(); @@ -101,19 +101,19 @@ public function mutate( }); } - public function lockForTrustedMutation(TenantOnboardingSession|int|string $draft, Workspace $workspace): TenantOnboardingSession + public function lockForTrustedMutation(ManagedEnvironmentOnboardingSession|int|string $draft, Workspace $workspace): ManagedEnvironmentOnboardingSession { - $draftId = $draft instanceof TenantOnboardingSession + $draftId = $draft instanceof ManagedEnvironmentOnboardingSession ? (int) $draft->getKey() : (int) $draft; - $lockedDraft = TenantOnboardingSession::query() + $lockedDraft = ManagedEnvironmentOnboardingSession::query() ->whereKey($draftId) ->where('workspace_id', (int) $workspace->getKey()) ->lockForUpdate() ->first(); - if (! $lockedDraft instanceof TenantOnboardingSession) { + if (! $lockedDraft instanceof ManagedEnvironmentOnboardingSession) { throw new NotFoundHttpException; } @@ -123,16 +123,16 @@ public function lockForTrustedMutation(TenantOnboardingSession|int|string $draft private function resolveDraftForIdentity( Workspace $workspace, string $entraTenantId, - ?TenantOnboardingSession $preferredDraft = null, - ): ?TenantOnboardingSession { - if ($preferredDraft instanceof TenantOnboardingSession) { - $lockedPreferredDraft = TenantOnboardingSession::query() + ?ManagedEnvironmentOnboardingSession $preferredDraft = null, + ): ?ManagedEnvironmentOnboardingSession { + if ($preferredDraft instanceof ManagedEnvironmentOnboardingSession) { + $lockedPreferredDraft = ManagedEnvironmentOnboardingSession::query() ->whereKey($preferredDraft->getKey()) ->where('workspace_id', (int) $workspace->getKey()) ->lockForUpdate() ->first(); - if ($lockedPreferredDraft instanceof TenantOnboardingSession && $lockedPreferredDraft->entra_tenant_id === $entraTenantId) { + if ($lockedPreferredDraft instanceof ManagedEnvironmentOnboardingSession && $lockedPreferredDraft->entra_tenant_id === $entraTenantId) { if ($lockedPreferredDraft->lifecycleState()->isTerminal()) { throw new OnboardingDraftImmutableException( draftId: (int) $lockedPreferredDraft->getKey(), @@ -144,7 +144,7 @@ private function resolveDraftForIdentity( } } - return TenantOnboardingSession::query() + return ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $workspace->getKey()) ->where('entra_tenant_id', $entraTenantId) ->resumable() @@ -153,7 +153,7 @@ private function resolveDraftForIdentity( ->first(); } - private function assertExpectedVersion(TenantOnboardingSession $draft, int $expectedVersion): void + private function assertExpectedVersion(ManagedEnvironmentOnboardingSession $draft, int $expectedVersion): void { $actualVersion = max(1, (int) ($draft->version ?? 1)); @@ -168,7 +168,7 @@ private function assertExpectedVersion(TenantOnboardingSession $draft, int $expe ); } - private function persistDraft(TenantOnboardingSession $draft, bool $incrementVersion): void + private function persistDraft(ManagedEnvironmentOnboardingSession $draft, bool $incrementVersion): void { $currentVersion = max(0, (int) ($draft->version ?? 0)); diff --git a/apps/platform/app/Services/Onboarding/OnboardingDraftResolver.php b/apps/platform/app/Services/Onboarding/OnboardingDraftResolver.php index de213530..73fd5893 100644 --- a/apps/platform/app/Services/Onboarding/OnboardingDraftResolver.php +++ b/apps/platform/app/Services/Onboarding/OnboardingDraftResolver.php @@ -4,7 +4,7 @@ namespace App\Services\Onboarding; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\Workspace; use App\Services\Audit\WorkspaceAuditLogger; @@ -25,18 +25,18 @@ public function __construct( * @throws AuthorizationException * @throws NotFoundHttpException */ - public function resolve(TenantOnboardingSession|int|string $draft, User $user, Workspace $workspace): TenantOnboardingSession + public function resolve(ManagedEnvironmentOnboardingSession|int|string $draft, User $user, Workspace $workspace): ManagedEnvironmentOnboardingSession { - $draftId = $draft instanceof TenantOnboardingSession + $draftId = $draft instanceof ManagedEnvironmentOnboardingSession ? (int) $draft->getKey() : (int) $draft; - $resolvedDraft = TenantOnboardingSession::query() - ->with(['tenant', 'startedByUser', 'updatedByUser']) + $resolvedDraft = ManagedEnvironmentOnboardingSession::query() + ->with(['managedEnvironment', 'startedByUser', 'updatedByUser']) ->whereKey($draftId) ->first(); - if (! $resolvedDraft instanceof TenantOnboardingSession) { + if (! $resolvedDraft instanceof ManagedEnvironmentOnboardingSession) { throw new NotFoundHttpException; } @@ -48,7 +48,7 @@ public function resolve(TenantOnboardingSession|int|string $draft, User $user, W $resolvedDraft = $this->lifecycleService ->syncPersistedLifecycle($resolvedDraft) - ->loadMissing(['tenant', 'startedByUser', 'updatedByUser']); + ->loadMissing(['managedEnvironment', 'startedByUser', 'updatedByUser']); $normalizedTenant = $this->lifecycleService->syncLinkedTenantAfterCancellation($resolvedDraft); @@ -65,7 +65,7 @@ public function resolve(TenantOnboardingSession|int|string $draft, User $user, W ], ); - $resolvedDraft->setRelation('tenant', $normalizedTenant); + $resolvedDraft->setRelation('managedEnvironment', $normalizedTenant); } return $resolvedDraft; @@ -75,18 +75,18 @@ public function resolve(TenantOnboardingSession|int|string $draft, User $user, W * @throws AuthorizationException * @throws NotFoundHttpException */ - public function resolveForTrustedAction(TenantOnboardingSession|int|string $draft, User $user, Workspace $workspace): TenantOnboardingSession + public function resolveForTrustedAction(ManagedEnvironmentOnboardingSession|int|string $draft, User $user, Workspace $workspace): ManagedEnvironmentOnboardingSession { return $this->resolve($draft, $user, $workspace); } /** - * @return Collection + * @return Collection */ public function resumableDraftsFor(User $user, Workspace $workspace): Collection { - $drafts = TenantOnboardingSession::query() - ->with(['tenant', 'startedByUser', 'updatedByUser']) + $drafts = ManagedEnvironmentOnboardingSession::query() + ->with(['managedEnvironment', 'startedByUser', 'updatedByUser']) ->where('workspace_id', (int) $workspace->getKey()) ->resumable() ->orderByDesc('updated_at') @@ -103,7 +103,7 @@ public function resumableDraftsFor(User $user, Workspace $workspace): Collection $resolvedDraft = $this->lifecycleService ->syncPersistedLifecycle($draft) - ->loadMissing(['tenant', 'startedByUser', 'updatedByUser']); + ->loadMissing(['managedEnvironment', 'startedByUser', 'updatedByUser']); if (! $this->lifecycleService->canResumeDraft($resolvedDraft)) { continue; diff --git a/apps/platform/app/Services/Onboarding/OnboardingDraftStageResolver.php b/apps/platform/app/Services/Onboarding/OnboardingDraftStageResolver.php index ba6b3947..eb1185de 100644 --- a/apps/platform/app/Services/Onboarding/OnboardingDraftStageResolver.php +++ b/apps/platform/app/Services/Onboarding/OnboardingDraftStageResolver.php @@ -4,7 +4,7 @@ namespace App\Services\Onboarding; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Support\Onboarding\OnboardingCheckpoint; use App\Support\Onboarding\OnboardingDraftStage; use App\Support\Onboarding\OnboardingLifecycleState; @@ -15,9 +15,9 @@ public function __construct( private readonly OnboardingLifecycleService $lifecycleService, ) {} - public function resolve(?TenantOnboardingSession $draft): OnboardingDraftStage + public function resolve(?ManagedEnvironmentOnboardingSession $draft): OnboardingDraftStage { - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return OnboardingDraftStage::Identify; } diff --git a/apps/platform/app/Services/Onboarding/OnboardingLifecycleService.php b/apps/platform/app/Services/Onboarding/OnboardingLifecycleService.php index cfe78815..a34271ee 100644 --- a/apps/platform/app/Services/Onboarding/OnboardingLifecycleService.php +++ b/apps/platform/app/Services/Onboarding/OnboardingLifecycleService.php @@ -8,7 +8,7 @@ use App\Models\OperationRun; use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Services\Tenants\TenantOperabilityService; use App\Support\Onboarding\OnboardingCheckpoint; use App\Support\Onboarding\OnboardingLifecycleState; @@ -26,11 +26,11 @@ public function __construct( private readonly ProductTelemetryRecorder $productTelemetryRecorder, ) {} - public function syncPersistedLifecycle(TenantOnboardingSession $draft, bool $incrementVersion = false): TenantOnboardingSession + public function syncPersistedLifecycle(ManagedEnvironmentOnboardingSession $draft, bool $incrementVersion = false): ManagedEnvironmentOnboardingSession { - $freshDraft = TenantOnboardingSession::query()->whereKey($draft->getKey())->first(); + $freshDraft = ManagedEnvironmentOnboardingSession::query()->whereKey($draft->getKey())->first(); - if (! $freshDraft instanceof TenantOnboardingSession) { + if (! $freshDraft instanceof ManagedEnvironmentOnboardingSession) { return $draft; } @@ -44,7 +44,7 @@ public function syncPersistedLifecycle(TenantOnboardingSession $draft, bool $inc return $freshDraft->refresh(); } - public function applySnapshot(TenantOnboardingSession $draft, bool $incrementVersion = false): bool + public function applySnapshot(ManagedEnvironmentOnboardingSession $draft, bool $incrementVersion = false): bool { $snapshot = $this->snapshot($draft); $lifecycleState = $draft->lifecycle_state instanceof OnboardingLifecycleState @@ -98,7 +98,7 @@ public function applySnapshot(TenantOnboardingSession $draft, bool $incrementVer return $changed; } - public function recordCompletedCheckpointTelemetryIfNeeded(TenantOnboardingSession $draft): void + public function recordCompletedCheckpointTelemetryIfNeeded(ManagedEnvironmentOnboardingSession $draft): void { if (! $draft->wasChanged('last_completed_checkpoint')) { return; @@ -127,7 +127,7 @@ public function recordCompletedCheckpointTelemetryIfNeeded(TenantOnboardingSessi workspaceId: $workspaceId, tenantId: $tenantId, userId: $userId, - subjectType: 'tenant_onboarding_session', + subjectType: 'managed_environment_onboarding_session', subjectId: (int) $draft->getKey(), metadata: [ 'checkpoint_key' => $checkpoint->value, @@ -147,7 +147,7 @@ public function recordCompletedCheckpointTelemetryIfNeeded(TenantOnboardingSessi * blocking_reason_code: string|null * } */ - public function snapshot(TenantOnboardingSession $draft): array + public function snapshot(ManagedEnvironmentOnboardingSession $draft): array { $selectedProviderConnectionId = $this->selectedProviderConnectionId($draft); $verificationRun = $this->verificationRun($draft); @@ -334,7 +334,7 @@ public function snapshot(TenantOnboardingSession $draft): array ]; } - public function verificationRun(TenantOnboardingSession $draft): ?OperationRun + public function verificationRun(ManagedEnvironmentOnboardingSession $draft): ?OperationRun { $state = is_array($draft->state) ? $draft->state : []; $runId = $this->normalizeInteger($state['verification_operation_run_id'] ?? $state['verification_run_id'] ?? null); @@ -355,7 +355,7 @@ public function verificationRun(TenantOnboardingSession $draft): ?OperationRun } public function verificationStatus( - TenantOnboardingSession $draft, + ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId = null, ?OperationRun $run = null, ): string { @@ -386,7 +386,7 @@ public function verificationStatus( } public function verificationCanProceed( - TenantOnboardingSession $draft, + ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId = null, ?OperationRun $run = null, ): bool { @@ -408,7 +408,7 @@ public function verificationCanProceed( return in_array($this->verificationStatus($draft, $selectedProviderConnectionId, $run), ['ready', 'needs_attention'], true); } - public function verificationIsBlocked(TenantOnboardingSession $draft, ?int $selectedProviderConnectionId = null): bool + public function verificationIsBlocked(ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId = null): bool { return $this->verificationStatus($draft, $selectedProviderConnectionId) === 'blocked'; } @@ -425,32 +425,32 @@ public function verificationIsBlocked(TenantOnboardingSession $draft, ?int $sele * is_completed: bool * }> */ - public function bootstrapRunSummaries(TenantOnboardingSession $draft, ?int $selectedProviderConnectionId = null): array + public function bootstrapRunSummaries(ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId = null): array { $selectedProviderConnectionId ??= $this->selectedProviderConnectionId($draft); return $this->bootstrapState($draft, $selectedProviderConnectionId)['summaries']; } - public function isReadyForActivation(TenantOnboardingSession $draft): bool + public function isReadyForActivation(ManagedEnvironmentOnboardingSession $draft): bool { return $this->snapshot($draft)['lifecycle_state'] === OnboardingLifecycleState::ReadyForActivation; } - public function hasActiveCheckpoint(TenantOnboardingSession $draft): bool + public function hasActiveCheckpoint(ManagedEnvironmentOnboardingSession $draft): bool { $snapshot = $this->snapshot($draft); return in_array($snapshot['lifecycle_state'], [OnboardingLifecycleState::Verifying, OnboardingLifecycleState::Bootstrapping], true); } - public function canResumeDraft(TenantOnboardingSession $draft): bool + public function canResumeDraft(ManagedEnvironmentOnboardingSession $draft): bool { if (! $draft->isWorkflowResumable()) { return false; } - $tenant = $draft->tenant; + $tenant = $draft->managedEnvironment; if (! $tenant instanceof ManagedEnvironment) { return true; @@ -459,9 +459,9 @@ public function canResumeDraft(TenantOnboardingSession $draft): bool return $this->tenantOperabilityService->canResumeOnboarding($tenant); } - public function syncLinkedTenantAfterCancellation(TenantOnboardingSession $draft): ?ManagedEnvironment + public function syncLinkedTenantAfterCancellation(ManagedEnvironmentOnboardingSession $draft): ?ManagedEnvironment { - $tenant = $draft->tenant; + $tenant = $draft->managedEnvironment; if (! $tenant instanceof ManagedEnvironment) { return null; @@ -471,7 +471,7 @@ public function syncLinkedTenantAfterCancellation(TenantOnboardingSession $draft return null; } - $hasOtherResumableDrafts = TenantOnboardingSession::query() + $hasOtherResumableDrafts = ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $draft->workspace_id) ->where('managed_environment_id', (int) $tenant->getKey()) ->whereKeyNot((int) $draft->getKey()) @@ -487,7 +487,7 @@ public function syncLinkedTenantAfterCancellation(TenantOnboardingSession $draft return $tenant->fresh(); } - private function hasTenantIdentity(TenantOnboardingSession $draft): bool + private function hasTenantIdentity(ManagedEnvironmentOnboardingSession $draft): bool { if ($draft->managed_environment_id !== null) { return true; @@ -499,7 +499,7 @@ private function hasTenantIdentity(TenantOnboardingSession $draft): bool return is_string($entraTenantId) && trim($entraTenantId) !== ''; } - private function selectedProviderConnectionId(TenantOnboardingSession $draft): ?int + private function selectedProviderConnectionId(ManagedEnvironmentOnboardingSession $draft): ?int { $state = is_array($draft->state) ? $draft->state : []; @@ -518,7 +518,7 @@ private function selectedProviderConnectionId(TenantOnboardingSession $draft): ? return $exists ? $providerConnectionId : null; } - private function connectionRecentlyUpdated(TenantOnboardingSession $draft): bool + private function connectionRecentlyUpdated(ManagedEnvironmentOnboardingSession $draft): bool { $state = is_array($draft->state) ? $draft->state : []; @@ -639,7 +639,7 @@ private function runReasonCodes(OperationRun $run): array * }> * } */ - private function bootstrapState(TenantOnboardingSession $draft, ?int $selectedProviderConnectionId): array + private function bootstrapState(ManagedEnvironmentOnboardingSession $draft, ?int $selectedProviderConnectionId): array { $selectedTypes = $this->bootstrapOperationTypes($draft); $runMap = $this->bootstrapRunMap($draft, $selectedTypes); @@ -717,7 +717,7 @@ private function bootstrapState(TenantOnboardingSession $draft, ?int $selectedPr /** * @return array */ - private function bootstrapOperationTypes(TenantOnboardingSession $draft): array + private function bootstrapOperationTypes(ManagedEnvironmentOnboardingSession $draft): array { $state = is_array($draft->state) ? $draft->state : []; $types = $state['bootstrap_operation_types'] ?? []; @@ -736,7 +736,7 @@ private function bootstrapOperationTypes(TenantOnboardingSession $draft): array * @param array $selectedTypes * @return array */ - private function bootstrapRunMap(TenantOnboardingSession $draft, array $selectedTypes): array + private function bootstrapRunMap(ManagedEnvironmentOnboardingSession $draft, array $selectedTypes): array { $state = is_array($draft->state) ? $draft->state : []; $runs = $state['bootstrap_operation_runs'] ?? null; diff --git a/apps/platform/app/Services/Operations/QueuedExecutionLegitimacyGate.php b/apps/platform/app/Services/Operations/QueuedExecutionLegitimacyGate.php index c5fa3834..0037639d 100644 --- a/apps/platform/app/Services/Operations/QueuedExecutionLegitimacyGate.php +++ b/apps/platform/app/Services/Operations/QueuedExecutionLegitimacyGate.php @@ -342,7 +342,7 @@ private function laneForContext(QueuedExecutionContext $context): TenantInteract $runContext = is_array($context->run->context) ? $context->run->context : []; $wizardFlow = data_get($runContext, 'wizard.flow'); - if (is_string($wizardFlow) && trim($wizardFlow) === 'managed_tenant_onboarding') { + if (is_string($wizardFlow) && trim($wizardFlow) === 'managed_environment_onboarding') { return TenantInteractionLane::OnboardingWorkflow; } diff --git a/apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php b/apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php index 9020568b..b0af6dc4 100644 --- a/apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php +++ b/apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php @@ -17,7 +17,7 @@ /** * Generates, auto-resolves, and re-opens permission posture findings - * based on the output of TenantPermissionService::compare(). + * based on the output of ManagedEnvironmentPermissionService::compare(). */ final class PermissionPostureFindingGenerator implements FindingGeneratorContract { diff --git a/apps/platform/app/Services/PortfolioCompare/CrossTenantPromotionExecutionService.php b/apps/platform/app/Services/PortfolioCompare/CrossEnvironmentPromotionExecutionService.php similarity index 74% rename from apps/platform/app/Services/PortfolioCompare/CrossTenantPromotionExecutionService.php rename to apps/platform/app/Services/PortfolioCompare/CrossEnvironmentPromotionExecutionService.php index 470b5ae3..85fc1398 100644 --- a/apps/platform/app/Services/PortfolioCompare/CrossTenantPromotionExecutionService.php +++ b/apps/platform/app/Services/PortfolioCompare/CrossEnvironmentPromotionExecutionService.php @@ -4,7 +4,7 @@ namespace App\Services\PortfolioCompare; -use App\Jobs\Operations\CrossTenantPromotionExecutionJob; +use App\Jobs\Operations\CrossEnvironmentPromotionExecutionJob; use App\Models\OperationRun; use App\Models\ProviderConnection; use App\Models\User; @@ -17,14 +17,14 @@ use App\Support\OperationalControls\OperationalControlBlockedException; use App\Support\OperationalControls\OperationalControlEvaluator; use App\Support\OperationRunStatus; -use App\Support\PortfolioCompare\CrossTenantCompareSelection; -use App\Support\PortfolioCompare\CrossTenantPromotionExecutionPlanner; +use App\Support\PortfolioCompare\CrossEnvironmentCompareSelection; +use App\Support\PortfolioCompare\CrossEnvironmentPromotionExecutionPlanner; use Carbon\CarbonImmutable; -final class CrossTenantPromotionExecutionService +final class CrossEnvironmentPromotionExecutionService { public function __construct( - private readonly CrossTenantPromotionExecutionPlanner $planner, + private readonly CrossEnvironmentPromotionExecutionPlanner $planner, private readonly OperationRunService $operationRuns, private readonly WorkspaceAuditLogger $auditLogger, private readonly OperationalControlEvaluator $operationalControls, @@ -35,12 +35,12 @@ public function __construct( * @param array $preflight */ public function start( - CrossTenantCompareSelection $selection, + CrossEnvironmentCompareSelection $selection, array $preview, array $preflight, User $actor, ): ProviderOperationStartResult { - $workspace = $selection->targetTenant->workspace; + $workspace = $selection->targetEnvironment->workspace; if (! $workspace instanceof Workspace) { throw new \RuntimeException('Promotion execution requires a workspace context.'); @@ -60,8 +60,8 @@ public function start( 'reason_text' => $decision->reasonText, 'expires_at' => $decision->expiresAt?->toIso8601String(), 'actor_id' => (int) $actor->getKey(), - 'source_tenant_id' => (int) $selection->sourceTenant->getKey(), - 'target_tenant_id' => (int) $selection->targetTenant->getKey(), + 'source_environment_id' => (int) $selection->sourceEnvironment->getKey(), + 'target_environment_id' => (int) $selection->targetEnvironment->getKey(), 'requested_scope' => 'promotion.execute', ], static fn (mixed $value): bool => $value !== null && $value !== ''), ], @@ -71,14 +71,14 @@ public function start( resourceId: $decision->sourceActivationId !== null ? (string) $decision->sourceActivationId : null, targetLabel: 'Promotion execution', summary: 'Promotion execution blocked by operational control', - tenant: $selection->targetTenant, + tenant: $selection->targetEnvironment, ); throw OperationalControlBlockedException::forDecision($decision, 'Promotion execution'); } $plan = $this->planner->build($preview, $preflight); - $providerConnection = $this->defaultProviderConnection((int) $selection->targetTenant->getKey()); + $providerConnection = $this->defaultProviderConnection((int) $selection->targetEnvironment->getKey()); $now = CarbonImmutable::now(); $identity = array_replace($plan['identity'], [ @@ -87,20 +87,20 @@ public function start( $context = [ 'operation_type' => 'promotion.execute', - 'source_tenant_id' => (int) $selection->sourceTenant->getKey(), - 'source_tenant_name' => (string) $selection->sourceTenant->name, - 'target_tenant_id' => (int) $selection->targetTenant->getKey(), - 'target_tenant_name' => (string) $selection->targetTenant->name, + 'source_environment_id' => (int) $selection->sourceEnvironment->getKey(), + 'source_environment_name' => (string) $selection->sourceEnvironment->name, + 'target_environment_id' => (int) $selection->targetEnvironment->getKey(), + 'target_environment_name' => (string) $selection->targetEnvironment->name, 'provider_connection_id' => $providerConnection instanceof ProviderConnection ? (int) $providerConnection->getKey() : null, 'required_capability' => Capabilities::TENANT_MANAGE, 'workspace_required_capability' => Capabilities::WORKSPACE_BASELINES_MANAGE, 'target_scope' => [ 'workspace_id' => (int) $workspace->getKey(), - 'managed_environment_id' => (int) $selection->targetTenant->getKey(), + 'managed_environment_id' => (int) $selection->targetEnvironment->getKey(), 'provider_connection_id' => $providerConnection instanceof ProviderConnection ? (int) $providerConnection->getKey() : null, 'entra_tenant_id' => $providerConnection instanceof ProviderConnection ? (string) $providerConnection->entra_tenant_id - : (string) ($selection->targetTenant->managed_environment_id ?? $selection->targetTenant->external_id ?? $selection->targetTenant->getKey()), + : (string) ($selection->targetEnvironment->managed_environment_id ?? $selection->targetEnvironment->external_id ?? $selection->targetEnvironment->getKey()), ], 'promotion_execution' => [ 'queued_at' => $now->toIso8601String(), @@ -111,7 +111,7 @@ public function start( ]; $run = $this->operationRuns->ensureRunWithIdentity( - tenant: $selection->targetTenant, + tenant: $selection->targetEnvironment, type: 'promotion.execute', identityInputs: $identity, context: $context, @@ -134,13 +134,13 @@ public function start( $this->operationRuns->dispatchOrFail( $run, - fn (OperationRun $operationRun): mixed => CrossTenantPromotionExecutionJob::dispatch($operationRun), + fn (OperationRun $operationRun): mixed => CrossEnvironmentPromotionExecutionJob::dispatch($operationRun), ); - $this->auditLogger->logCrossTenantPromotionExecutionQueued( + $this->auditLogger->logCrossEnvironmentPromotionExecutionQueued( workspace: $workspace, - sourceTenant: $selection->sourceTenant, - targetTenant: $selection->targetTenant, + sourceEnvironment: $selection->sourceEnvironment, + targetEnvironment: $selection->targetEnvironment, operationRun: $run->fresh() ?? $run, plan: $plan, actor: $actor, @@ -149,10 +149,10 @@ public function start( return ProviderOperationStartResult::started($run->fresh() ?? $run, true); } - private function defaultProviderConnection(int $tenantId): ?ProviderConnection + private function defaultProviderConnection(int $environmentId): ?ProviderConnection { return ProviderConnection::query() - ->where('managed_environment_id', $tenantId) + ->where('managed_environment_id', $environmentId) ->where('provider', 'microsoft') ->where('is_default', true) ->orderBy('id') diff --git a/apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php b/apps/platform/app/Services/PortfolioTriage/ManagedEnvironmentTriageReviewService.php similarity index 79% rename from apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php rename to apps/platform/app/Services/PortfolioTriage/ManagedEnvironmentTriageReviewService.php index 091c37f7..7cb5a5ad 100644 --- a/apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php +++ b/apps/platform/app/Services/PortfolioTriage/ManagedEnvironmentTriageReviewService.php @@ -5,19 +5,19 @@ namespace App\Services\PortfolioTriage; use App\Models\ManagedEnvironment; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; use App\Services\Audit\WorkspaceAuditLogger; use App\Support\Audit\AuditActionId; use App\Support\BackupHealth\TenantBackupHealthAssessment; -use App\Support\PortfolioTriage\TenantTriageReviewFingerprint; +use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewFingerprint; use Illuminate\Support\Facades\DB; use InvalidArgumentException; -final readonly class TenantTriageReviewService +final readonly class ManagedEnvironmentTriageReviewService { public function __construct( - private TenantTriageReviewFingerprint $fingerprints, + private ManagedEnvironmentTriageReviewFingerprint $fingerprints, private WorkspaceAuditLogger $auditLogger, ) {} @@ -30,11 +30,11 @@ public function markReviewed( ?TenantBackupHealthAssessment $backupHealth = null, ?array $recoveryEvidence = null, ?User $actor = null, - ): TenantTriageReview { + ): ManagedEnvironmentTriageReview { return $this->store( tenant: $tenant, concernFamily: $concernFamily, - manualState: TenantTriageReview::STATE_REVIEWED, + manualState: ManagedEnvironmentTriageReview::STATE_REVIEWED, backupHealth: $backupHealth, recoveryEvidence: $recoveryEvidence, actor: $actor, @@ -50,11 +50,11 @@ public function markFollowUpNeeded( ?TenantBackupHealthAssessment $backupHealth = null, ?array $recoveryEvidence = null, ?User $actor = null, - ): TenantTriageReview { + ): ManagedEnvironmentTriageReview { return $this->store( tenant: $tenant, concernFamily: $concernFamily, - manualState: TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + manualState: ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, backupHealth: $backupHealth, recoveryEvidence: $recoveryEvidence, actor: $actor, @@ -71,8 +71,8 @@ private function store( ?TenantBackupHealthAssessment $backupHealth, ?array $recoveryEvidence, ?User $actor, - ): TenantTriageReview { - if (! in_array($manualState, TenantTriageReview::MANUAL_STATES, true)) { + ): ManagedEnvironmentTriageReview { + if (! in_array($manualState, ManagedEnvironmentTriageReview::MANUAL_STATES, true)) { throw new InvalidArgumentException('Unsupported triage review state.'); } @@ -89,7 +89,7 @@ private function store( $workspaceId = (int) $tenant->workspace_id; $now = now(); - /** @var TenantTriageReview $review */ + /** @var ManagedEnvironmentTriageReview $review */ $review = DB::transaction(function () use ( $tenant, $workspaceId, @@ -97,8 +97,8 @@ private function store( $currentConcern, $actor, $now, - ): TenantTriageReview { - TenantTriageReview::query() + ): ManagedEnvironmentTriageReview { + ManagedEnvironmentTriageReview::query() ->forWorkspace($workspaceId) ->forTenant((int) $tenant->getKey()) ->where('concern_family', $currentConcern['concern_family']) @@ -108,7 +108,7 @@ private function store( 'updated_at' => $now, ]); - return TenantTriageReview::query()->create([ + return ManagedEnvironmentTriageReview::query()->create([ 'workspace_id' => $workspaceId, 'managed_environment_id' => (int) $tenant->getKey(), 'concern_family' => $currentConcern['concern_family'], @@ -126,9 +126,9 @@ private function store( $this->auditLogger->log( workspace: $tenant->workspace, - action: $manualState === TenantTriageReview::STATE_REVIEWED - ? AuditActionId::TenantTriageReviewMarkedReviewed - : AuditActionId::TenantTriageReviewMarkedFollowUpNeeded, + action: $manualState === ManagedEnvironmentTriageReview::STATE_REVIEWED + ? AuditActionId::ManagedEnvironmentTriageReviewMarkedReviewed + : AuditActionId::ManagedEnvironmentTriageReviewMarkedFollowUpNeeded, context: [ 'metadata' => [ 'concern_family' => $currentConcern['concern_family'], @@ -138,7 +138,7 @@ private function store( ], ], actor: $actor, - resourceType: 'tenant_triage_review', + resourceType: 'managed_environment_triage_review', resourceId: (string) $review->getKey(), targetLabel: $tenant->name, tenant: $tenant, @@ -156,7 +156,7 @@ private function summaryFor(string $concernFamily, string $manualState): string default => 'Portfolio concern', }; - $state = $manualState === TenantTriageReview::STATE_REVIEWED + $state = $manualState === ManagedEnvironmentTriageReview::STATE_REVIEWED ? 'reviewed' : 'follow-up needed'; diff --git a/apps/platform/app/Services/ReviewPackService.php b/apps/platform/app/Services/ReviewPackService.php index 05119abb..e323839c 100644 --- a/apps/platform/app/Services/ReviewPackService.php +++ b/apps/platform/app/Services/ReviewPackService.php @@ -11,7 +11,7 @@ use App\Models\OperationRun; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Services\Audit\WorkspaceAuditLogger; use App\Services\Entitlements\WorkspaceCommercialLifecycleResolver; @@ -136,7 +136,7 @@ public function generate(ManagedEnvironment $tenant, User $user, array $options * * @param array $options */ - public function generateFromReview(TenantReview $review, User $user, array $options = []): ReviewPack + public function generateFromReview(EnvironmentReview $review, User $user, array $options = []): ReviewPack { $review->loadMissing(['tenant', 'evidenceSnapshot', 'sections']); @@ -155,7 +155,7 @@ public function generateFromReview(TenantReview $review, User $user, array $opti if ($existing instanceof ReviewPack) { $this->logReviewExport($review, $user, $existing, 'reused'); - $this->recordReviewPackRequestTelemetry($existing, $user, 'tenant_review'); + $this->recordReviewPackRequestTelemetry($existing, $user, 'environment_review'); return $existing; } @@ -164,7 +164,7 @@ public function generateFromReview(TenantReview $review, User $user, array $opti tenant: $tenant, type: OperationRunType::ReviewPackGenerate->value, inputs: [ - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'include_pii' => $options['include_pii'], 'include_operations' => $options['include_operations'], 'evidence_snapshot_id' => (int) $snapshot->getKey(), @@ -177,7 +177,7 @@ public function generateFromReview(TenantReview $review, User $user, array $opti if ($queuedPack instanceof ReviewPack) { $this->logReviewExport($review, $user, $queuedPack, 'reused_active_run'); - $this->recordReviewPackRequestTelemetry($queuedPack, $user, 'tenant_review'); + $this->recordReviewPackRequestTelemetry($queuedPack, $user, 'environment_review'); return $queuedPack; } @@ -186,14 +186,14 @@ public function generateFromReview(TenantReview $review, User $user, array $opti $reviewPack = ReviewPack::create([ 'managed_environment_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'operation_run_id' => (int) $operationRun->getKey(), 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'status' => ReviewPackStatus::Queued->value, 'options' => $options, 'summary' => [ - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'review_status' => (string) $review->status, 'review_completeness_state' => (string) $review->completeness_state, 'section_count' => $review->sections->count(), @@ -226,7 +226,7 @@ public function generateFromReview(TenantReview $review, User $user, array $opti }); $this->logReviewExport($review, $user, $reviewPack, 'queued'); - $this->recordReviewPackRequestTelemetry($reviewPack, $user, 'tenant_review'); + $this->recordReviewPackRequestTelemetry($reviewPack, $user, 'environment_review'); return $reviewPack; } @@ -308,10 +308,10 @@ public function findExistingPack(ManagedEnvironment $tenant, string $fingerprint ->first(); } - public function findExistingPackForReview(TenantReview $review, string $fingerprint): ?ReviewPack + public function findExistingPackForReview(EnvironmentReview $review, string $fingerprint): ?ReviewPack { return ReviewPack::query() - ->where('tenant_review_id', (int) $review->getKey()) + ->where('environment_review_id', (int) $review->getKey()) ->ready() ->where('fingerprint', $fingerprint) ->where('expires_at', '>', now()) @@ -330,12 +330,12 @@ public function checkActiveRun(ManagedEnvironment $tenant): bool ->exists(); } - public function checkActiveRunForReview(TenantReview $review): bool + public function checkActiveRunForReview(EnvironmentReview $review): bool { return OperationRun::query() ->where('managed_environment_id', (int) $review->managed_environment_id) ->where('type', OperationRunType::ReviewPackGenerate->value) - ->whereJsonContains('context->tenant_review_id', (int) $review->getKey()) + ->whereJsonContains('context->environment_review_id', (int) $review->getKey()) ->active() ->exists(); } @@ -376,10 +376,10 @@ private function computeFingerprintForSnapshot(EvidenceSnapshot $snapshot, array return hash('sha256', json_encode($data, JSON_THROW_ON_ERROR)); } - public function computeFingerprintForReview(TenantReview $review, array $options): string + public function computeFingerprintForReview(EnvironmentReview $review, array $options): string { $data = [ - 'tenant_review_id' => (int) $review->getKey(), + 'environment_review_id' => (int) $review->getKey(), 'review_fingerprint' => (string) $review->fingerprint, 'review_status' => (string) $review->status, 'delivery_contract' => self::REVIEW_DERIVED_DELIVERY_CONTRACT, @@ -414,7 +414,7 @@ private function findPackForRun(ManagedEnvironment $tenant, OperationRun $operat ->first(); } - private function logReviewExport(TenantReview $review, User $user, ReviewPack $reviewPack, string $mode): void + private function logReviewExport(EnvironmentReview $review, User $user, ReviewPack $reviewPack, string $mode): void { $tenant = $review->tenant; @@ -424,7 +424,7 @@ private function logReviewExport(TenantReview $review, User $user, ReviewPack $r $this->auditLogger->log( workspace: $tenant->workspace, - action: AuditActionId::TenantReviewExported, + action: AuditActionId::EnvironmentReviewExported, context: [ 'metadata' => [ 'review_id' => (int) $review->getKey(), @@ -434,7 +434,7 @@ private function logReviewExport(TenantReview $review, User $user, ReviewPack $r ], ], actor: $user, - resourceType: 'tenant_review', + resourceType: 'environment_review', resourceId: (string) $review->getKey(), targetLabel: sprintf('ManagedEnvironment review #%d', (int) $review->getKey()), operationRunId: $reviewPack->operation_run_id, diff --git a/apps/platform/app/Services/SystemConsole/OperationRunTriageService.php b/apps/platform/app/Services/SystemConsole/OperationRunTriageService.php index 97fac7d4..84f6184d 100644 --- a/apps/platform/app/Services/SystemConsole/OperationRunTriageService.php +++ b/apps/platform/app/Services/SystemConsole/OperationRunTriageService.php @@ -19,8 +19,8 @@ final class OperationRunTriageService 'directory.groups.sync', 'rbac.health_check', 'entra.admin_roles.scan', - 'tenant.review_pack.generate', - 'tenant.review.compose', + 'environment.review_pack.generate', + 'environment.review.compose', ]; private const CANCELABLE_TYPES = [ @@ -29,8 +29,8 @@ final class OperationRunTriageService 'directory.groups.sync', 'rbac.health_check', 'entra.admin_roles.scan', - 'tenant.review_pack.generate', - 'tenant.review.compose', + 'environment.review_pack.generate', + 'environment.review.compose', ]; public function __construct( diff --git a/apps/platform/app/Services/Tenants/TenantActionPolicySurface.php b/apps/platform/app/Services/Tenants/TenantActionPolicySurface.php index ee7e1acb..d7623c02 100644 --- a/apps/platform/app/Services/Tenants/TenantActionPolicySurface.php +++ b/apps/platform/app/Services/Tenants/TenantActionPolicySurface.php @@ -5,7 +5,7 @@ namespace App\Services\Tenants; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Services\Onboarding\OnboardingLifecycleService; use App\Support\Audit\AuditActionId; @@ -38,7 +38,7 @@ public function buildContext(ManagedEnvironment $tenant, TenantActionSurface $su $workspaceId = request() !== null ? $this->workspaceContext->currentWorkspaceId(request()) : null; - $resumeOutcome = $draft instanceof TenantOnboardingSession + $resumeOutcome = $draft instanceof ManagedEnvironmentOnboardingSession ? $this->tenantOperabilityService->outcomeFor( tenant: $tenant, question: TenantOperabilityQuestion::ResumeOnboardingEligibility, @@ -58,7 +58,7 @@ public function buildContext(ManagedEnvironment $tenant, TenantActionSurface $su lane: $lane, relatedOnboardingDraft: $draft, relatedOnboardingIsResumable: $resumeOutcome?->allowed ?? false, - hasRelatedOnboardingDraft: $draft instanceof TenantOnboardingSession, + hasRelatedOnboardingDraft: $draft instanceof ManagedEnvironmentOnboardingSession, isArchived: $lifecycle->canRestore(), ); } @@ -130,7 +130,7 @@ public function onboardingEntryDescriptor(int $resumableDraftCount): TenantActio }; } - public function relatedOnboardingDraft(ManagedEnvironment $tenant, ?User $user = null): ?TenantOnboardingSession + public function relatedOnboardingDraft(ManagedEnvironment $tenant, ?User $user = null): ?ManagedEnvironmentOnboardingSession { $user ??= auth()->user(); @@ -138,12 +138,12 @@ public function relatedOnboardingDraft(ManagedEnvironment $tenant, ?User $user = return null; } - return TenantOnboardingSession::query() + return ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $tenant->workspace_id) ->where('managed_environment_id', (int) $tenant->getKey()) ->orderByDesc('updated_at') ->get() - ->first(fn (TenantOnboardingSession $draft): bool => Gate::forUser($user)->allows('view', $draft)); + ->first(fn (ManagedEnvironmentOnboardingSession $draft): bool => Gate::forUser($user)->allows('view', $draft)); } private function viewAction(): TenantActionDescriptor @@ -267,7 +267,7 @@ private function relatedOnboardingActionForContext( ): ?TenantActionDescriptor { $draft = $context->relatedOnboardingDraft; - if (! $draft instanceof TenantOnboardingSession) { + if (! $draft instanceof ManagedEnvironmentOnboardingSession) { return null; } diff --git a/apps/platform/app/Services/Tenants/TenantOperabilityService.php b/apps/platform/app/Services/Tenants/TenantOperabilityService.php index be72ac51..560a9557 100644 --- a/apps/platform/app/Services/Tenants/TenantOperabilityService.php +++ b/apps/platform/app/Services/Tenants/TenantOperabilityService.php @@ -5,7 +5,7 @@ namespace App\Services\Tenants; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Services\Auth\CapabilityResolver; use App\Support\ReasonTranslation\ReasonResolutionEnvelope; @@ -186,7 +186,7 @@ public function outcomeFor( ?User $actor = null, ?int $workspaceId = null, TenantInteractionLane $lane = TenantInteractionLane::AdministrativeManagement, - ?TenantOnboardingSession $onboardingDraft = null, + ?ManagedEnvironmentOnboardingSession $onboardingDraft = null, ?string $requiredCapability = null, ?ManagedEnvironment $selectedTenant = null, ?string $linkedRecordType = null, @@ -478,7 +478,7 @@ private function resumeOnboardingOutcome(TenantOperabilityContext $context, Tena ); } - if ($context->onboardingDraft instanceof TenantOnboardingSession && ! $context->onboardingDraft->isWorkflowResumable()) { + if ($context->onboardingDraft instanceof ManagedEnvironmentOnboardingSession && ! $context->onboardingDraft->isWorkflowResumable()) { return TenantOperabilityOutcome::deny( question: TenantOperabilityQuestion::ResumeOnboardingEligibility, lifecycle: $lifecycle, diff --git a/apps/platform/app/Support/Audit/AuditActionId.php b/apps/platform/app/Support/Audit/AuditActionId.php index e44c0f5a..6d57c49b 100644 --- a/apps/platform/app/Support/Audit/AuditActionId.php +++ b/apps/platform/app/Support/Audit/AuditActionId.php @@ -34,19 +34,19 @@ enum AuditActionId: string case PolicyProviderMissingDetected = 'policy.provider_missing_detected'; case PolicyProviderMissingCleared = 'policy.provider_missing_cleared'; - // Managed tenant onboarding wizard. - case ManagedTenantOnboardingStart = 'managed_tenant_onboarding.start'; - case ManagedTenantOnboardingResume = 'managed_tenant_onboarding.resume'; - case ManagedTenantOnboardingDraftSelected = 'managed_tenant_onboarding.draft_selected'; - case ManagedTenantOnboardingDraftUpdated = 'managed_tenant_onboarding.draft_updated'; - case ManagedTenantOnboardingProviderConnectionChanged = 'managed_tenant_onboarding.provider_connection_changed'; - case ManagedTenantOnboardingVerificationStart = 'managed_tenant_onboarding.verification_start'; - case ManagedTenantOnboardingVerificationPersisted = 'managed_tenant_onboarding.verification_persisted'; - case ManagedTenantOnboardingBootstrapStarted = 'managed_tenant_onboarding.bootstrap_started'; - case ManagedTenantOnboardingCancelled = 'managed_tenant_onboarding.cancelled'; - case ManagedTenantOnboardingDeleted = 'managed_tenant_onboarding.deleted'; - case ManagedTenantOnboardingActivationOverrideUsed = 'managed_tenant_onboarding.activation_override_used'; - case ManagedTenantOnboardingActivation = 'managed_tenant_onboarding.activation'; + // Managed environment onboarding wizard. + case ManagedEnvironmentOnboardingStart = 'managed_environment_onboarding.start'; + case ManagedEnvironmentOnboardingResume = 'managed_environment_onboarding.resume'; + case ManagedEnvironmentOnboardingDraftSelected = 'managed_environment_onboarding.draft_selected'; + case ManagedEnvironmentOnboardingDraftUpdated = 'managed_environment_onboarding.draft_updated'; + case ManagedEnvironmentOnboardingProviderConnectionChanged = 'managed_environment_onboarding.provider_connection_changed'; + case ManagedEnvironmentOnboardingVerificationStart = 'managed_environment_onboarding.verification_start'; + case ManagedEnvironmentOnboardingVerificationPersisted = 'managed_environment_onboarding.verification_persisted'; + case ManagedEnvironmentOnboardingBootstrapStarted = 'managed_environment_onboarding.bootstrap_started'; + case ManagedEnvironmentOnboardingCancelled = 'managed_environment_onboarding.cancelled'; + case ManagedEnvironmentOnboardingDeleted = 'managed_environment_onboarding.deleted'; + case ManagedEnvironmentOnboardingActivationOverrideUsed = 'managed_environment_onboarding.activation_override_used'; + case ManagedEnvironmentOnboardingActivation = 'managed_environment_onboarding.activation'; case VerificationCompleted = 'verification.completed'; case VerificationCheckAcknowledged = 'verification.check_acknowledged'; @@ -79,9 +79,9 @@ enum AuditActionId: string case BaselineCompareStarted = 'baseline_compare.started'; case BaselineCompareCompleted = 'baseline_compare.completed'; case BaselineCompareFailed = 'baseline_compare.failed'; - case CrossTenantPromotionPreflightGenerated = 'cross_tenant_promotion_preflight.generated'; - case CrossTenantPromotionExecutionQueued = 'cross_tenant_promotion_execution.queued'; - case CrossTenantPromotionExecutionCompleted = 'cross_tenant_promotion_execution.completed'; + case CrossEnvironmentPromotionPreflightGenerated = 'cross_environment_promotion_preflight.generated'; + case CrossEnvironmentPromotionExecutionQueued = 'cross_environment_promotion_execution.queued'; + case CrossEnvironmentPromotionExecutionCompleted = 'cross_environment_promotion_execution.completed'; case BaselineAssignmentCreated = 'baseline_assignment.created'; case BaselineAssignmentUpdated = 'baseline_assignment.updated'; case BaselineAssignmentDeleted = 'baseline_assignment.deleted'; @@ -104,17 +104,17 @@ enum AuditActionId: string case EvidenceSnapshotRefreshed = 'evidence_snapshot.refreshed'; case EvidenceSnapshotExpired = 'evidence_snapshot.expired'; case EvidenceSnapshotOpened = 'evidence_snapshot.opened'; - case TenantReviewCreated = 'tenant_review.created'; - case TenantReviewRefreshed = 'tenant_review.refreshed'; - case TenantReviewPublished = 'tenant_review.published'; - case TenantReviewArchived = 'tenant_review.archived'; - case TenantReviewOpened = 'tenant_review.opened'; - case TenantReviewExported = 'tenant_review.exported'; - case TenantReviewSuccessorCreated = 'tenant_review.successor_created'; + case EnvironmentReviewCreated = 'environment_review.created'; + case EnvironmentReviewRefreshed = 'environment_review.refreshed'; + case EnvironmentReviewPublished = 'environment_review.published'; + case EnvironmentReviewArchived = 'environment_review.archived'; + case EnvironmentReviewOpened = 'environment_review.opened'; + case EnvironmentReviewExported = 'environment_review.exported'; + case EnvironmentReviewSuccessorCreated = 'environment_review.successor_created'; case CustomerReviewWorkspaceOpened = 'customer_review_workspace.opened'; case ReviewPackDownloaded = 'review_pack.downloaded'; - case TenantTriageReviewMarkedReviewed = 'tenant_triage_review.marked_reviewed'; - case TenantTriageReviewMarkedFollowUpNeeded = 'tenant_triage_review.marked_follow_up_needed'; + case ManagedEnvironmentTriageReviewMarkedReviewed = 'managed_environment_triage_review.marked_reviewed'; + case ManagedEnvironmentTriageReviewMarkedFollowUpNeeded = 'managed_environment_triage_review.marked_follow_up_needed'; case SupportDiagnosticsOpened = 'support_diagnostics.opened'; case SupportRequestCreated = 'support_request.created'; @@ -209,18 +209,18 @@ private static function labels(): array self::ManagedEnvironmentAccessScopeRemove->value => 'ManagedEnvironment access scope removal', self::PolicyProviderMissingDetected->value => 'Policy provider missing detected', self::PolicyProviderMissingCleared->value => 'Policy provider missing cleared', - self::ManagedTenantOnboardingStart->value => 'Managed tenant onboarding start', - self::ManagedTenantOnboardingResume->value => 'Managed tenant onboarding resume', - self::ManagedTenantOnboardingDraftSelected->value => 'Managed tenant onboarding draft selected', - self::ManagedTenantOnboardingDraftUpdated->value => 'Managed tenant onboarding draft updated', - self::ManagedTenantOnboardingProviderConnectionChanged->value => 'Managed tenant onboarding provider connection changed', - self::ManagedTenantOnboardingVerificationStart->value => 'Managed tenant onboarding verification start', - self::ManagedTenantOnboardingVerificationPersisted->value => 'Managed tenant onboarding verification persisted', - self::ManagedTenantOnboardingBootstrapStarted->value => 'Managed tenant onboarding bootstrap started', - self::ManagedTenantOnboardingCancelled->value => 'Managed tenant onboarding cancelled', - self::ManagedTenantOnboardingDeleted->value => 'Managed tenant onboarding deleted', - self::ManagedTenantOnboardingActivationOverrideUsed->value => 'Managed tenant onboarding activation override used', - self::ManagedTenantOnboardingActivation->value => 'Managed tenant onboarding activation', + self::ManagedEnvironmentOnboardingStart->value => 'Managed environment onboarding start', + self::ManagedEnvironmentOnboardingResume->value => 'Managed environment onboarding resume', + self::ManagedEnvironmentOnboardingDraftSelected->value => 'Managed environment onboarding draft selected', + self::ManagedEnvironmentOnboardingDraftUpdated->value => 'Managed environment onboarding draft updated', + self::ManagedEnvironmentOnboardingProviderConnectionChanged->value => 'Managed environment onboarding provider connection changed', + self::ManagedEnvironmentOnboardingVerificationStart->value => 'Managed environment onboarding verification start', + self::ManagedEnvironmentOnboardingVerificationPersisted->value => 'Managed environment onboarding verification persisted', + self::ManagedEnvironmentOnboardingBootstrapStarted->value => 'Managed environment onboarding bootstrap started', + self::ManagedEnvironmentOnboardingCancelled->value => 'Managed environment onboarding cancelled', + self::ManagedEnvironmentOnboardingDeleted->value => 'Managed environment onboarding deleted', + self::ManagedEnvironmentOnboardingActivationOverrideUsed->value => 'Managed environment onboarding activation override used', + self::ManagedEnvironmentOnboardingActivation->value => 'Managed environment onboarding activation', self::VerificationCompleted->value => 'Verification completed', self::VerificationCheckAcknowledged->value => 'Verification check acknowledged', self::AlertDestinationCreated->value => 'Alert destination created', @@ -249,9 +249,9 @@ private static function labels(): array self::BaselineCompareStarted->value => 'Baseline compare started', self::BaselineCompareCompleted->value => 'Baseline compare completed', self::BaselineCompareFailed->value => 'Baseline compare failed', - self::CrossTenantPromotionPreflightGenerated->value => 'Cross-tenant promotion preflight generated', - self::CrossTenantPromotionExecutionQueued->value => 'Cross-tenant promotion execution queued', - self::CrossTenantPromotionExecutionCompleted->value => 'Cross-tenant promotion execution completed', + self::CrossEnvironmentPromotionPreflightGenerated->value => 'Cross-environment promotion preflight generated', + self::CrossEnvironmentPromotionExecutionQueued->value => 'Cross-environment promotion execution queued', + self::CrossEnvironmentPromotionExecutionCompleted->value => 'Cross-environment promotion execution completed', self::BaselineAssignmentCreated->value => 'Baseline assignment created', self::BaselineAssignmentUpdated->value => 'Baseline assignment updated', self::BaselineAssignmentDeleted->value => 'Baseline assignment deleted', @@ -274,17 +274,17 @@ private static function labels(): array self::EvidenceSnapshotRefreshed->value => 'Evidence snapshot refreshed', self::EvidenceSnapshotExpired->value => 'Evidence snapshot expired', self::EvidenceSnapshotOpened->value => 'Evidence snapshot opened', - self::TenantReviewCreated->value => 'ManagedEnvironment review created', - self::TenantReviewRefreshed->value => 'ManagedEnvironment review refreshed', - self::TenantReviewPublished->value => 'ManagedEnvironment review published', - self::TenantReviewArchived->value => 'ManagedEnvironment review archived', - self::TenantReviewOpened->value => 'ManagedEnvironment review opened', - self::TenantReviewExported->value => 'ManagedEnvironment review exported', - self::TenantReviewSuccessorCreated->value => 'ManagedEnvironment review next cycle created', + self::EnvironmentReviewCreated->value => 'ManagedEnvironment review created', + self::EnvironmentReviewRefreshed->value => 'ManagedEnvironment review refreshed', + self::EnvironmentReviewPublished->value => 'ManagedEnvironment review published', + self::EnvironmentReviewArchived->value => 'ManagedEnvironment review archived', + self::EnvironmentReviewOpened->value => 'ManagedEnvironment review opened', + self::EnvironmentReviewExported->value => 'ManagedEnvironment review exported', + self::EnvironmentReviewSuccessorCreated->value => 'ManagedEnvironment review next cycle created', self::CustomerReviewWorkspaceOpened->value => 'Customer review workspace opened', self::ReviewPackDownloaded->value => 'Review pack downloaded', - self::TenantTriageReviewMarkedReviewed->value => 'Triage review marked reviewed', - self::TenantTriageReviewMarkedFollowUpNeeded->value => 'Triage review marked follow-up needed', + self::ManagedEnvironmentTriageReviewMarkedReviewed->value => 'Triage review marked reviewed', + self::ManagedEnvironmentTriageReviewMarkedFollowUpNeeded->value => 'Triage review marked follow-up needed', self::SupportDiagnosticsOpened->value => 'Support diagnostics opened', self::SupportRequestCreated->value => 'Support request created', self::SupportRequestExternalTicketCreated->value => 'Support request external ticket created', @@ -362,9 +362,9 @@ private static function summaries(): array self::BaselineProfileUpdated->value => 'Baseline profile updated', self::BaselineProfileArchived->value => 'Baseline profile archived', self::BaselineProfileScopeBackfilled->value => 'Baseline profile scope backfilled', - self::CrossTenantPromotionPreflightGenerated->value => 'Cross-tenant promotion preflight generated', - self::CrossTenantPromotionExecutionQueued->value => 'Cross-tenant promotion execution queued', - self::CrossTenantPromotionExecutionCompleted->value => 'Cross-tenant promotion execution completed', + self::CrossEnvironmentPromotionPreflightGenerated->value => 'Cross-environment promotion preflight generated', + self::CrossEnvironmentPromotionExecutionQueued->value => 'Cross-environment promotion execution queued', + self::CrossEnvironmentPromotionExecutionCompleted->value => 'Cross-environment promotion execution completed', self::AlertDestinationCreated->value => 'Alert destination created', self::AlertDestinationUpdated->value => 'Alert destination updated', self::AlertDestinationDeleted->value => 'Alert destination deleted', @@ -388,13 +388,13 @@ private static function summaries(): array self::EvidenceSnapshotRefreshed->value => 'Evidence snapshot refreshed', self::EvidenceSnapshotExpired->value => 'Evidence snapshot expired', self::EvidenceSnapshotOpened->value => 'Evidence snapshot opened', - self::TenantReviewCreated->value => 'ManagedEnvironment review created', - self::TenantReviewRefreshed->value => 'ManagedEnvironment review refreshed', - self::TenantReviewPublished->value => 'ManagedEnvironment review published', - self::TenantReviewArchived->value => 'ManagedEnvironment review archived', - self::TenantReviewOpened->value => 'ManagedEnvironment review opened', - self::TenantReviewExported->value => 'ManagedEnvironment review exported', - self::TenantReviewSuccessorCreated->value => 'ManagedEnvironment review next cycle created', + self::EnvironmentReviewCreated->value => 'ManagedEnvironment review created', + self::EnvironmentReviewRefreshed->value => 'ManagedEnvironment review refreshed', + self::EnvironmentReviewPublished->value => 'ManagedEnvironment review published', + self::EnvironmentReviewArchived->value => 'ManagedEnvironment review archived', + self::EnvironmentReviewOpened->value => 'ManagedEnvironment review opened', + self::EnvironmentReviewExported->value => 'ManagedEnvironment review exported', + self::EnvironmentReviewSuccessorCreated->value => 'ManagedEnvironment review next cycle created', self::CustomerReviewWorkspaceOpened->value => 'Customer review workspace opened', self::ReviewPackDownloaded->value => 'Review pack downloaded', self::SupportDiagnosticsOpened->value => 'Support diagnostics opened', diff --git a/apps/platform/app/Support/Auth/Capabilities.php b/apps/platform/app/Support/Auth/Capabilities.php index 1eb49347..8623eabf 100644 --- a/apps/platform/app/Support/Auth/Capabilities.php +++ b/apps/platform/app/Support/Auth/Capabilities.php @@ -27,28 +27,28 @@ class Capabilities public const WORKSPACE_MEMBERSHIP_MANAGE = 'workspace_membership.manage'; - // Managed tenant onboarding - public const WORKSPACE_MANAGED_TENANT_ONBOARD = 'workspace_managed_tenant.onboard'; + // Managed environment onboarding + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD = 'workspace_managed_environment.onboard'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_IDENTIFY = 'workspace_managed_tenant.onboard.identify'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_IDENTIFY = 'workspace_managed_environment.onboard.identify'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_CANCEL = 'workspace_managed_tenant.onboard.cancel'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CANCEL = 'workspace_managed_environment.onboard.cancel'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_VIEW = 'workspace_managed_tenant.onboard.connection.view'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_VIEW = 'workspace_managed_environment.onboard.connection.view'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE = 'workspace_managed_tenant.onboard.connection.manage'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE = 'workspace_managed_environment.onboard.connection.manage'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_CONNECTION_MANAGE_DEDICATED = 'workspace_managed_tenant.onboard.connection.manage_dedicated'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_CONNECTION_MANAGE_DEDICATED = 'workspace_managed_environment.onboard.connection.manage_dedicated'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_VERIFICATION_START = 'workspace_managed_tenant.onboard.verification.start'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_VERIFICATION_START = 'workspace_managed_environment.onboard.verification.start'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC = 'workspace_managed_tenant.onboard.bootstrap.inventory_sync'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_INVENTORY_SYNC = 'workspace_managed_environment.onboard.bootstrap.inventory_sync'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_POLICY_SYNC = 'workspace_managed_tenant.onboard.bootstrap.policy_sync'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_POLICY_SYNC = 'workspace_managed_environment.onboard.bootstrap.policy_sync'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP = 'workspace_managed_tenant.onboard.bootstrap.backup_bootstrap'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_BOOTSTRAP_BACKUP_BOOTSTRAP = 'workspace_managed_environment.onboard.bootstrap.backup_bootstrap'; - public const WORKSPACE_MANAGED_TENANT_ONBOARD_ACTIVATE = 'workspace_managed_tenant.onboard.activate'; + public const WORKSPACE_MANAGED_ENVIRONMENT_ONBOARD_ACTIVATE = 'workspace_managed_environment.onboard.activate'; // Workspace settings public const WORKSPACE_SETTINGS_VIEW = 'workspace_settings.view'; @@ -146,12 +146,12 @@ class Capabilities public const REVIEW_PACK_MANAGE = 'review_pack.manage'; // ManagedEnvironment reviews - public const TENANT_REVIEW_VIEW = 'tenant_review.view'; + public const ENVIRONMENT_REVIEW_VIEW = 'environment_review.view'; - public const TENANT_REVIEW_MANAGE = 'tenant_review.manage'; + public const ENVIRONMENT_REVIEW_MANAGE = 'environment_review.manage'; // Portfolio triage review progress - public const TENANT_TRIAGE_REVIEW_MANAGE = 'tenant_triage_review.manage'; + public const MANAGED_ENVIRONMENT_TRIAGE_REVIEW_MANAGE = 'managed_environment_triage_review.manage'; // Evidence snapshots public const EVIDENCE_VIEW = 'evidence.view'; diff --git a/apps/platform/app/Support/Badges/BadgeCatalog.php b/apps/platform/app/Support/Badges/BadgeCatalog.php index a21eea57..1ded200b 100644 --- a/apps/platform/app/Support/Badges/BadgeCatalog.php +++ b/apps/platform/app/Support/Badges/BadgeCatalog.php @@ -42,7 +42,7 @@ final class BadgeCatalog BadgeDomain::TenantStatus->value => Domains\TenantStatusBadge::class, BadgeDomain::TenantWorkspacePosture->value => Domains\TenantWorkspacePostureBadge::class, BadgeDomain::TenantRbacStatus->value => Domains\TenantRbacStatusBadge::class, - BadgeDomain::TenantPermissionStatus->value => Domains\TenantPermissionStatusBadge::class, + BadgeDomain::ManagedEnvironmentPermissionStatus->value => Domains\ManagedEnvironmentPermissionStatusBadge::class, BadgeDomain::PolicySnapshotMode->value => Domains\PolicySnapshotModeBadge::class, BadgeDomain::PolicyRestoreMode->value => Domains\PolicyRestoreModeBadge::class, BadgeDomain::PolicyRisk->value => Domains\PolicyRiskBadge::class, @@ -53,7 +53,7 @@ final class BadgeCatalog BadgeDomain::ProviderConsentStatus->value => Domains\ProviderConsentStatusBadge::class, BadgeDomain::ProviderVerificationStatus->value => Domains\ProviderVerificationStatusBadge::class, BadgeDomain::ProviderCapabilityStatus->value => Domains\ProviderCapabilityStatusBadge::class, - BadgeDomain::ManagedTenantOnboardingVerificationStatus->value => Domains\ManagedTenantOnboardingVerificationStatusBadge::class, + BadgeDomain::ManagedEnvironmentOnboardingVerificationStatus->value => Domains\ManagedEnvironmentOnboardingVerificationStatusBadge::class, BadgeDomain::VerificationCheckStatus->value => Domains\VerificationCheckStatusBadge::class, BadgeDomain::VerificationCheckSeverity->value => Domains\VerificationCheckSeverityBadge::class, BadgeDomain::VerificationReportOverall->value => Domains\VerificationReportOverallBadge::class, @@ -66,9 +66,9 @@ final class BadgeCatalog BadgeDomain::CommercialLifecycleState->value => Domains\CommercialLifecycleStateBadge::class, BadgeDomain::EvidenceSnapshotStatus->value => Domains\EvidenceSnapshotStatusBadge::class, BadgeDomain::EvidenceCompleteness->value => Domains\EvidenceCompletenessBadge::class, - BadgeDomain::TenantReviewStatus->value => Domains\TenantReviewStatusBadge::class, - BadgeDomain::TenantReviewCompleteness->value => Domains\TenantReviewCompletenessStateBadge::class, - BadgeDomain::TenantTriageReviewState->value => Domains\TenantTriageReviewStateBadge::class, + BadgeDomain::EnvironmentReviewStatus->value => Domains\EnvironmentReviewStatusBadge::class, + BadgeDomain::EnvironmentReviewCompleteness->value => Domains\EnvironmentReviewCompletenessStateBadge::class, + BadgeDomain::ManagedEnvironmentTriageReviewState->value => Domains\ManagedEnvironmentTriageReviewStateBadge::class, BadgeDomain::SystemHealth->value => Domains\SystemHealthBadge::class, BadgeDomain::ReferenceResolutionState->value => Domains\ReferenceResolutionStateBadge::class, BadgeDomain::DiffRowStatus->value => Domains\DiffRowStatusBadge::class, @@ -204,7 +204,7 @@ public static function normalizeProviderVerificationStatus(mixed $value): ?strin }; } - public static function normalizeManagedTenantOnboardingVerificationStatus(mixed $value): ?string + public static function normalizeManagedEnvironmentOnboardingVerificationStatus(mixed $value): ?string { $state = self::normalizeState($value); diff --git a/apps/platform/app/Support/Badges/BadgeDomain.php b/apps/platform/app/Support/Badges/BadgeDomain.php index c09ce245..c94de4d0 100644 --- a/apps/platform/app/Support/Badges/BadgeDomain.php +++ b/apps/platform/app/Support/Badges/BadgeDomain.php @@ -33,7 +33,7 @@ enum BadgeDomain: string case TenantStatus = 'tenant_status'; case TenantWorkspacePosture = 'tenant_workspace_posture'; case TenantRbacStatus = 'tenant_rbac_status'; - case TenantPermissionStatus = 'tenant_permission_status'; + case ManagedEnvironmentPermissionStatus = 'managed_environment_permission_status'; case PolicySnapshotMode = 'policy_snapshot_mode'; case PolicyRestoreMode = 'policy_restore_mode'; case PolicyRisk = 'policy_risk'; @@ -44,7 +44,7 @@ enum BadgeDomain: string case ProviderConsentStatus = 'provider_connection.consent_status'; case ProviderVerificationStatus = 'provider_connection.verification_status'; case ProviderCapabilityStatus = 'provider_capability_status'; - case ManagedTenantOnboardingVerificationStatus = 'managed_tenant_onboarding.verification_status'; + case ManagedEnvironmentOnboardingVerificationStatus = 'managed_environment_onboarding.verification_status'; case VerificationCheckStatus = 'verification_check_status'; case VerificationCheckSeverity = 'verification_check_severity'; case VerificationReportOverall = 'verification_report_overall'; @@ -57,9 +57,9 @@ enum BadgeDomain: string case CommercialLifecycleState = 'commercial_lifecycle_state'; case EvidenceSnapshotStatus = 'evidence_snapshot_status'; case EvidenceCompleteness = 'evidence_completeness'; - case TenantReviewStatus = 'tenant_review_status'; - case TenantReviewCompleteness = 'tenant_review_completeness'; - case TenantTriageReviewState = 'tenant_triage_review_state'; + case EnvironmentReviewStatus = 'environment_review_status'; + case EnvironmentReviewCompleteness = 'environment_review_completeness'; + case ManagedEnvironmentTriageReviewState = 'managed_environment_triage_review_state'; case SystemHealth = 'system_health'; case ReferenceResolutionState = 'reference_resolution_state'; case DiffRowStatus = 'diff_row_status'; diff --git a/apps/platform/app/Support/Badges/Domains/EnvironmentReviewCompletenessStateBadge.php b/apps/platform/app/Support/Badges/Domains/EnvironmentReviewCompletenessStateBadge.php new file mode 100644 index 00000000..5f23d8b5 --- /dev/null +++ b/apps/platform/app/Support/Badges/Domains/EnvironmentReviewCompletenessStateBadge.php @@ -0,0 +1,28 @@ +value => OperatorOutcomeTaxonomy::spec(BadgeDomain::EnvironmentReviewCompleteness, $state, 'heroicon-m-check-circle'), + EnvironmentReviewCompletenessState::Partial->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::EnvironmentReviewCompleteness, $state, 'heroicon-m-exclamation-triangle'), + EnvironmentReviewCompletenessState::Missing->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::EnvironmentReviewCompleteness, $state, 'heroicon-m-clock'), + EnvironmentReviewCompletenessState::Stale->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::EnvironmentReviewCompleteness, $state, 'heroicon-m-arrow-path'), + default => BadgeSpec::unknown(), + } ?? BadgeSpec::unknown(); + } +} diff --git a/apps/platform/app/Support/Badges/Domains/EnvironmentReviewStatusBadge.php b/apps/platform/app/Support/Badges/Domains/EnvironmentReviewStatusBadge.php new file mode 100644 index 00000000..6dd46901 --- /dev/null +++ b/apps/platform/app/Support/Badges/Domains/EnvironmentReviewStatusBadge.php @@ -0,0 +1,28 @@ +value => new BadgeSpec('Draft', 'gray', 'heroicon-m-pencil-square'), + EnvironmentReviewStatus::Ready->value => new BadgeSpec('Ready', 'info', 'heroicon-m-check-circle'), + EnvironmentReviewStatus::Published->value => new BadgeSpec('Published', 'success', 'heroicon-m-check-badge'), + EnvironmentReviewStatus::Archived->value => new BadgeSpec('Archived', 'gray', 'heroicon-m-archive-box'), + EnvironmentReviewStatus::Superseded->value => new BadgeSpec('Superseded', 'warning', 'heroicon-m-arrow-path'), + EnvironmentReviewStatus::Failed->value => new BadgeSpec('Failed', 'danger', 'heroicon-m-x-circle'), + default => BadgeSpec::unknown(), + }; + } +} diff --git a/apps/platform/app/Support/Badges/Domains/ManagedTenantOnboardingVerificationStatusBadge.php b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentOnboardingVerificationStatusBadge.php similarity index 80% rename from apps/platform/app/Support/Badges/Domains/ManagedTenantOnboardingVerificationStatusBadge.php rename to apps/platform/app/Support/Badges/Domains/ManagedEnvironmentOnboardingVerificationStatusBadge.php index b5eb2223..72cf0875 100644 --- a/apps/platform/app/Support/Badges/Domains/ManagedTenantOnboardingVerificationStatusBadge.php +++ b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentOnboardingVerificationStatusBadge.php @@ -6,11 +6,11 @@ use App\Support\Badges\BadgeMapper; use App\Support\Badges\BadgeSpec; -final class ManagedTenantOnboardingVerificationStatusBadge implements BadgeMapper +final class ManagedEnvironmentOnboardingVerificationStatusBadge implements BadgeMapper { public function spec(mixed $value): BadgeSpec { - $state = BadgeCatalog::normalizeManagedTenantOnboardingVerificationStatus($value); + $state = BadgeCatalog::normalizeManagedEnvironmentOnboardingVerificationStatus($value); return match ($state) { 'not_started' => new BadgeSpec('Not started', 'gray', 'heroicon-m-minus-circle'), diff --git a/apps/platform/app/Support/Badges/Domains/TenantPermissionStatusBadge.php b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentPermissionStatusBadge.php similarity index 89% rename from apps/platform/app/Support/Badges/Domains/TenantPermissionStatusBadge.php rename to apps/platform/app/Support/Badges/Domains/ManagedEnvironmentPermissionStatusBadge.php index 5b069680..c9423eef 100644 --- a/apps/platform/app/Support/Badges/Domains/TenantPermissionStatusBadge.php +++ b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentPermissionStatusBadge.php @@ -6,7 +6,7 @@ use App\Support\Badges\BadgeMapper; use App\Support\Badges\BadgeSpec; -final class TenantPermissionStatusBadge implements BadgeMapper +final class ManagedEnvironmentPermissionStatusBadge implements BadgeMapper { public function spec(mixed $value): BadgeSpec { diff --git a/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentTriageReviewStateBadge.php b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentTriageReviewStateBadge.php new file mode 100644 index 00000000..6ddf55ed --- /dev/null +++ b/apps/platform/app/Support/Badges/Domains/ManagedEnvironmentTriageReviewStateBadge.php @@ -0,0 +1,26 @@ + new BadgeSpec('Not reviewed', 'gray', 'heroicon-m-eye-slash'), + ManagedEnvironmentTriageReview::STATE_REVIEWED => new BadgeSpec('Reviewed', 'success', 'heroicon-m-check-circle'), + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED => new BadgeSpec('Follow-up needed', 'danger', 'heroicon-m-exclamation-triangle'), + ManagedEnvironmentTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW => new BadgeSpec('Changed since review', 'warning', 'heroicon-m-arrow-path'), + default => BadgeSpec::unknown(), + }; + } +} diff --git a/apps/platform/app/Support/Badges/Domains/TenantReviewCompletenessStateBadge.php b/apps/platform/app/Support/Badges/Domains/TenantReviewCompletenessStateBadge.php deleted file mode 100644 index f6f53439..00000000 --- a/apps/platform/app/Support/Badges/Domains/TenantReviewCompletenessStateBadge.php +++ /dev/null @@ -1,28 +0,0 @@ -value => OperatorOutcomeTaxonomy::spec(BadgeDomain::TenantReviewCompleteness, $state, 'heroicon-m-check-circle'), - TenantReviewCompletenessState::Partial->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::TenantReviewCompleteness, $state, 'heroicon-m-exclamation-triangle'), - TenantReviewCompletenessState::Missing->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::TenantReviewCompleteness, $state, 'heroicon-m-clock'), - TenantReviewCompletenessState::Stale->value => OperatorOutcomeTaxonomy::spec(BadgeDomain::TenantReviewCompleteness, $state, 'heroicon-m-arrow-path'), - default => BadgeSpec::unknown(), - } ?? BadgeSpec::unknown(); - } -} diff --git a/apps/platform/app/Support/Badges/Domains/TenantReviewStatusBadge.php b/apps/platform/app/Support/Badges/Domains/TenantReviewStatusBadge.php deleted file mode 100644 index 9a43942b..00000000 --- a/apps/platform/app/Support/Badges/Domains/TenantReviewStatusBadge.php +++ /dev/null @@ -1,28 +0,0 @@ -value => new BadgeSpec('Draft', 'gray', 'heroicon-m-pencil-square'), - TenantReviewStatus::Ready->value => new BadgeSpec('Ready', 'info', 'heroicon-m-check-circle'), - TenantReviewStatus::Published->value => new BadgeSpec('Published', 'success', 'heroicon-m-check-badge'), - TenantReviewStatus::Archived->value => new BadgeSpec('Archived', 'gray', 'heroicon-m-archive-box'), - TenantReviewStatus::Superseded->value => new BadgeSpec('Superseded', 'warning', 'heroicon-m-arrow-path'), - TenantReviewStatus::Failed->value => new BadgeSpec('Failed', 'danger', 'heroicon-m-x-circle'), - default => BadgeSpec::unknown(), - }; - } -} diff --git a/apps/platform/app/Support/Badges/Domains/TenantTriageReviewStateBadge.php b/apps/platform/app/Support/Badges/Domains/TenantTriageReviewStateBadge.php deleted file mode 100644 index 44074753..00000000 --- a/apps/platform/app/Support/Badges/Domains/TenantTriageReviewStateBadge.php +++ /dev/null @@ -1,26 +0,0 @@ - new BadgeSpec('Not reviewed', 'gray', 'heroicon-m-eye-slash'), - TenantTriageReview::STATE_REVIEWED => new BadgeSpec('Reviewed', 'success', 'heroicon-m-check-circle'), - TenantTriageReview::STATE_FOLLOW_UP_NEEDED => new BadgeSpec('Follow-up needed', 'danger', 'heroicon-m-exclamation-triangle'), - TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW => new BadgeSpec('Changed since review', 'warning', 'heroicon-m-arrow-path'), - default => BadgeSpec::unknown(), - }; - } -} diff --git a/apps/platform/app/Support/Badges/OperatorOutcomeTaxonomy.php b/apps/platform/app/Support/Badges/OperatorOutcomeTaxonomy.php index 1bbb7e53..86259fa9 100644 --- a/apps/platform/app/Support/Badges/OperatorOutcomeTaxonomy.php +++ b/apps/platform/app/Support/Badges/OperatorOutcomeTaxonomy.php @@ -475,7 +475,7 @@ final class OperatorOutcomeTaxonomy 'notes' => 'Evidence exists but is old enough that the operator should refresh it before relying on it.', ], ], - 'tenant_review_completeness' => [ + 'environment_review_completeness' => [ 'complete' => [ 'axis' => 'data_coverage', 'label' => 'Review inputs ready', @@ -926,7 +926,7 @@ public static function curatedExamples(): array ['name' => 'Operation completed successfully', 'domain' => BadgeDomain::OperationRunOutcome, 'raw_value' => 'succeeded'], ['name' => 'Evidence not collected yet', 'domain' => BadgeDomain::EvidenceCompleteness, 'raw_value' => 'missing'], ['name' => 'Evidence refresh recommended', 'domain' => BadgeDomain::EvidenceCompleteness, 'raw_value' => 'stale'], - ['name' => 'Review input pending', 'domain' => BadgeDomain::TenantReviewCompleteness, 'raw_value' => 'missing'], + ['name' => 'Review input pending', 'domain' => BadgeDomain::EnvironmentReviewCompleteness, 'raw_value' => 'missing'], ['name' => 'Mixed evidence detail stays diagnostic', 'domain' => BadgeDomain::BaselineSnapshotFidelity, 'raw_value' => 'partial'], ['name' => 'Support limited stays diagnostic', 'domain' => BadgeDomain::BaselineSnapshotFidelity, 'raw_value' => 'unsupported'], ['name' => 'Coverage gaps need review', 'domain' => BadgeDomain::BaselineSnapshotGapStatus, 'raw_value' => 'gaps_present'], diff --git a/apps/platform/app/Support/CustomerHealth/WorkspaceHealthSummaryQuery.php b/apps/platform/app/Support/CustomerHealth/WorkspaceHealthSummaryQuery.php index 6ed3e281..a4de79bf 100644 --- a/apps/platform/app/Support/CustomerHealth/WorkspaceHealthSummaryQuery.php +++ b/apps/platform/app/Support/CustomerHealth/WorkspaceHealthSummaryQuery.php @@ -12,7 +12,7 @@ use App\Models\ProviderConnection; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\Workspace; use App\Support\Onboarding\OnboardingLifecycleState; use App\Support\OperationRunOutcome; @@ -78,7 +78,7 @@ public function summaries(SystemConsoleWindow|string|null $window = null, ?Carbo $tenantsByWorkspace = $activeTenants->groupBy(static fn (ManagedEnvironment $tenant): int => (int) $tenant->workspace_id); - $latestOnboardingSessions = TenantOnboardingSession::query() + $latestOnboardingSessions = ManagedEnvironmentOnboardingSession::query() ->whereIn('workspace_id', $workspaceIds) ->where(function (Builder $query): void { $this->constrainToActiveTenantTruth($query); @@ -86,8 +86,8 @@ public function summaries(SystemConsoleWindow|string|null $window = null, ?Carbo ->orderByDesc('updated_at') ->orderByDesc('id') ->get(['id', 'workspace_id', 'managed_environment_id', 'lifecycle_state', 'updated_at', 'created_at']) - ->groupBy(static fn (TenantOnboardingSession $session): int => (int) $session->workspace_id) - ->map(static fn (Collection $sessions): ?TenantOnboardingSession => $sessions->first()); + ->groupBy(static fn (ManagedEnvironmentOnboardingSession $session): int => (int) $session->workspace_id) + ->map(static fn (Collection $sessions): ?ManagedEnvironmentOnboardingSession => $sessions->first()); $providerConnectionsByWorkspace = ProviderConnection::query() ->whereIn('workspace_id', $workspaceIds) @@ -268,7 +268,7 @@ public function summaries(SystemConsoleWindow|string|null $window = null, ?Carbo $workspaceId = (int) $workspace->getKey(); /** @var Collection $workspaceTenants */ $workspaceTenants = $tenantsByWorkspace->get($workspaceId, collect()); - /** @var TenantOnboardingSession|null $latestOnboardingSession */ + /** @var ManagedEnvironmentOnboardingSession|null $latestOnboardingSession */ $latestOnboardingSession = $latestOnboardingSessions->get($workspaceId); /** @var Collection $providerConnections */ $providerConnections = $providerConnectionsByWorkspace->get($workspaceId, collect()); @@ -426,7 +426,7 @@ private function resolveWindow(SystemConsoleWindow|string|null $window): SystemC */ private function buildDimensions( Collection $tenants, - ?TenantOnboardingSession $latestOnboardingSession, + ?ManagedEnvironmentOnboardingSession $latestOnboardingSession, Collection $providerConnections, int $recentRunCount, int $recentFailedRunCount, @@ -473,9 +473,9 @@ private function buildDimensions( /** * @param Collection $tenants */ - private function onboardingReadinessLevel(Collection $tenants, ?TenantOnboardingSession $latestOnboardingSession): string + private function onboardingReadinessLevel(Collection $tenants, ?ManagedEnvironmentOnboardingSession $latestOnboardingSession): string { - if ($latestOnboardingSession instanceof TenantOnboardingSession) { + if ($latestOnboardingSession instanceof ManagedEnvironmentOnboardingSession) { return match ($latestOnboardingSession->lifecycleState()) { OnboardingLifecycleState::ReadyForActivation, OnboardingLifecycleState::Completed => 'ok', diff --git a/apps/platform/app/Support/TenantDashboard/TenantDashboardSummary.php b/apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummary.php similarity index 95% rename from apps/platform/app/Support/TenantDashboard/TenantDashboardSummary.php rename to apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummary.php index f2734846..0d61e5d7 100644 --- a/apps/platform/app/Support/TenantDashboard/TenantDashboardSummary.php +++ b/apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummary.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace App\Support\TenantDashboard; +namespace App\Support\EnvironmentDashboard; -final readonly class TenantDashboardSummary +final readonly class EnvironmentDashboardSummary { /** * @param array{workspace:string,tenant:string,provider:?string,providerKey:?string,latestActivity:?string} $context diff --git a/apps/platform/app/Support/TenantDashboard/TenantDashboardSummaryBuilder.php b/apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php similarity index 95% rename from apps/platform/app/Support/TenantDashboard/TenantDashboardSummaryBuilder.php rename to apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php index 02e13d9f..555aceb7 100644 --- a/apps/platform/app/Support/TenantDashboard/TenantDashboardSummaryBuilder.php +++ b/apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Support\TenantDashboard; +namespace App\Support\EnvironmentDashboard; use App\Filament\Pages\BaselineCompareLanding; use App\Filament\Pages\Reviews\CustomerReviewWorkspace; @@ -12,7 +12,7 @@ use App\Filament\Resources\FindingExceptionResource; use App\Filament\Resources\FindingResource; use App\Filament\Resources\ReviewPackResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\EvidenceSnapshot; use App\Models\Finding; use App\Models\FindingException; @@ -20,9 +20,9 @@ use App\Models\ProviderConnection; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; -use App\Services\Intune\TenantRequiredPermissionsViewModelBuilder; +use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder; use App\Support\Auth\Capabilities; use App\Support\Badges\BadgeDomain; use App\Support\Badges\BadgeRenderer; @@ -46,16 +46,16 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; -final class TenantDashboardSummaryBuilder +final class EnvironmentDashboardSummaryBuilder { public function __construct( private readonly TenantGovernanceAggregateResolver $tenantGovernanceAggregateResolver, private readonly TenantBackupHealthResolver $tenantBackupHealthResolver, private readonly RestoreSafetyResolver $restoreSafetyResolver, - private readonly TenantRequiredPermissionsViewModelBuilder $tenantRequiredPermissionsViewModelBuilder, + private readonly ManagedEnvironmentRequiredPermissionsViewModelBuilder $tenantRequiredPermissionsViewModelBuilder, ) {} - public function build(ManagedEnvironment $tenant, ?User $user = null): TenantDashboardSummary + public function build(ManagedEnvironment $tenant, ?User $user = null): EnvironmentDashboardSummary { $tenant->loadMissing('workspace', 'providerConnections'); @@ -70,7 +70,7 @@ public function build(ManagedEnvironment $tenant, ?User $user = null): TenantDas if ($request?->attributes->has($cacheKey)) { $cached = $request->attributes->get($cacheKey); - if ($cached instanceof TenantDashboardSummary) { + if ($cached instanceof EnvironmentDashboardSummary) { return $cached; } } @@ -84,7 +84,7 @@ public function build(ManagedEnvironment $tenant, ?User $user = null): TenantDas 'status' => 'missing', ]); - $latestReview = $this->latestTenantReview($tenant); + $latestReview = $this->latestEnvironmentReview($tenant); $latestReviewPack = $this->latestReviewPack($tenant); $latestEvidenceSnapshot = $this->latestEvidenceSnapshot($tenant); $exceptionStats = $this->exceptionStats($tenant); @@ -102,7 +102,7 @@ public function build(ManagedEnvironment $tenant, ?User $user = null): TenantDas exceptionStats: $exceptionStats, ); - $summary = new TenantDashboardSummary( + $summary = new EnvironmentDashboardSummary( context: [ 'workspace' => (string) ($tenant->workspace?->name ?? $this->overviewText('context_workspace')), 'tenant' => (string) $tenant->name, @@ -186,7 +186,7 @@ private function providerChipKey(?ProviderConnection $connection): ?string */ private function latestActivityLabel( ?ProviderConnection $primaryProviderConnection, - ?TenantReview $latestReview, + ?EnvironmentReview $latestReview, ?ReviewPack $latestReviewPack, ?EvidenceSnapshot $latestEvidenceSnapshot, array $recentOperations, @@ -207,7 +207,7 @@ private function latestActivityLabel( */ private function latestActivityTimestamp( ?ProviderConnection $primaryProviderConnection, - ?TenantReview $latestReview, + ?EnvironmentReview $latestReview, ?ReviewPack $latestReviewPack, ?EvidenceSnapshot $latestEvidenceSnapshot, array $recentOperations, @@ -243,9 +243,9 @@ private function latestActivityTimestamp( return $candidates[0]; } - private function latestTenantReview(ManagedEnvironment $tenant): ?TenantReview + private function latestEnvironmentReview(ManagedEnvironment $tenant): ?EnvironmentReview { - return TenantReview::query() + return EnvironmentReview::query() ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack']) ->where('managed_environment_id', (int) $tenant->getKey()) ->latest('generated_at') @@ -256,7 +256,7 @@ private function latestTenantReview(ManagedEnvironment $tenant): ?TenantReview private function latestReviewPack(ManagedEnvironment $tenant): ?ReviewPack { return ReviewPack::query() - ->with(['tenant', 'tenantReview']) + ->with(['tenant', 'environmentReview']) ->where('managed_environment_id', (int) $tenant->getKey()) ->latest('generated_at') ->latest('id') @@ -599,7 +599,7 @@ private function recommendedActions( TenantBackupHealthAssessment $backupHealth, array $recoveryEvidence, array $requiredPermissions, - ?TenantReview $latestReview, + ?EnvironmentReview $latestReview, ?ReviewPack $latestReviewPack, array $exceptionStats, ): array { @@ -714,7 +714,7 @@ private function recommendedActions( ); } - if ($latestReview instanceof TenantReview && $latestReviewPack?->status !== 'ready') { + if ($latestReview instanceof EnvironmentReview && $latestReviewPack?->status !== 'ready') { $candidates[] = $this->actionCandidate( priority: 80, key: 'continue_review', @@ -743,7 +743,7 @@ private function governanceStatus( TenantGovernanceAggregate $aggregate, TenantBackupHealthAssessment $backupHealth, array $requiredPermissions, - ?TenantReview $latestReview, + ?EnvironmentReview $latestReview, ?EvidenceSnapshot $latestEvidenceSnapshot, ): array { $overview = is_array($requiredPermissions['overview'] ?? null) @@ -782,7 +782,7 @@ private function governanceStatus( 'value' => $this->reviewValue($latestReview), 'tone' => $this->reviewTone($latestReview), 'description' => $this->reviewDescription($latestReview), - ...$this->tenantReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview), + ...$this->environmentReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview), ], [ 'key' => 'provider_permissions', @@ -815,7 +815,7 @@ private function readinessCards( ?User $user, ?ProviderConnection $primaryProviderConnection, array $requiredPermissions, - ?TenantReview $latestReview, + ?EnvironmentReview $latestReview, ?ReviewPack $latestReviewPack, ?EvidenceSnapshot $latestEvidenceSnapshot, array $exceptionStats, @@ -831,18 +831,18 @@ private function readinessCards( /** * @return array */ - private function currentReviewCard(ManagedEnvironment $tenant, ?User $user, ?TenantReview $latestReview): array + private function currentReviewCard(ManagedEnvironment $tenant, ?User $user, ?EnvironmentReview $latestReview): array { $timestamp = $latestReview?->published_at ?? $latestReview?->generated_at ?? $latestReview?->updated_at; return [ 'key' => 'current_review', 'title' => $this->overviewText('readiness_current_review_title'), - 'status' => $latestReview instanceof TenantReview + 'status' => $latestReview instanceof EnvironmentReview ? $this->reviewValue($latestReview) : $this->overviewText('readiness_current_review_empty_status'), - 'tone' => $latestReview instanceof TenantReview ? $this->reviewTone($latestReview) : 'gray', - 'body' => $latestReview instanceof TenantReview + 'tone' => $latestReview instanceof EnvironmentReview ? $this->reviewTone($latestReview) : 'gray', + 'body' => $latestReview instanceof EnvironmentReview ? $this->reviewDescription($latestReview) : $this->overviewText('readiness_current_review_empty_description'), 'progress' => $this->reviewProgress($latestReview), @@ -852,7 +852,7 @@ private function currentReviewCard(ManagedEnvironment $tenant, ?User $user, ?Ten $this->relativeTime($timestamp), ), ), - ...$this->tenantReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview), + ...$this->environmentReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview), ]; } @@ -1061,8 +1061,8 @@ private function recentOperationIcon(string $operationType): string { return match (OperationCatalog::canonicalCode($operationType)) { 'inventory.sync' => 'heroicon-m-arrow-path', - 'tenant.review_pack.generate' => 'heroicon-m-document-arrow-down', - 'tenant.review.compose' => 'heroicon-m-document-text', + 'environment.review_pack.generate' => 'heroicon-m-document-arrow-down', + 'environment.review.compose' => 'heroicon-m-document-text', 'tenant.evidence.snapshot.generate' => 'heroicon-m-document-duplicate', 'baseline.compare' => 'heroicon-m-arrows-right-left', 'provider.connection.check', 'rbac.health_check' => 'heroicon-m-shield-check', @@ -1157,16 +1157,16 @@ private function riskExceptionsAction(ManagedEnvironment $tenant, ?User $user, s /** * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string} */ - private function tenantReviewAction(ManagedEnvironment $tenant, ?User $user, string $label, ?TenantReview $review = null): array + private function environmentReviewAction(ManagedEnvironment $tenant, ?User $user, string $label, ?EnvironmentReview $review = null): array { - $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_REVIEW_VIEW); + $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_VIEW); $url = null; if ($canOpen) { - $url = $review instanceof TenantReview - ? TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) - : TenantReviewResource::tenantScopedUrl('index', tenant: $tenant); + $url = $review instanceof EnvironmentReview + ? EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) + : EnvironmentReviewResource::tenantScopedUrl('index', tenant: $tenant); } return $this->actionPayload( @@ -1179,13 +1179,13 @@ private function tenantReviewAction(ManagedEnvironment $tenant, ?User $user, str /** * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string} */ - private function continueReviewAction(ManagedEnvironment $tenant, ?User $user, TenantReview $review): array + private function continueReviewAction(ManagedEnvironment $tenant, ?User $user, EnvironmentReview $review): array { - $canContinue = $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_REVIEW_MANAGE); + $canContinue = $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_MANAGE); return $this->actionPayload( label: $this->overviewText('action_continue_review'), - url: $canContinue ? TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) : null, + url: $canContinue ? EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) : null, helperText: $canContinue ? null : $this->overviewText('helper_continue_review_requires_manage'), ); } @@ -1220,7 +1220,7 @@ private function customerWorkspaceAction(ManagedEnvironment $tenant, ?User $user $canOpenWorkspace = $user instanceof User && $user->canAccessTenant($tenant) && ( - $user->can(Capabilities::TENANT_REVIEW_VIEW, $tenant) + $user->can(Capabilities::ENVIRONMENT_REVIEW_VIEW, $tenant) || $user->can(Capabilities::REVIEW_PACK_VIEW, $tenant) || $user->can(Capabilities::EVIDENCE_VIEW, $tenant) ); @@ -1507,13 +1507,13 @@ private function canOpenTenantCapability(ManagedEnvironment $tenant, ?User $user && $user->can($capability, $tenant); } - private function reviewSurfaceActionLabel(ManagedEnvironment $tenant, ?User $user, ?TenantReview $review): string + private function reviewSurfaceActionLabel(ManagedEnvironment $tenant, ?User $user, ?EnvironmentReview $review): string { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return $this->overviewText('action_open_reviews'); } - return $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_REVIEW_MANAGE) + return $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_MANAGE) ? $this->overviewText('action_continue_review') : $this->overviewText('action_open_review'); } @@ -1545,27 +1545,27 @@ private function evidenceCoverageDescription(?EvidenceSnapshot $snapshot): strin return $this->overviewText('evidence_generated_prefix', ['time' => $snapshot->generated_at?->diffForHumans()]); } - private function reviewValue(?TenantReview $review): string + private function reviewValue(?EnvironmentReview $review): string { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return $this->overviewText('status_not_ready'); } - return BadgeRenderer::spec(BadgeDomain::TenantReviewStatus, (string) $review->status)->label; + return BadgeRenderer::spec(BadgeDomain::EnvironmentReviewStatus, (string) $review->status)->label; } - private function reviewTone(?TenantReview $review): string + private function reviewTone(?EnvironmentReview $review): string { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return 'warning'; } - return BadgeRenderer::spec(BadgeDomain::TenantReviewStatus, (string) $review->status)->color; + return BadgeRenderer::spec(BadgeDomain::EnvironmentReviewStatus, (string) $review->status)->color; } - private function reviewDescription(?TenantReview $review): string + private function reviewDescription(?EnvironmentReview $review): string { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return $this->overviewText('review_unavailable_description'); } @@ -1577,9 +1577,9 @@ private function reviewDescription(?TenantReview $review): string /** * @return list> */ - private function reviewProgress(?TenantReview $review): array + private function reviewProgress(?EnvironmentReview $review): array { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return []; } diff --git a/apps/platform/app/Support/TenantReviewCompletenessState.php b/apps/platform/app/Support/EnvironmentReviewCompletenessState.php similarity index 88% rename from apps/platform/app/Support/TenantReviewCompletenessState.php rename to apps/platform/app/Support/EnvironmentReviewCompletenessState.php index 59ba9972..1626db21 100644 --- a/apps/platform/app/Support/TenantReviewCompletenessState.php +++ b/apps/platform/app/Support/EnvironmentReviewCompletenessState.php @@ -4,7 +4,7 @@ namespace App\Support; -enum TenantReviewCompletenessState: string +enum EnvironmentReviewCompletenessState: string { case Complete = 'complete'; case Partial = 'partial'; diff --git a/apps/platform/app/Support/TenantReviewStatus.php b/apps/platform/app/Support/EnvironmentReviewStatus.php similarity index 95% rename from apps/platform/app/Support/TenantReviewStatus.php rename to apps/platform/app/Support/EnvironmentReviewStatus.php index 28208420..2a91f1e8 100644 --- a/apps/platform/app/Support/TenantReviewStatus.php +++ b/apps/platform/app/Support/EnvironmentReviewStatus.php @@ -4,7 +4,7 @@ namespace App\Support; -enum TenantReviewStatus: string +enum EnvironmentReviewStatus: string { case Draft = 'draft'; case Ready = 'ready'; diff --git a/apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php b/apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php index a566350a..20e8398a 100644 --- a/apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php +++ b/apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php @@ -7,7 +7,7 @@ use App\Models\EvidenceSnapshot; use App\Models\EvidenceSnapshotItem; use App\Models\Finding; -use App\Support\TenantReviewCompletenessState; +use App\Support\EnvironmentReviewCompletenessState; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; @@ -414,11 +414,11 @@ private function snapshotLimitations(EvidenceSnapshot $snapshot, ?EvidenceSnapsh $limitations = []; $state = (string) ($findingsItem?->state ?? $snapshot->completeness_state); - if ($state === TenantReviewCompletenessState::Stale->value || (string) $snapshot->status === 'expired' || ($snapshot->expires_at !== null && $snapshot->expires_at->isPast())) { + if ($state === EnvironmentReviewCompletenessState::Stale->value || (string) $snapshot->status === 'expired' || ($snapshot->expires_at !== null && $snapshot->expires_at->isPast())) { $limitations[] = 'stale_evidence'; } - if (in_array($state, [TenantReviewCompletenessState::Partial->value, TenantReviewCompletenessState::Missing->value], true)) { + if (in_array($state, [EnvironmentReviewCompletenessState::Partial->value, EnvironmentReviewCompletenessState::Missing->value], true)) { $limitations[] = 'partial_mapping'; } @@ -439,19 +439,19 @@ private function snapshotLimitations(EvidenceSnapshot $snapshot, ?EvidenceSnapsh private function sectionCompleteness(?EvidenceSnapshotItem $findingsItem, bool $noMappedControls, array $snapshotLimitations): string { if (! $findingsItem instanceof EvidenceSnapshotItem) { - return TenantReviewCompletenessState::Missing->value; + return EnvironmentReviewCompletenessState::Missing->value; } if (in_array('stale_evidence', $snapshotLimitations, true)) { - return TenantReviewCompletenessState::Stale->value; + return EnvironmentReviewCompletenessState::Stale->value; } if ($noMappedControls || in_array('partial_mapping', $snapshotLimitations, true)) { - return TenantReviewCompletenessState::Partial->value; + return EnvironmentReviewCompletenessState::Partial->value; } - return TenantReviewCompletenessState::tryFrom((string) $findingsItem->state)?->value - ?? TenantReviewCompletenessState::Missing->value; + return EnvironmentReviewCompletenessState::tryFrom((string) $findingsItem->state)?->value + ?? EnvironmentReviewCompletenessState::Missing->value; } private function proofAccessState(EvidenceSnapshot $snapshot): string diff --git a/apps/platform/app/Support/GovernanceInbox/GovernanceInboxSectionBuilder.php b/apps/platform/app/Support/GovernanceInbox/GovernanceInboxSectionBuilder.php index 9df88386..4b8867e7 100644 --- a/apps/platform/app/Support/GovernanceInbox/GovernanceInboxSectionBuilder.php +++ b/apps/platform/app/Support/GovernanceInbox/GovernanceInboxSectionBuilder.php @@ -11,22 +11,22 @@ use App\Filament\Resources\AlertDeliveryResource; use App\Filament\Resources\FindingExceptionResource; use App\Filament\Resources\FindingResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\AlertDelivery; use App\Models\Finding; use App\Models\FindingException; use App\Models\OperationRun; use App\Models\ManagedEnvironment; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; use App\Models\Workspace; -use App\Services\TenantReviews\TenantReviewRegisterService; +use App\Services\EnvironmentReviews\EnvironmentReviewRegisterService; use App\Support\Auth\Capabilities; use App\Support\BackupHealth\TenantBackupHealthResolver; use App\Support\Navigation\CanonicalNavigationContext; use App\Support\OperationRunLinks; use App\Support\PortfolioTriage\PortfolioArrivalContextToken; -use App\Support\PortfolioTriage\TenantTriageReviewStateResolver; +use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewStateResolver; use App\Support\RestoreSafety\RestoreSafetyResolver; use Illuminate\Support\Str; @@ -49,8 +49,8 @@ public function __construct( private TenantBackupHealthResolver $backupHealthResolver, private RestoreSafetyResolver $restoreSafetyResolver, - private TenantTriageReviewStateResolver $tenantTriageReviewStateResolver, - private TenantReviewRegisterService $tenantReviewRegisterService, + private ManagedEnvironmentTriageReviewStateResolver $managedEnvironmentTriageReviewStateResolver, + private EnvironmentReviewRegisterService $environmentReviewRegisterService, ) {} /** @@ -477,13 +477,13 @@ private function reviewFollowUpSection( : array_keys($reviewTenants); $backupHealthByTenant = $this->backupHealthResolver->assessMany($tenantIds); $recoveryEvidenceByTenant = $this->restoreSafetyResolver->dashboardRecoveryEvidenceForTenants($tenantIds, $backupHealthByTenant); - $resolved = $this->tenantTriageReviewStateResolver->resolveMany( + $resolved = $this->managedEnvironmentTriageReviewStateResolver->resolveMany( workspaceId: (int) $workspace->getKey(), tenantIds: $tenantIds, backupHealthByTenant: $backupHealthByTenant, recoveryEvidenceByTenant: $recoveryEvidenceByTenant, ); - $latestPublishedReviews = $this->tenantReviewRegisterService + $latestPublishedReviews = $this->environmentReviewRegisterService ->latestPublishedQuery($user, $workspace) ->get() ->keyBy('managed_environment_id') @@ -509,8 +509,8 @@ private function reviewFollowUpSection( $derivedState = $row['derived_state'] ?? null; if (! in_array($derivedState, [ - TenantTriageReview::STATE_FOLLOW_UP_NEEDED, - TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, + ManagedEnvironmentTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, ], true)) { continue; } @@ -893,11 +893,11 @@ private function reviewEntry( mixed $latestPublishedReview, ?CanonicalNavigationContext $navigationContext, ): array { - $state = (string) ($row['derived_state'] ?? TenantTriageReview::DERIVED_STATE_NOT_REVIEWED); + $state = (string) ($row['derived_state'] ?? ManagedEnvironmentTriageReview::DERIVED_STATE_NOT_REVIEWED); $familyLabel = $family === PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH ? 'Backup health' : 'Recovery evidence'; - $headline = $state === TenantTriageReview::STATE_FOLLOW_UP_NEEDED + $headline = $state === ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED ? $familyLabel.' needs review follow-up' : $familyLabel.' changed since review'; $sublineParts = array_values(array_filter([ @@ -909,19 +909,19 @@ private function reviewEntry( : null, ])); $destinationUrl = $latestPublishedReview !== null - ? TenantReviewResource::tenantScopedUrl('view', ['record' => $latestPublishedReview], $tenant) + ? EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $latestPublishedReview], $tenant) : CustomerReviewWorkspace::tenantPrefilterUrl($tenant); return [ 'family_key' => 'review_follow_up', - 'source_model' => TenantTriageReview::class, + 'source_model' => ManagedEnvironmentTriageReview::class, 'source_key' => (string) $tenant->getKey().':'.$family, 'managed_environment_id' => (int) $tenant->getKey(), 'tenant_label' => $tenant->name, 'headline' => $headline, 'subline' => $sublineParts === [] ? null : implode(' • ', $sublineParts), - 'urgency_rank' => $state === TenantTriageReview::STATE_FOLLOW_UP_NEEDED ? 0 : 1, - 'status_label' => $state === TenantTriageReview::STATE_FOLLOW_UP_NEEDED + 'urgency_rank' => $state === ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED ? 0 : 1, + 'status_label' => $state === ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED ? 'Follow-up needed' : 'Changed since review', 'destination_url' => $this->appendQuery($destinationUrl, $navigationContext?->toQuery() ?? []), diff --git a/apps/platform/app/Support/Livewire/TrustedState/TrustedStatePolicy.php b/apps/platform/app/Support/Livewire/TrustedState/TrustedStatePolicy.php index f4443a63..9d1b776b 100644 --- a/apps/platform/app/Support/Livewire/TrustedState/TrustedStatePolicy.php +++ b/apps/platform/app/Support/Livewire/TrustedState/TrustedStatePolicy.php @@ -8,7 +8,7 @@ final class TrustedStatePolicy { - public const MANAGED_TENANT_ONBOARDING_WIZARD = 'managed_tenant_onboarding_wizard'; + public const MANAGED_ENVIRONMENT_ONBOARDING_WIZARD = 'managed_environment_onboarding_wizard'; public const TENANT_REQUIRED_PERMISSIONS = 'tenant_required_permissions'; @@ -90,8 +90,8 @@ private function field( public function firstSlice(): array { return [ - self::MANAGED_TENANT_ONBOARDING_WIZARD => [ - 'component_name' => 'Managed tenant onboarding wizard', + self::MANAGED_ENVIRONMENT_ONBOARDING_WIZARD => [ + 'component_name' => 'Managed environment onboarding wizard', 'plane' => 'admin_workspace', 'route_anchor' => 'onboarding_draft', 'authority_sources' => [ @@ -102,21 +102,21 @@ public function firstSlice(): array ], 'locked_identities' => [ 'workspace_id', - 'managed_tenant_id', + 'managed_environment_id', 'onboarding_session_id', ], 'locked_identity_fields' => [ $this->field( - name: 'managedTenantId', + name: 'managedEnvironmentId', stateClass: TrustedStateClass::LockedIdentity, phpType: '?int', sourceOfTruth: 'persisted_onboarding_draft', usedForProtectedAction: true, revalidationRequired: true, implementationMarkers: [ - "#[Locked]\n public ?int \$managedTenantId = null;", - 'public ?int $managedTenantId = null;', - 'currentManagedTenantRecord()', + "#[Locked]\n public ?int \$managedEnvironmentId = null;", + 'public ?int $managedEnvironmentId = null;', + 'currentManagedEnvironmentRecord()', ], notes: 'Continuity-only tenant identity; protected actions must re-resolve the tenant record before use.', ), @@ -184,34 +184,34 @@ public function firstSlice(): array $this->field( name: 'onboardingSession', stateClass: TrustedStateClass::ServerDerivedAuthority, - phpType: '?TenantOnboardingSession', + phpType: '?ManagedEnvironmentOnboardingSession', sourceOfTruth: 'persisted_onboarding_draft', usedForProtectedAction: true, revalidationRequired: true, implementationMarkers: [ - 'public ?TenantOnboardingSession $onboardingSession = null;', + 'public ?ManagedEnvironmentOnboardingSession $onboardingSession = null;', 'resolveOnboardingDraft(', 'currentOnboardingSessionRecord()', ], notes: 'Draft model instances remain convenience state only and are refreshed from canonical persisted draft truth.', ), $this->field( - name: 'managedTenant', + name: 'managedEnvironment', stateClass: TrustedStateClass::ServerDerivedAuthority, phpType: '?ManagedEnvironment', sourceOfTruth: 'explicit_scoped_query', usedForProtectedAction: true, revalidationRequired: true, implementationMarkers: [ - 'public ?ManagedEnvironment $managedTenant = null;', - 'currentManagedTenantRecord()', + 'public ?ManagedEnvironment $managedEnvironment = null;', + 'currentManagedEnvironmentRecord()', ], notes: 'ManagedEnvironment model instances are display helpers only and must be re-derived from draft or scoped tenant queries.', ), ], 'forbidden_public_authority_fields' => [ 'workspace', - 'managedTenant', + 'managedEnvironment', 'onboardingSession', ], ], diff --git a/apps/platform/app/Support/Livewire/TrustedState/TrustedStateResolver.php b/apps/platform/app/Support/Livewire/TrustedState/TrustedStateResolver.php index 5869e17c..930d78f2 100644 --- a/apps/platform/app/Support/Livewire/TrustedState/TrustedStateResolver.php +++ b/apps/platform/app/Support/Livewire/TrustedState/TrustedStateResolver.php @@ -5,7 +5,7 @@ namespace App\Support\Livewire\TrustedState; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\Workspace; use App\Services\Onboarding\OnboardingDraftResolver; @@ -29,11 +29,11 @@ public function currentWorkspaceForMember(User $user, WorkspaceContext $workspac } public function resolveOnboardingDraft( - TenantOnboardingSession|int|string $draft, + ManagedEnvironmentOnboardingSession|int|string $draft, User $user, Workspace $workspace, OnboardingDraftResolver $resolver, - ): TenantOnboardingSession { + ): ManagedEnvironmentOnboardingSession { return $resolver->resolveForTrustedAction($draft, $user, $workspace); } diff --git a/apps/platform/app/Support/ManagedEnvironmentLinks.php b/apps/platform/app/Support/ManagedEnvironmentLinks.php index 4c9afc5a..107691b0 100644 --- a/apps/platform/app/Support/ManagedEnvironmentLinks.php +++ b/apps/platform/app/Support/ManagedEnvironmentLinks.php @@ -22,7 +22,7 @@ public static function indexUrl(Workspace|ManagedEnvironment|null $scope = null, return url('/admin'); } - return self::withQuery(route('admin.workspace.managed-tenants.index', [ + return self::withQuery(route('admin.workspace.managed-environments.index', [ 'workspace' => self::workspaceRouteKey($workspace), ]), $query); } @@ -40,7 +40,7 @@ public static function viewUrl(ManagedEnvironment $environment, array $query = [ return self::withQuery(route('admin.workspace.environments.show', [ 'workspace' => self::workspaceRouteKey($workspace), - 'tenant' => self::environmentRouteKey($environment), + 'environment' => self::environmentRouteKey($environment), ]), $query); } @@ -145,7 +145,7 @@ private static function environmentChildUrl(string $routeName, ManagedEnvironmen return self::withQuery(route($routeName, [ 'workspace' => self::workspaceRouteKey($workspace), - 'tenant' => self::environmentRouteKey($environment), + 'environment' => self::environmentRouteKey($environment), ]), $query); } diff --git a/apps/platform/app/Support/Middleware/DenyNonMemberTenantAccess.php b/apps/platform/app/Support/Middleware/DenyNonMemberTenantAccess.php index 71347601..c1cd7216 100644 --- a/apps/platform/app/Support/Middleware/DenyNonMemberTenantAccess.php +++ b/apps/platform/app/Support/Middleware/DenyNonMemberTenantAccess.php @@ -16,7 +16,7 @@ class DenyNonMemberTenantAccess */ public function handle(Request $request, Closure $next): Response { - $tenant = $request->route()?->parameter('tenant'); + $tenant = $request->route()?->parameter('environment') ?? $request->route()?->parameter('tenant'); if (! $tenant instanceof ManagedEnvironment) { return $next($request); diff --git a/apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php b/apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php index a05431dc..571b2333 100644 --- a/apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php +++ b/apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php @@ -107,10 +107,10 @@ public function handle(Request $request, Closure $next): Response $workspace = $workspaceContext->currentWorkspace($request); if ($workspace !== null) { - return redirect()->route('admin.workspace.managed-tenants.index', ['workspace' => $workspace]); + return redirect()->route('admin.workspace.managed-environments.index', ['workspace' => $workspace]); } - return redirect()->route('filament.admin.pages.choose-tenant'); + return redirect()->route('filament.admin.pages.choose-environment'); } if ($resolvedContext->pageCategory === TenantPageCategory::TenantBound && ! $resolvedContext->hasTenant()) { @@ -139,7 +139,7 @@ public function handle(Request $request, Closure $next): Response if ( str_starts_with($path, '/admin/workspaces/') - || in_array($path, ['/admin', '/admin/choose-workspace', '/admin/choose-tenant', '/admin/no-access', '/admin/alerts', '/admin/audit-log', '/admin/onboarding', '/admin/settings/workspace', '/admin/findings/my-work', '/admin/findings/intake', '/admin/findings/hygiene'], true) + || in_array($path, ['/admin', '/admin/choose-workspace', '/admin/choose-environment', '/admin/no-access', '/admin/alerts', '/admin/audit-log', '/admin/onboarding', '/admin/settings/workspace', '/admin/findings/my-work', '/admin/findings/intake', '/admin/findings/hygiene'], true) ) { $this->configureNavigationForRequest($panel); diff --git a/apps/platform/app/Support/Navigation/CanonicalNavigationContext.php b/apps/platform/app/Support/Navigation/CanonicalNavigationContext.php index 0ba51b9c..32ac418f 100644 --- a/apps/platform/app/Support/Navigation/CanonicalNavigationContext.php +++ b/apps/platform/app/Support/Navigation/CanonicalNavigationContext.php @@ -5,7 +5,7 @@ namespace App\Support\Navigation; use App\Filament\Pages\BaselineCompareMatrix; -use App\Filament\Resources\TenantResource\Pages\ListTenants; +use App\Filament\Resources\ManagedEnvironmentResource\Pages\ListManagedEnvironments; use App\Models\BaselineProfile; use App\Models\ManagedEnvironment; use Filament\Facades\Filament; @@ -102,7 +102,7 @@ public static function forTenantRegistry(string $backLinkUrl, ?int $tenantId = n { return new self( sourceSurface: 'tenant_registry', - canonicalRouteName: ListTenants::getRouteName(Filament::getPanel('admin')), + canonicalRouteName: ListManagedEnvironments::getRouteName(Filament::getPanel('admin')), tenantId: $tenantId, backLinkLabel: __('localization.shell.back_to_environment_registry'), backLinkUrl: $backLinkUrl, diff --git a/apps/platform/app/Support/Onboarding/OnboardingCheckpoint.php b/apps/platform/app/Support/Onboarding/OnboardingCheckpoint.php index 66b160d4..4e50898f 100644 --- a/apps/platform/app/Support/Onboarding/OnboardingCheckpoint.php +++ b/apps/platform/app/Support/Onboarding/OnboardingCheckpoint.php @@ -15,7 +15,7 @@ enum OnboardingCheckpoint: string public function label(): string { return match ($this) { - self::Identify => 'Identify managed tenant', + self::Identify => 'Identify managed environment', self::ConnectProvider => 'Connect provider', self::VerifyAccess => 'Verify access', self::Bootstrap => 'Bootstrap', diff --git a/apps/platform/app/Support/Onboarding/OnboardingDraftStage.php b/apps/platform/app/Support/Onboarding/OnboardingDraftStage.php index 30d74698..89987c27 100644 --- a/apps/platform/app/Support/Onboarding/OnboardingDraftStage.php +++ b/apps/platform/app/Support/Onboarding/OnboardingDraftStage.php @@ -17,7 +17,7 @@ enum OnboardingDraftStage: string public function label(): string { return match ($this) { - self::Identify => 'Identify managed tenant', + self::Identify => 'Identify managed environment', self::ConnectProvider => 'Connect provider', self::VerifyAccess => 'Verify access', self::Bootstrap => 'Bootstrap', diff --git a/apps/platform/app/Support/OperateHub/OperateHubShell.php b/apps/platform/app/Support/OperateHub/OperateHubShell.php index 46fc88c1..a98b0e8e 100644 --- a/apps/platform/app/Support/OperateHub/OperateHubShell.php +++ b/apps/platform/app/Support/OperateHub/OperateHubShell.php @@ -342,6 +342,10 @@ private function resolveRouteTenantCandidate(?Request $request = null, ?TenantPa $route = $request?->route(); $pageCategory ??= $this->pageCategory($request); + if ($route?->hasParameter('environment')) { + return $this->resolveTenantIdentifier($route->parameter('environment')); + } + if ($route?->hasParameter('tenant')) { return $this->resolveTenantIdentifier($route->parameter('tenant')); } diff --git a/apps/platform/app/Support/OperationCatalog.php b/apps/platform/app/Support/OperationCatalog.php index 933f1e09..89cad44a 100644 --- a/apps/platform/app/Support/OperationCatalog.php +++ b/apps/platform/app/Support/OperationCatalog.php @@ -275,8 +275,8 @@ private static function canonicalDefinitions(): array 'baseline.compare' => new CanonicalOperationType('baseline.compare', 'platform_foundation', null, 'Baseline compare', true, 120), 'permission.posture.check' => new CanonicalOperationType('permission.posture.check', 'platform_foundation', null, 'Permission posture check', false, 30), 'entra.admin_roles.scan' => new CanonicalOperationType('entra.admin_roles.scan', 'entra', null, 'Entra admin roles scan', false, 60), - 'tenant.review_pack.generate' => new CanonicalOperationType('tenant.review_pack.generate', 'platform_foundation', 'review_pack', 'Review pack generation', true, 60), - 'tenant.review.compose' => new CanonicalOperationType('tenant.review.compose', 'platform_foundation', 'tenant_review', 'Review composition', true, 60), + 'environment.review_pack.generate' => new CanonicalOperationType('environment.review_pack.generate', 'platform_foundation', 'review_pack', 'Review pack generation', true, 60), + 'environment.review.compose' => new CanonicalOperationType('environment.review.compose', 'platform_foundation', 'environment_review', 'Review composition', true, 60), 'tenant.evidence.snapshot.generate' => new CanonicalOperationType('tenant.evidence.snapshot.generate', 'platform_foundation', 'evidence_snapshot', 'Evidence snapshot generation', true, 120), 'rbac.health_check' => new CanonicalOperationType('rbac.health_check', 'intune', null, 'RBAC health check', false, 30), ]; @@ -338,8 +338,8 @@ private static function operationAliases(): array new OperationTypeAlias('permission.posture.check', 'permission.posture.check', 'canonical', true), new OperationTypeAlias('permission_posture_check', 'permission.posture.check', 'legacy_alias', false, 'Historical permission_posture_check values resolve to permission.posture.check.', 'Prefer dotted permission posture naming on new read paths.'), new OperationTypeAlias('entra.admin_roles.scan', 'entra.admin_roles.scan', 'canonical', true), - new OperationTypeAlias('tenant.review_pack.generate', 'tenant.review_pack.generate', 'canonical', true), - new OperationTypeAlias('tenant.review.compose', 'tenant.review.compose', 'canonical', true), + new OperationTypeAlias('environment.review_pack.generate', 'environment.review_pack.generate', 'canonical', true), + new OperationTypeAlias('environment.review.compose', 'environment.review.compose', 'canonical', true), new OperationTypeAlias('tenant.evidence.snapshot.generate', 'tenant.evidence.snapshot.generate', 'canonical', true), new OperationTypeAlias('rbac.health_check', 'rbac.health_check', 'canonical', true), ]; diff --git a/apps/platform/app/Support/OperationRunLinks.php b/apps/platform/app/Support/OperationRunLinks.php index 716a6931..ad88f8a7 100644 --- a/apps/platform/app/Support/OperationRunLinks.php +++ b/apps/platform/app/Support/OperationRunLinks.php @@ -12,12 +12,12 @@ use App\Filament\Resources\PolicyResource; use App\Filament\Resources\RestoreRunResource; use App\Filament\Resources\ReviewPackResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\EvidenceSnapshot; use App\Models\OperationRun; use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\Workspace; use App\Support\Navigation\CanonicalNavigationContext; use App\Support\Workspaces\WorkspaceContext; @@ -232,18 +232,18 @@ public static function related(OperationRun $run, ?ManagedEnvironment $tenant): } } - if ($canonicalType === 'tenant.review.compose') { - $review = TenantReview::query() + if ($canonicalType === 'environment.review.compose') { + $review = EnvironmentReview::query() ->where('operation_run_id', (int) $run->getKey()) ->latest('id') ->first(); - if ($review instanceof TenantReview) { - $links['ManagedEnvironment Review'] = TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant); + if ($review instanceof EnvironmentReview) { + $links['ManagedEnvironment Review'] = EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant); } } - if ($canonicalType === 'tenant.review_pack.generate') { + if ($canonicalType === 'environment.review_pack.generate') { $pack = ReviewPack::query() ->where('operation_run_id', (int) $run->getKey()) ->latest('id') diff --git a/apps/platform/app/Support/OperationRunType.php b/apps/platform/app/Support/OperationRunType.php index 6cc87010..05a95638 100644 --- a/apps/platform/app/Support/OperationRunType.php +++ b/apps/platform/app/Support/OperationRunType.php @@ -17,8 +17,8 @@ enum OperationRunType: string case RestoreExecute = 'restore.execute'; case PromotionExecute = 'promotion.execute'; case EntraAdminRolesScan = 'entra.admin_roles.scan'; - case ReviewPackGenerate = 'tenant.review_pack.generate'; - case TenantReviewCompose = 'tenant.review.compose'; + case ReviewPackGenerate = 'environment.review_pack.generate'; + case EnvironmentReviewCompose = 'environment.review.compose'; case EvidenceSnapshotGenerate = 'tenant.evidence.snapshot.generate'; case RbacHealthCheck = 'rbac.health_check'; diff --git a/apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php b/apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php index 693b9985..9de0249b 100644 --- a/apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php +++ b/apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php @@ -22,7 +22,7 @@ final class OperationalControlCatalog 'label' => 'Promotion execution', 'supported_scopes' => ['global', 'workspace'], 'operation_types' => ['promotion.execute'], - 'affected_surfaces' => ['admin.cross_tenant_compare.execute'], + 'affected_surfaces' => ['admin.cross_environment_compare.execute'], ], 'ai.execution' => [ 'key' => 'ai.execution', diff --git a/apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php b/apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php index b8327e09..d0e3d42f 100644 --- a/apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php +++ b/apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php @@ -28,7 +28,7 @@ public function requiredCapabilityForType(string $operationType): ?string 'restore.execute', 'promotion.execute' => Capabilities::TENANT_MANAGE, 'directory.role_definitions.sync' => Capabilities::TENANT_MANAGE, 'alerts.evaluate', 'alerts.deliver' => Capabilities::ALERTS_VIEW, - 'tenant.review.compose' => Capabilities::TENANT_REVIEW_VIEW, + 'environment.review.compose' => Capabilities::ENVIRONMENT_REVIEW_VIEW, // Viewing verification reports should be possible for readonly members. // Starting verification is separately guarded by the verification service. @@ -52,7 +52,7 @@ public function requiredExecutionCapabilityForType(string $operationType): ?stri 'policy.sync', 'tenant.sync' => Capabilities::TENANT_SYNC, 'policy.delete' => Capabilities::TENANT_MANAGE, 'assignments.restore', 'restore.execute', 'promotion.execute' => Capabilities::TENANT_MANAGE, - 'tenant.review.compose' => Capabilities::TENANT_REVIEW_MANAGE, + 'environment.review.compose' => Capabilities::ENVIRONMENT_REVIEW_MANAGE, default => $this->requiredCapabilityForType($operationType), }; } diff --git a/apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilder.php b/apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilder.php index 5bf34bca..850a943d 100644 --- a/apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilder.php +++ b/apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilder.php @@ -124,8 +124,8 @@ private function headline( 'baseline.capture' => $this->baselineCaptureHeadline($artifactTruth, $context, $counts, $operatorExplanation), 'baseline.compare' => $this->baselineCompareHeadline($artifactTruth, $context, $counts, $operatorExplanation), 'tenant.evidence.snapshot.generate' => $this->evidenceSnapshotHeadline($artifactTruth, $operatorExplanation), - 'tenant.review.compose' => $this->reviewComposeHeadline($artifactTruth, $dominantCause, $operatorExplanation), - 'tenant.review_pack.generate' => $this->reviewPackHeadline($artifactTruth, $dominantCause, $operatorExplanation), + 'environment.review.compose' => $this->reviewComposeHeadline($artifactTruth, $dominantCause, $operatorExplanation), + 'environment.review_pack.generate' => $this->reviewPackHeadline($artifactTruth, $dominantCause, $operatorExplanation), default => $operatorExplanation?->headline ?? $artifactTruth?->primaryExplanation ?? 'This governance run needs review before it can be relied on.', @@ -352,7 +352,7 @@ private function nextActionCategory( if ( $reasonEnvelope?->actionability === 'prerequisite_missing' - || in_array($canonicalType, ['tenant.evidence.snapshot.generate', 'tenant.review.compose', 'tenant.review_pack.generate'], true) + || in_array($canonicalType, ['tenant.evidence.snapshot.generate', 'environment.review.compose', 'environment.review_pack.generate'], true) ) { return 'refresh_prerequisite_data'; } @@ -390,8 +390,8 @@ private function affectedScaleCue( 'baseline.capture' => $this->baselineCaptureScaleCue($context, $counts), 'baseline.compare' => $this->baselineCompareScaleCue($context, $counts), 'tenant.evidence.snapshot.generate' => $this->countDescriptorScaleCue($operatorExplanation?->countDescriptors ?? [], ['Missing dimensions', 'Stale dimensions', 'Evidence dimensions']), - 'tenant.review.compose' => $this->reviewScaleCue($artifactTruth, $operatorExplanation?->countDescriptors ?? []), - 'tenant.review_pack.generate' => $this->reviewPackScaleCue($artifactTruth, $operatorExplanation?->countDescriptors ?? []), + 'environment.review.compose' => $this->reviewScaleCue($artifactTruth, $operatorExplanation?->countDescriptors ?? []), + 'environment.review_pack.generate' => $this->reviewPackScaleCue($artifactTruth, $operatorExplanation?->countDescriptors ?? []), default => $this->summaryCountsScaleCue($counts), }; } @@ -601,8 +601,8 @@ private function rankCauseCandidates( 'baseline.capture' => $this->baselineCaptureCandidates($candidates, $context), 'baseline.compare' => $this->baselineCompareCandidates($candidates, $context), 'tenant.evidence.snapshot.generate' => $this->evidenceSnapshotCandidates($candidates, $artifactTruth, $operatorExplanation), - 'tenant.review.compose' => $this->reviewComposeCandidates($candidates, $artifactTruth), - 'tenant.review_pack.generate' => $this->reviewPackCandidates($candidates, $artifactTruth), + 'environment.review.compose' => $this->reviewComposeCandidates($candidates, $artifactTruth), + 'environment.review_pack.generate' => $this->reviewPackCandidates($candidates, $artifactTruth), default => null, }; diff --git a/apps/platform/app/Support/OpsUx/OperationRunProgressContract.php b/apps/platform/app/Support/OpsUx/OperationRunProgressContract.php index ad9b82d5..ba559c8c 100644 --- a/apps/platform/app/Support/OpsUx/OperationRunProgressContract.php +++ b/apps/platform/app/Support/OpsUx/OperationRunProgressContract.php @@ -343,7 +343,7 @@ private static function legacyPhasedLabel(OperationRun $run, array $context): ?s */ private static function legacyCompositeLabel(OperationRun $run, array $summaryCounts, array $context): ?string { - if ((string) $run->type !== 'tenant.review.compose') { + if ((string) $run->type !== 'environment.review.compose') { return null; } diff --git a/apps/platform/app/Support/OpsUx/OperationUxPresenter.php b/apps/platform/app/Support/OpsUx/OperationUxPresenter.php index 02436e8c..c7c41f84 100644 --- a/apps/platform/app/Support/OpsUx/OperationUxPresenter.php +++ b/apps/platform/app/Support/OpsUx/OperationUxPresenter.php @@ -596,7 +596,7 @@ private static function operationRunPrimaryAction(OperationRun $run, object $not ]; } - if (self::isManagedTenantOnboardingWizardRun($run)) { + if (self::isManagedEnvironmentOnboardingWizardRun($run)) { return [ 'label' => OperationRunLinks::openLabel(), 'url' => OperationRunLinks::tenantlessView($run), @@ -619,13 +619,13 @@ private static function operationRunPrimaryAction(OperationRun $run, object $not ]; } - private static function isManagedTenantOnboardingWizardRun(OperationRun $run): bool + private static function isManagedEnvironmentOnboardingWizardRun(OperationRun $run): bool { $context = is_array($run->context) ? $run->context : []; $wizard = $context['wizard'] ?? null; return is_array($wizard) - && ($wizard['flow'] ?? null) === 'managed_tenant_onboarding'; + && ($wizard['flow'] ?? null) === 'managed_environment_onboarding'; } /** diff --git a/apps/platform/app/Support/PortfolioCompare/CrossTenantComparePreviewBuilder.php b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentComparePreviewBuilder.php similarity index 86% rename from apps/platform/app/Support/PortfolioCompare/CrossTenantComparePreviewBuilder.php rename to apps/platform/app/Support/PortfolioCompare/CrossEnvironmentComparePreviewBuilder.php index c0317bc3..ca69b8f3 100644 --- a/apps/platform/app/Support/PortfolioCompare/CrossTenantComparePreviewBuilder.php +++ b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentComparePreviewBuilder.php @@ -13,7 +13,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; -final class CrossTenantComparePreviewBuilder +final class CrossEnvironmentComparePreviewBuilder { public function __construct( private readonly CurrentStateHashResolver $currentStateHashResolver, @@ -23,23 +23,23 @@ public function __construct( * @return array{ * selection: array{ * workspaceId: int, - * sourceTenantId: int, - * sourceTenantName: string, - * targetTenantId: int, - * targetTenantName: string, + * sourceEnvironmentId: int, + * sourceEnvironmentName: string, + * targetEnvironmentId: int, + * targetEnvironmentName: string, * policyTypes: list * }, * summary: array{match: int, different: int, missing: int, ambiguous: int, blocked: int, total: int}, * subjects: list> * } */ - public function build(CrossTenantCompareSelection $selection): array + public function build(CrossEnvironmentCompareSelection $selection): array { - $sourceIndex = $this->indexTenantSubjects($selection->sourceTenant, $selection->policyTypes); - $targetIndex = $this->indexTenantSubjects($selection->targetTenant, $selection->policyTypes); + $sourceIndex = $this->indexEnvironmentSubjects($selection->sourceEnvironment, $selection->policyTypes); + $targetIndex = $this->indexEnvironmentSubjects($selection->targetEnvironment, $selection->policyTypes); - $sourceEvidence = $this->resolvedEvidenceMap($selection->sourceTenant, $sourceIndex['evidence_subjects']); - $targetEvidence = $this->resolvedEvidenceMap($selection->targetTenant, $targetIndex['evidence_subjects']); + $sourceEvidence = $this->resolvedEvidenceMap($selection->sourceEnvironment, $sourceIndex['evidence_subjects']); + $targetEvidence = $this->resolvedEvidenceMap($selection->targetEnvironment, $targetIndex['evidence_subjects']); $subjects = []; $summary = [ @@ -54,8 +54,8 @@ public function build(CrossTenantCompareSelection $selection): array foreach ($sourceIndex['preview_subjects'] as $sourceSubject) { $previewSubject = $this->buildPreviewSubject( sourceSubject: $sourceSubject, - sourceTenant: $selection->sourceTenant, - targetTenant: $selection->targetTenant, + sourceEnvironment: $selection->sourceEnvironment, + targetEnvironment: $selection->targetEnvironment, targetIndex: $targetIndex['subjects'], sourceEvidence: $sourceEvidence, targetEvidence: $targetEvidence, @@ -88,10 +88,10 @@ public function build(CrossTenantCompareSelection $selection): array return [ 'selection' => [ 'workspaceId' => $selection->workspaceId(), - 'sourceTenantId' => $selection->sourceTenantId(), - 'sourceTenantName' => (string) $selection->sourceTenant->name, - 'targetTenantId' => $selection->targetTenantId(), - 'targetTenantName' => (string) $selection->targetTenant->name, + 'sourceEnvironmentId' => $selection->sourceEnvironmentId(), + 'sourceEnvironmentName' => (string) $selection->sourceEnvironment->name, + 'targetEnvironmentId' => $selection->targetEnvironmentId(), + 'targetEnvironmentName' => (string) $selection->targetEnvironment->name, 'policyTypes' => $selection->policyTypes, ], 'summary' => $summary, @@ -100,7 +100,7 @@ public function build(CrossTenantCompareSelection $selection): array } /** - * @param ManagedEnvironment $tenant + * @param ManagedEnvironment $environment * @param list $policyTypes * @return array{ * preview_subjects: list>, @@ -108,10 +108,10 @@ public function build(CrossTenantCompareSelection $selection): array * subjects: array> * } */ - private function indexTenantSubjects(ManagedEnvironment $tenant, array $policyTypes): array + private function indexEnvironmentSubjects(ManagedEnvironment $environment, array $policyTypes): array { $inventoryItems = InventoryItem::query() - ->where('managed_environment_id', (int) $tenant->getKey()) + ->where('managed_environment_id', (int) $environment->getKey()) ->when( $policyTypes !== [], fn ($query) => $query->whereIn('policy_type', $policyTypes), @@ -137,7 +137,7 @@ private function indexTenantSubjects(ManagedEnvironment $tenant, array $policyTy is_string($inventoryItem->external_id ?? null) ? (string) $inventoryItem->external_id : null, ); - $subjectRecord = $this->inventorySubjectRecord($tenant, $inventoryItem, $policyType, $subjectKey); + $subjectRecord = $this->inventorySubjectRecord($environment, $inventoryItem, $policyType, $subjectKey); if ($subjectKey === null) { $previewSubjects[] = [ @@ -203,8 +203,8 @@ private function indexTenantSubjects(ManagedEnvironment $tenant, array $policyTy */ private function buildPreviewSubject( array $sourceSubject, - ManagedEnvironment $sourceTenant, - ManagedEnvironment $targetTenant, + ManagedEnvironment $sourceEnvironment, + ManagedEnvironment $targetEnvironment, array $targetIndex, array $sourceEvidence, array $targetEvidence, @@ -293,9 +293,9 @@ private function buildPreviewSubject( 'state' => $state, 'trustLevel' => $trustLevel, 'reasonCodes' => $reasonCodes, - 'source' => $this->subjectSidePayload($sourceTenant, $sourceSubject, $sourceEvidenceRecord), + 'source' => $this->subjectSidePayload($sourceEnvironment, $sourceSubject, $sourceEvidenceRecord), 'target' => $this->subjectSidePayload( - $targetTenant, + $targetEnvironment, is_array($targetSubject['representative'] ?? null) ? $targetSubject['representative'] : null, $targetEvidenceRecord, ), @@ -306,20 +306,20 @@ private function buildPreviewSubject( * @param list $subjects * @return array */ - private function resolvedEvidenceMap(ManagedEnvironment $tenant, array $subjects): array + private function resolvedEvidenceMap(ManagedEnvironment $environment, array $subjects): array { - return $this->currentStateHashResolver->resolveForSubjects($tenant, $subjects); + return $this->currentStateHashResolver->resolveForSubjects($environment, $subjects); } /** * @param array|null $subject * @return array */ - private function subjectSidePayload(ManagedEnvironment $tenant, ?array $subject, ?ResolvedEvidence $evidence): array + private function subjectSidePayload(ManagedEnvironment $environment, ?array $subject, ?ResolvedEvidence $evidence): array { return [ - 'tenantId' => (int) $tenant->getKey(), - 'tenantName' => (string) $tenant->name, + 'environmentId' => (int) $environment->getKey(), + 'environmentName' => (string) $environment->name, 'inventoryItemId' => is_numeric($subject['inventoryItemId'] ?? null) ? (int) $subject['inventoryItemId'] : null, 'subjectExternalId' => is_string($subject['subjectExternalId'] ?? null) ? (string) $subject['subjectExternalId'] : null, 'displayName' => is_string($subject['displayName'] ?? null) ? (string) $subject['displayName'] : null, @@ -339,7 +339,7 @@ private function subjectSidePayload(ManagedEnvironment $tenant, ?array $subject, * lastSeenAt: ?string * } */ - private function inventorySubjectRecord(ManagedEnvironment $tenant, InventoryItem $inventoryItem, string $policyType, ?string $subjectKey): array + private function inventorySubjectRecord(ManagedEnvironment $environment, InventoryItem $inventoryItem, string $policyType, ?string $subjectKey): array { $displayName = is_string($inventoryItem->display_name ?? null) ? trim((string) $inventoryItem->display_name) : ''; $displayName = $displayName !== '' @@ -347,7 +347,7 @@ private function inventorySubjectRecord(ManagedEnvironment $tenant, InventoryIte : ($subjectKey !== null ? Str::headline($subjectKey) : Str::headline($policyType)); return [ - 'tenantId' => (int) $tenant->getKey(), + 'environmentId' => (int) $environment->getKey(), 'policyType' => $policyType, 'displayName' => $displayName, 'subjectKey' => $subjectKey, diff --git a/apps/platform/app/Support/PortfolioCompare/CrossTenantCompareSelection.php b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentCompareSelection.php similarity index 59% rename from apps/platform/app/Support/PortfolioCompare/CrossTenantCompareSelection.php rename to apps/platform/app/Support/PortfolioCompare/CrossEnvironmentCompareSelection.php index cba26913..bfc76e49 100644 --- a/apps/platform/app/Support/PortfolioCompare/CrossTenantCompareSelection.php +++ b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentCompareSelection.php @@ -7,11 +7,11 @@ use App\Models\ManagedEnvironment; use InvalidArgumentException; -final readonly class CrossTenantCompareSelection +final readonly class CrossEnvironmentCompareSelection { - public ManagedEnvironment $sourceTenant; + public ManagedEnvironment $sourceEnvironment; - public ManagedEnvironment $targetTenant; + public ManagedEnvironment $targetEnvironment; /** * @var list @@ -22,19 +22,19 @@ * @param list $policyTypes */ public function __construct( - ManagedEnvironment $sourceTenant, - ManagedEnvironment $targetTenant, + ManagedEnvironment $sourceEnvironment, + ManagedEnvironment $targetEnvironment, array $policyTypes = [], ) { - $this->sourceTenant = $sourceTenant; - $this->targetTenant = $targetTenant; + $this->sourceEnvironment = $sourceEnvironment; + $this->targetEnvironment = $targetEnvironment; - if ((int) $this->sourceTenant->getKey() === (int) $this->targetTenant->getKey()) { - throw new InvalidArgumentException('Source and target tenants must differ.'); + if ((int) $this->sourceEnvironment->getKey() === (int) $this->targetEnvironment->getKey()) { + throw new InvalidArgumentException('Source and target environments must differ.'); } - if ((int) $this->sourceTenant->workspace_id !== (int) $this->targetTenant->workspace_id) { - throw new InvalidArgumentException('Source and target tenants must belong to the same workspace.'); + if ((int) $this->sourceEnvironment->workspace_id !== (int) $this->targetEnvironment->workspace_id) { + throw new InvalidArgumentException('Source and target environments must belong to the same workspace.'); } $this->policyTypes = $this->normalizePolicyTypes($policyTypes); @@ -42,17 +42,17 @@ public function __construct( public function workspaceId(): int { - return (int) $this->sourceTenant->workspace_id; + return (int) $this->sourceEnvironment->workspace_id; } - public function sourceTenantId(): int + public function sourceEnvironmentId(): int { - return (int) $this->sourceTenant->getKey(); + return (int) $this->sourceEnvironment->getKey(); } - public function targetTenantId(): int + public function targetEnvironmentId(): int { - return (int) $this->targetTenant->getKey(); + return (int) $this->targetEnvironment->getKey(); } public function hasPolicyTypeFilter(): bool diff --git a/apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionExecutionPlanner.php b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionExecutionPlanner.php similarity index 93% rename from apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionExecutionPlanner.php rename to apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionExecutionPlanner.php index fe8e99f1..f45fedc8 100644 --- a/apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionExecutionPlanner.php +++ b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionExecutionPlanner.php @@ -7,7 +7,7 @@ use DomainException; use InvalidArgumentException; -final class CrossTenantPromotionExecutionPlanner +final class CrossEnvironmentPromotionExecutionPlanner { /** * @param array $preview @@ -71,7 +71,7 @@ public function build(array $preview, array $preflight): array /** * @param array $payload - * @return array{sourceTenantId: ?int, targetTenantId: ?int, policyTypes: list} + * @return array{sourceEnvironmentId: ?int, targetEnvironmentId: ?int, policyTypes: list} */ private function selection(array $payload): array { @@ -86,8 +86,8 @@ private function selection(array $payload): array sort($policyTypes); return [ - 'sourceTenantId' => is_numeric($selection['sourceTenantId'] ?? null) ? (int) $selection['sourceTenantId'] : null, - 'targetTenantId' => is_numeric($selection['targetTenantId'] ?? null) ? (int) $selection['targetTenantId'] : null, + 'sourceEnvironmentId' => is_numeric($selection['sourceEnvironmentId'] ?? null) ? (int) $selection['sourceEnvironmentId'] : null, + 'targetEnvironmentId' => is_numeric($selection['targetEnvironmentId'] ?? null) ? (int) $selection['targetEnvironmentId'] : null, 'policyTypes' => $policyTypes, ]; } @@ -161,14 +161,14 @@ private function executionItem(array $subject): ?array 'execution_action' => $action, 'readiness_reason_codes' => $this->stringList(data_get($subject, 'preflight.reasonCodes', [])), 'source' => [ - 'managed_environment_id' => $this->intValue(data_get($subject, 'source.tenantId')), + 'managed_environment_id' => $this->intValue(data_get($subject, 'source.environmentId')), 'inventory_item_id' => $this->intValue(data_get($subject, 'source.inventoryItemId')), 'subject_external_id' => $this->nullableString(data_get($subject, 'source.subjectExternalId')), 'policy_version_id' => (int) $policyVersionId, 'evidence_hash' => $this->nullableString(data_get($subject, 'source.evidence.hash')), ], 'target' => [ - 'managed_environment_id' => $this->intValue(data_get($subject, 'target.tenantId')), + 'managed_environment_id' => $this->intValue(data_get($subject, 'target.environmentId')), 'inventory_item_id' => $this->intValue(data_get($subject, 'target.inventoryItemId')), 'subject_external_id' => $this->nullableString(data_get($subject, 'target.subjectExternalId')), ], @@ -220,8 +220,8 @@ private function sortItems(array $items): array private function identity(array $selection, array $items): array { return [ - 'source_tenant_id' => $selection['sourceTenantId'] ?? null, - 'target_tenant_id' => $selection['targetTenantId'] ?? null, + 'source_environment_id' => $selection['sourceEnvironmentId'] ?? null, + 'target_environment_id' => $selection['targetEnvironmentId'] ?? null, 'policy_types' => $selection['policyTypes'] ?? [], 'subjects' => array_map(static fn (array $item): array => [ 'policy_type' => $item['policy_type'] ?? '', diff --git a/apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionPreflight.php b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionPreflight.php similarity index 86% rename from apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionPreflight.php rename to apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionPreflight.php index c1c5c466..9586c047 100644 --- a/apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionPreflight.php +++ b/apps/platform/app/Support/PortfolioCompare/CrossEnvironmentPromotionPreflight.php @@ -4,7 +4,7 @@ namespace App\Support\PortfolioCompare; -final class CrossTenantPromotionPreflight +final class CrossEnvironmentPromotionPreflight { /** * @param array{ @@ -129,14 +129,14 @@ private function decision(string $bucket, array $reasonCodes): array private function reasonLabel(string $reasonCode): string { return match ($reasonCode) { - 'source_identifier_missing' => 'Source tenant subject is missing a stable compare identifier.', - 'source_subject_ambiguous' => 'Source tenant subject resolves to multiple candidates and cannot drive promotion safely.', - 'target_subject_ambiguous' => 'Target tenant has multiple matching subjects and needs manual mapping.', + 'source_identifier_missing' => 'Source environment subject is missing a stable compare identifier.', + 'source_subject_ambiguous' => 'Source environment subject resolves to multiple candidates and cannot drive promotion safely.', + 'target_subject_ambiguous' => 'Target environment has multiple matching subjects and needs manual mapping.', 'source_evidence_refresh_required' => 'Refresh source evidence before relying on this subject.', 'target_evidence_refresh_required' => 'Refresh target evidence before relying on this subject.', - 'target_already_aligned' => 'Target tenant already matches the source for this subject.', - 'target_subject_requires_update' => 'Target tenant differs from the source but has enough evidence for later promotion planning.', - 'target_subject_missing' => 'Target tenant does not currently contain this subject and can be planned as a missing target item.', + 'target_already_aligned' => 'Target environment already matches the source for this subject.', + 'target_subject_requires_update' => 'Target environment differs from the source but has enough evidence for later promotion planning.', + 'target_subject_missing' => 'Target environment does not currently contain this subject and can be planned as a missing target item.', default => 'This subject needs additional review before promotion planning can continue.', }; } diff --git a/apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php b/apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewFingerprint.php similarity index 98% rename from apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php rename to apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewFingerprint.php index c59b535d..cf18f8ed 100644 --- a/apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php +++ b/apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewFingerprint.php @@ -8,7 +8,7 @@ use App\Support\Tenants\TenantRecoveryTriagePresentation; use JsonException; -final class TenantTriageReviewFingerprint +final class ManagedEnvironmentTriageReviewFingerprint { /** * @param array|null $recoveryEvidence diff --git a/apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php b/apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewStateResolver.php similarity index 88% rename from apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php rename to apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewStateResolver.php index bb748300..8c7dc27e 100644 --- a/apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php +++ b/apps/platform/app/Support/PortfolioTriage/ManagedEnvironmentTriageReviewStateResolver.php @@ -4,13 +4,13 @@ namespace App\Support\PortfolioTriage; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Support\BackupHealth\TenantBackupHealthAssessment; -final readonly class TenantTriageReviewStateResolver +final readonly class ManagedEnvironmentTriageReviewStateResolver { public function __construct( - private TenantTriageReviewFingerprint $fingerprints, + private ManagedEnvironmentTriageReviewFingerprint $fingerprints, ) {} /** @@ -52,7 +52,7 @@ public function resolveMany( ]; } - $activeReviews = TenantTriageReview::query() + $activeReviews = ManagedEnvironmentTriageReview::query() ->with('reviewer:id,name,email') ->forWorkspace($workspaceId) ->whereIn('managed_environment_id', $tenantIds) @@ -92,9 +92,9 @@ public function resolveMany( $summaries[$family]['affected_total']++; match ($row['derived_state']) { - TenantTriageReview::STATE_REVIEWED => $summaries[$family]['reviewed_count']++, - TenantTriageReview::STATE_FOLLOW_UP_NEEDED => $summaries[$family]['follow_up_needed_count']++, - TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW => $summaries[$family]['changed_since_review_count']++, + ManagedEnvironmentTriageReview::STATE_REVIEWED => $summaries[$family]['reviewed_count']++, + ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED => $summaries[$family]['follow_up_needed_count']++, + ManagedEnvironmentTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW => $summaries[$family]['changed_since_review_count']++, default => $summaries[$family]['not_reviewed_count']++, }; } @@ -119,7 +119,7 @@ private function resolveFamily( int $tenantId, string $concernFamily, ?array $currentConcern, - ?TenantTriageReview $activeReview, + ?ManagedEnvironmentTriageReview $activeReview, ): array { $reviewerName = null; @@ -147,8 +147,8 @@ private function resolveFamily( } $derivedState = match (true) { - ! $activeReview instanceof TenantTriageReview => TenantTriageReview::DERIVED_STATE_NOT_REVIEWED, - $activeReview->review_fingerprint !== $currentConcern['fingerprint'] => TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, + ! $activeReview instanceof ManagedEnvironmentTriageReview => ManagedEnvironmentTriageReview::DERIVED_STATE_NOT_REVIEWED, + $activeReview->review_fingerprint !== $currentConcern['fingerprint'] => ManagedEnvironmentTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, default => (string) $activeReview->current_state, }; diff --git a/apps/platform/app/Support/PortfolioTriage/PortfolioArrivalContextResolver.php b/apps/platform/app/Support/PortfolioTriage/PortfolioArrivalContextResolver.php index f2f92135..5d14d9c1 100644 --- a/apps/platform/app/Support/PortfolioTriage/PortfolioArrivalContextResolver.php +++ b/apps/platform/app/Support/PortfolioTriage/PortfolioArrivalContextResolver.php @@ -6,7 +6,7 @@ use App\Filament\Resources\BackupSetResource; use App\Filament\Resources\RestoreRunResource; -use App\Filament\Resources\TenantResource; +use App\Filament\Resources\ManagedEnvironmentResource; use App\Models\RestoreRun; use App\Models\ManagedEnvironment; use App\Models\User; @@ -474,19 +474,19 @@ private function sanitizeRegistryReturnFilters(array $filters): array { $sanitized = []; - $backupPostures = TenantResource::sanitizeBackupPostures($filters['backup_posture'] ?? []); + $backupPostures = ManagedEnvironmentResource::sanitizeBackupPostures($filters['backup_posture'] ?? []); if ($backupPostures !== []) { $sanitized['backup_posture'] = $backupPostures; } - $recoveryEvidence = TenantResource::sanitizeRecoveryEvidenceStates($filters['recovery_evidence'] ?? []); + $recoveryEvidence = ManagedEnvironmentResource::sanitizeRecoveryEvidenceStates($filters['recovery_evidence'] ?? []); if ($recoveryEvidence !== []) { $sanitized['recovery_evidence'] = $recoveryEvidence; } - $triageSort = TenantResource::sanitizeTriageSort($filters['triage_sort'] ?? null); + $triageSort = ManagedEnvironmentResource::sanitizeTriageSort($filters['triage_sort'] ?? null); if ($triageSort !== null) { $sanitized['triage_sort'] = $triageSort; diff --git a/apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php b/apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php index 81d2c0f5..640c0df3 100644 --- a/apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php +++ b/apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php @@ -6,19 +6,19 @@ use App\Models\ManagedEnvironment; use App\Models\ProviderConnection; -use App\Services\Intune\TenantRequiredPermissionsViewModelBuilder; +use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder; use App\Support\Links\RequiredPermissionsLinks; use App\Support\Providers\ProviderConsentStatus; use App\Support\Providers\ProviderReasonCodes; use App\Support\Providers\ProviderVerificationStatus; -use App\Support\Verification\TenantPermissionCheckClusters; +use App\Support\Verification\ManagedEnvironmentPermissionCheckClusters; use InvalidArgumentException; final class ProviderCapabilityEvaluator { public function __construct( private readonly ProviderCapabilityRegistry $registry, - private readonly TenantRequiredPermissionsViewModelBuilder $requiredPermissionsViewModelBuilder, + private readonly ManagedEnvironmentRequiredPermissionsViewModelBuilder $requiredPermissionsViewModelBuilder, ) {} /** @@ -267,7 +267,7 @@ private function evaluatePermissionRequirements( continue; } - $requirementRows[$requirementKey] = TenantPermissionCheckClusters::rowsForRequirementKey($permissions, $requirementKey); + $requirementRows[$requirementKey] = ManagedEnvironmentPermissionCheckClusters::rowsForRequirementKey($permissions, $requirementKey); } $allRows = array_values(array_merge(...array_values($requirementRows ?: [[]]))); diff --git a/apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php b/apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php index 2bf117e4..52b13762 100644 --- a/apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php +++ b/apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php @@ -7,7 +7,7 @@ use App\Filament\Resources\FindingResource; use App\Filament\Resources\ProviderConnectionResource; use App\Filament\Resources\ReviewPackResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\AuditLog; use App\Models\Finding; use App\Models\OperationRun; @@ -15,7 +15,7 @@ use App\Models\ReviewPack; use App\Models\StoredReport; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; use App\Support\Ai\AiDataClassification; @@ -40,7 +40,7 @@ final class SupportDiagnosticBundleBuilder 'operation_context', 'findings', 'stored_reports', - 'tenant_review', + 'environment_review', 'review_pack', 'audit_history', ]; @@ -64,8 +64,8 @@ public function forTenant(ManagedEnvironment $tenant, ?User $actor = null): arra $operationRun = $this->tenantOperationRun($tenant); $findings = $this->tenantFindings($tenant); $storedReports = $this->tenantStoredReports($tenant); - $tenantReview = $this->tenantReview($tenant); - $reviewPack = $this->tenantReviewPack($tenant, $tenantReview); + $environmentReview = $this->environmentReview($tenant); + $reviewPack = $this->environmentReviewPack($tenant, $environmentReview); $auditLogs = $this->tenantAuditLogs($tenant); return $this->bundle( @@ -82,7 +82,7 @@ public function forTenant(ManagedEnvironment $tenant, ?User $actor = null): arra $this->operationContextSection($operationRun, $tenant), $this->findingsSection($findings, $tenant), $this->storedReportsSection($storedReports), - $this->tenantReviewSection($tenantReview, $tenant), + $this->environmentReviewSection($environmentReview, $tenant), $this->reviewPackSection($reviewPack, $tenant), $this->auditHistorySection($auditLogs), ], @@ -103,8 +103,8 @@ public function forOperationRun(OperationRun $run, ?User $actor = null): array : null; $findings = $tenant instanceof ManagedEnvironment ? $this->operationFindings($run, $tenant) : collect(); $storedReports = $tenant instanceof ManagedEnvironment ? $this->tenantStoredReports($tenant) : collect(); - $tenantReview = $tenant instanceof ManagedEnvironment ? $this->operationTenantReview($run, $tenant) : null; - $reviewPack = $tenant instanceof ManagedEnvironment ? $this->operationReviewPack($run, $tenant, $tenantReview) : null; + $environmentReview = $tenant instanceof ManagedEnvironment ? $this->operationEnvironmentReview($run, $tenant) : null; + $reviewPack = $tenant instanceof ManagedEnvironment ? $this->operationReviewPack($run, $tenant, $environmentReview) : null; $auditLogs = $this->operationAuditLogs($run); $runSummary = $this->runSummaryBuilder->build($run); $runSummaryArray = $runSummary?->toArray(); @@ -127,7 +127,7 @@ public function forOperationRun(OperationRun $run, ?User $actor = null): array $this->operationContextSection($run, $tenant, $runSummaryArray), $this->findingsSection($findings, $tenant), $this->storedReportsSection($storedReports), - $this->tenantReviewSection($tenantReview, $tenant), + $this->environmentReviewSection($environmentReview, $tenant), $this->reviewPackSection($reviewPack, $tenant), $this->auditHistorySection($auditLogs), ], @@ -375,9 +375,9 @@ private function tenantStoredReports(ManagedEnvironment $tenant): Collection ->get(); } - private function tenantReview(ManagedEnvironment $tenant): ?TenantReview + private function environmentReview(ManagedEnvironment $tenant): ?EnvironmentReview { - return TenantReview::query() + return EnvironmentReview::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('workspace_id', (int) $tenant->workspace_id) ->orderByDesc('generated_at') @@ -385,9 +385,9 @@ private function tenantReview(ManagedEnvironment $tenant): ?TenantReview ->first(); } - private function operationTenantReview(OperationRun $run, ManagedEnvironment $tenant): ?TenantReview + private function operationEnvironmentReview(OperationRun $run, ManagedEnvironment $tenant): ?EnvironmentReview { - $review = TenantReview::query() + $review = EnvironmentReview::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('workspace_id', (int) $tenant->workspace_id) ->where('operation_run_id', (int) $run->getKey()) @@ -395,14 +395,14 @@ private function operationTenantReview(OperationRun $run, ManagedEnvironment $te ->orderByDesc('id') ->first(); - return $review instanceof TenantReview ? $review : $this->tenantReview($tenant); + return $review instanceof EnvironmentReview ? $review : $this->environmentReview($tenant); } - private function tenantReviewPack(ManagedEnvironment $tenant, ?TenantReview $tenantReview): ?ReviewPack + private function environmentReviewPack(ManagedEnvironment $tenant, ?EnvironmentReview $environmentReview): ?ReviewPack { - if ($tenantReview instanceof TenantReview && is_numeric($tenantReview->current_export_review_pack_id)) { + if ($environmentReview instanceof EnvironmentReview && is_numeric($environmentReview->current_export_review_pack_id)) { $pack = ReviewPack::query() - ->whereKey((int) $tenantReview->current_export_review_pack_id) + ->whereKey((int) $environmentReview->current_export_review_pack_id) ->where('managed_environment_id', (int) $tenant->getKey()) ->where('workspace_id', (int) $tenant->workspace_id) ->first(); @@ -420,7 +420,7 @@ private function tenantReviewPack(ManagedEnvironment $tenant, ?TenantReview $ten ->first(); } - private function operationReviewPack(OperationRun $run, ManagedEnvironment $tenant, ?TenantReview $tenantReview): ?ReviewPack + private function operationReviewPack(OperationRun $run, ManagedEnvironment $tenant, ?EnvironmentReview $environmentReview): ?ReviewPack { $pack = ReviewPack::query() ->where('managed_environment_id', (int) $tenant->getKey()) @@ -430,7 +430,7 @@ private function operationReviewPack(OperationRun $run, ManagedEnvironment $tena ->orderByDesc('id') ->first(); - return $pack instanceof ReviewPack ? $pack : $this->tenantReviewPack($tenant, $tenantReview); + return $pack instanceof ReviewPack ? $pack : $this->environmentReviewPack($tenant, $environmentReview); } /** @@ -714,34 +714,34 @@ private function storedReportsSection(Collection $reports): array ); } - private function tenantReviewSection(?TenantReview $review, ?ManagedEnvironment $tenant): array + private function environmentReviewSection(?EnvironmentReview $review, ?ManagedEnvironment $tenant): array { - if (! $review instanceof TenantReview) { + if (! $review instanceof EnvironmentReview) { return $this->section( - key: 'tenant_review', + key: 'environment_review', label: 'ManagedEnvironment review', availability: 'missing', - summary: 'No tenant review was found for this support context.', + summary: 'No environment review was found for this support context.', references: [ - $this->missingReference('tenant_review', 'ManagedEnvironment review not yet observed', 'Open environment review'), + $this->missingReference('environment_review', 'ManagedEnvironment review not yet observed', 'Open environment review'), ], ); } return $this->section( - key: 'tenant_review', + key: 'environment_review', label: 'ManagedEnvironment review', availability: 'available', - summary: sprintf('Latest tenant review is %s with %s completeness.', (string) $review->status, (string) $review->completeness_state), + summary: sprintf('Latest environment review is %s with %s completeness.', (string) $review->status, (string) $review->completeness_state), freshnessNote: $this->freshnessNote($review->generated_at, 'Generated'), references: [ $this->modelReference( - type: 'tenant_review', + type: 'environment_review', record: $review, label: 'ManagedEnvironment review #'.$review->getKey(), actionLabel: 'Open environment review', url: $tenant instanceof ManagedEnvironment - ? TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) + ? EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant) : null, freshnessAt: $review->generated_at, ), diff --git a/apps/platform/app/Support/Tenants/TenantActionContext.php b/apps/platform/app/Support/Tenants/TenantActionContext.php index 823dfa3f..d8594b67 100644 --- a/apps/platform/app/Support/Tenants/TenantActionContext.php +++ b/apps/platform/app/Support/Tenants/TenantActionContext.php @@ -5,7 +5,7 @@ namespace App\Support\Tenants; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; final readonly class TenantActionContext @@ -17,7 +17,7 @@ public function __construct( public ?User $actor, public ?int $workspaceId, public TenantInteractionLane $lane, - public ?TenantOnboardingSession $relatedOnboardingDraft, + public ?ManagedEnvironmentOnboardingSession $relatedOnboardingDraft, public bool $relatedOnboardingIsResumable, public bool $hasRelatedOnboardingDraft, public bool $isArchived, diff --git a/apps/platform/app/Support/Tenants/TenantOperabilityContext.php b/apps/platform/app/Support/Tenants/TenantOperabilityContext.php index 18e1a7b7..7316e299 100644 --- a/apps/platform/app/Support/Tenants/TenantOperabilityContext.php +++ b/apps/platform/app/Support/Tenants/TenantOperabilityContext.php @@ -5,7 +5,7 @@ namespace App\Support\Tenants; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; final readonly class TenantOperabilityContext @@ -18,7 +18,7 @@ public function __construct( public ?TenantPageCategory $pageCategory = null, public ?string $linkedRecordType = null, public ?int $linkedRecordId = null, - public ?TenantOnboardingSession $onboardingDraft = null, + public ?ManagedEnvironmentOnboardingSession $onboardingDraft = null, public ?string $requiredCapability = null, public ?ManagedEnvironment $selectedTenant = null, ) {} @@ -29,7 +29,7 @@ public static function forTenant( ?int $workspaceId = null, TenantInteractionLane $lane = TenantInteractionLane::AdministrativeManagement, ?TenantPageCategory $pageCategory = null, - ?TenantOnboardingSession $onboardingDraft = null, + ?ManagedEnvironmentOnboardingSession $onboardingDraft = null, ?string $requiredCapability = null, ?ManagedEnvironment $selectedTenant = null, ?string $linkedRecordType = null, diff --git a/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php b/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php index 2355be35..023706cf 100644 --- a/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php +++ b/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php @@ -5,7 +5,7 @@ namespace App\Support\Ui\ActionSurface; use App\Filament\Pages\BreakGlassRecovery; -use App\Filament\Pages\ChooseTenant; +use App\Filament\Pages\ChooseEnvironment; use App\Filament\Pages\ChooseWorkspace; use App\Filament\Pages\BaselineCompareLanding; use App\Filament\Pages\BaselineCompareMatrix; @@ -16,11 +16,11 @@ use App\Filament\Pages\Monitoring\Operations; use App\Filament\Pages\Operations\TenantlessOperationRunViewer; use App\Filament\Pages\Reviews\ReviewRegister; -use App\Filament\Pages\TenantDashboard; -use App\Filament\Pages\TenantDiagnostics; +use App\Filament\Pages\EnvironmentDashboard; +use App\Filament\Pages\EnvironmentDiagnostics; use App\Filament\Pages\Tenancy\RegisterTenant; -use App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard; -use App\Filament\Pages\Workspaces\ManagedTenantsLanding; +use App\Filament\Pages\Workspaces\ManagedEnvironmentOnboardingWizard; +use App\Filament\Pages\Workspaces\ManagedEnvironmentsLanding; use App\Filament\Resources\AlertDeliveryResource\Pages\ListAlertDeliveries; use App\Filament\Resources\AlertDestinationResource\Pages\ViewAlertDestination; use App\Filament\Resources\BackupSetResource\Pages\ViewBackupSet; @@ -32,9 +32,9 @@ use App\Filament\Resources\PolicyVersionResource\Pages\ViewPolicyVersion; use App\Filament\Resources\ProviderConnectionResource\Pages\ViewProviderConnection; use App\Filament\Resources\ReviewPackResource\Pages\ViewReviewPack; -use App\Filament\Resources\TenantResource\Pages\EditTenant; -use App\Filament\Resources\TenantResource\Pages\ViewTenant; -use App\Filament\Resources\TenantReviewResource\Pages\ViewTenantReview; +use App\Filament\Resources\ManagedEnvironmentResource\Pages\EditManagedEnvironment; +use App\Filament\Resources\ManagedEnvironmentResource\Pages\ViewManagedEnvironment; +use App\Filament\Resources\EnvironmentReviewResource\Pages\ViewEnvironmentReview; use App\Filament\Resources\Workspaces\Pages\ViewWorkspace; use App\Filament\System\Pages\Dashboard as SystemDashboard; use App\Filament\System\Pages\Directory\ViewTenant as SystemDirectoryViewTenant; @@ -60,12 +60,12 @@ public static function baseline(): self // Baseline allowlist for legacy surfaces. Keep shrinking this list. // Declared system table pages are discovered directly; deferred system tooling stays out of scope by not opting in. 'App\\Filament\\Pages\\Auth\\Login' => 'Auth entry page is out-of-scope for action-surface retrofits in spec 082.', - 'App\\Filament\\Pages\\ChooseTenant' => 'ManagedEnvironment chooser has no contract-style table action surface.', + 'App\\Filament\\Pages\\ChooseEnvironment' => 'ManagedEnvironment chooser has no contract-style table action surface.', 'App\\Filament\\Pages\\ChooseWorkspace' => 'Workspace chooser has no contract-style table action surface.', 'App\\Filament\\Pages\\Tenancy\\RegisterTenant' => 'ManagedEnvironment onboarding route is covered by onboarding/RBAC specs.', - 'App\\Filament\\Pages\\TenantDashboard' => 'Dashboard retrofit deferred; widget and summary surfaces are excluded from this contract.', - 'App\\Filament\\Pages\\Workspaces\\ManagedTenantOnboardingWizard' => 'Onboarding wizard has dedicated conformance tests in spec 172 (OnboardingVerificationTest, OnboardingVerificationClustersTest, OnboardingVerificationV1_5UxTest) and remains exempt from blanket discovery.', - 'App\\Filament\\Pages\\Workspaces\\ManagedTenantsLanding' => 'Managed-tenant landing retrofit deferred to workspace feature track.', + 'App\\Filament\\Pages\\EnvironmentDashboard' => 'Dashboard retrofit deferred; widget and summary surfaces are excluded from this contract.', + 'App\\Filament\\Pages\\Workspaces\\ManagedEnvironmentOnboardingWizard' => 'Onboarding wizard has dedicated conformance tests in spec 172 (OnboardingVerificationTest, OnboardingVerificationClustersTest, OnboardingVerificationV1_5UxTest) and remains exempt from blanket discovery.', + 'App\\Filament\\Pages\\Workspaces\\ManagedEnvironmentsLanding' => 'Managed-tenant landing retrofit deferred to workspace feature track.', ], TenantOwnedModelFamilies::actionSurfaceBaselineExemptions())); } @@ -156,8 +156,8 @@ public static function spec192RecordPageInventory(): array 'allowsPrimaryNavigation' => false, 'browserSmokeRequired' => true, ], - ViewTenantReview::class => [ - 'surfaceKey' => 'tenant_review_view', + ViewEnvironmentReview::class => [ + 'surfaceKey' => 'environment_review_view', 'classification' => 'remediation_required', 'canonicalNoun' => 'ManagedEnvironment review', 'panelScope' => 'tenant', @@ -172,7 +172,7 @@ public static function spec192RecordPageInventory(): array 'allowsPrimaryNavigation' => false, 'browserSmokeRequired' => true, ], - EditTenant::class => [ + EditManagedEnvironment::class => [ 'surfaceKey' => 'tenant_edit', 'classification' => 'remediation_required', 'canonicalNoun' => 'ManagedEnvironment', @@ -188,7 +188,7 @@ public static function spec192RecordPageInventory(): array 'allowsPrimaryNavigation' => false, 'browserSmokeRequired' => true, ], - ViewTenant::class => [ + ViewManagedEnvironment::class => [ 'surfaceKey' => 'tenant_view', 'classification' => 'workflow_heavy_special_type', 'canonicalNoun' => 'ManagedEnvironment', @@ -494,7 +494,7 @@ public static function spec193MonitoringSurfaceInventory(): array 'exceptionReason' => null, 'browserSmokeRequired' => true, ], - TenantDiagnostics::class => [ + EnvironmentDiagnostics::class => [ 'surfaceKey' => 'tenant_diagnostics', 'classification' => 'special_type_acceptable', 'canonicalNoun' => 'ManagedEnvironment diagnostics', @@ -818,10 +818,10 @@ public static function spec195ResidualSurfaceInventory(): array 'mustRemainBaselineExempt' => true, 'mustNotRemainBaselineExempt' => false, ], - ChooseTenant::class => [ - 'surfaceKey' => 'choose_tenant', + ChooseEnvironment::class => [ + 'surfaceKey' => 'choose_environment', 'surfaceName' => 'Choose ManagedEnvironment', - 'pageClass' => ChooseTenant::class, + 'pageClass' => ChooseEnvironment::class, 'panelPlane' => 'tenant', 'surfaceKind' => 'selector', 'discoveryState' => 'primary_discovered_baseline_exempt', @@ -870,10 +870,10 @@ public static function spec195ResidualSurfaceInventory(): array 'mustRemainBaselineExempt' => true, 'mustNotRemainBaselineExempt' => false, ], - ManagedTenantOnboardingWizard::class => [ - 'surfaceKey' => 'managed_tenant_onboarding_wizard', + ManagedEnvironmentOnboardingWizard::class => [ + 'surfaceKey' => 'managed_environment_onboarding_wizard', 'surfaceName' => 'Managed ManagedEnvironment Onboarding Wizard', - 'pageClass' => ManagedTenantOnboardingWizard::class, + 'pageClass' => ManagedEnvironmentOnboardingWizard::class, 'panelPlane' => 'admin', 'surfaceKind' => 'wizard', 'discoveryState' => 'primary_discovered_baseline_exempt', @@ -896,10 +896,10 @@ public static function spec195ResidualSurfaceInventory(): array 'mustRemainBaselineExempt' => true, 'mustNotRemainBaselineExempt' => false, ], - ManagedTenantsLanding::class => [ - 'surfaceKey' => 'managed_tenants_landing', + ManagedEnvironmentsLanding::class => [ + 'surfaceKey' => 'managed_environments_landing', 'surfaceName' => 'Managed Tenants Landing', - 'pageClass' => ManagedTenantsLanding::class, + 'pageClass' => ManagedEnvironmentsLanding::class, 'panelPlane' => 'admin', 'surfaceKind' => 'landing', 'discoveryState' => 'primary_discovered_baseline_exempt', @@ -909,12 +909,12 @@ public static function spec195ResidualSurfaceInventory(): array 'evidence' => [ [ 'kind' => 'feature_livewire_test', - 'reference' => 'tests/Feature/Workspaces/Spec195ManagedTenantsLandingTest.php', + 'reference' => 'tests/Feature/Workspaces/Spec195ManagedEnvironmentsLandingTest.php', 'proves' => 'The landing stays membership-scoped, preserves selector routing, and rejects outsider tenant openings.', ], [ 'kind' => 'feature_livewire_test', - 'reference' => 'tests/Feature/Filament/ManagedTenantsLandingLifecycleTest.php', + 'reference' => 'tests/Feature/Filament/ManagedEnvironmentsLandingLifecycleTest.php', 'proves' => 'The landing intentionally exposes broader administrative discoverability than the tenant chooser.', ], ], @@ -922,10 +922,10 @@ public static function spec195ResidualSurfaceInventory(): array 'mustRemainBaselineExempt' => true, 'mustNotRemainBaselineExempt' => false, ], - TenantDashboard::class => [ + EnvironmentDashboard::class => [ 'surfaceKey' => 'tenant_dashboard', 'surfaceName' => 'ManagedEnvironment Dashboard', - 'pageClass' => TenantDashboard::class, + 'pageClass' => EnvironmentDashboard::class, 'panelPlane' => 'tenant', 'surfaceKind' => 'dashboard_shell', 'discoveryState' => 'primary_discovered_baseline_exempt', diff --git a/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceValidator.php b/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceValidator.php index 24b029ca..ae655c2a 100644 --- a/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceValidator.php +++ b/apps/platform/app/Support/Ui/ActionSurface/ActionSurfaceValidator.php @@ -1098,9 +1098,9 @@ private static function qualifiesAsSpec195BaselineResidualCandidate(string $clas { if (in_array($className, [ 'App\\Filament\\Pages\\BreakGlassRecovery', - 'App\\Filament\\Pages\\ChooseTenant', + 'App\\Filament\\Pages\\ChooseEnvironment', 'App\\Filament\\Pages\\ChooseWorkspace', - 'App\\Filament\\Pages\\TenantDashboard', + 'App\\Filament\\Pages\\EnvironmentDashboard', ], true)) { return true; } diff --git a/apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php b/apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php index 4098b481..77e89721 100644 --- a/apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php +++ b/apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php @@ -42,10 +42,10 @@ public static function families(): array 'familyKey' => 'review_lifecycle', 'canonicalObject' => 'review', 'panels' => ['tenant'], - 'surfaceKeys' => ['view_tenant_review'], + 'surfaceKeys' => ['view_environment_review'], 'defaultActionOrder' => ['refresh_review', 'publish_review', 'archive_review'], 'supportsDocumentedDeviation' => true, - 'defaultMutationScopeSource' => 'tenant review lifecycle', + 'defaultMutationScopeSource' => 'environment review lifecycle', ], 'evidence_lifecycle' => [ 'familyKey' => 'evidence_lifecycle', @@ -156,11 +156,11 @@ public static function rules(): array dangerPolicy: 'none', canonicalLabel: 'Refresh review', modalHeading: 'Refresh review', - modalDescription: 'Refresh this tenant review from the latest eligible evidence basis. TenantPilot queues a recomputation for this review and keeps existing publication history untouched.', + modalDescription: 'Refresh this environment review from the latest eligible evidence basis. TenantPilot queues a recomputation for this review and keeps existing publication history untouched.', successTitle: 'Refresh review queued', auditVerb: 'refresh review', - serviceOwner: 'TenantReviewService', - surfaceKeys: ['view_tenant_review'], + serviceOwner: 'EnvironmentReviewService', + surfaceKeys: ['view_environment_review'], ), 'publish_review' => new GovernanceActionRule( actionKey: 'publish_review', @@ -170,11 +170,11 @@ public static function rules(): array dangerPolicy: 'none', canonicalLabel: 'Publish review', modalHeading: 'Publish review', - modalDescription: 'Publish this tenant review as the current governed review outcome for this tenant. TenantPilot records the publication decision only.', + modalDescription: 'Publish this environment review as the current governed review outcome for this tenant. TenantPilot records the publication decision only.', successTitle: 'Review published', auditVerb: 'publish review', - serviceOwner: 'TenantReviewLifecycleService', - surfaceKeys: ['view_tenant_review'], + serviceOwner: 'EnvironmentReviewLifecycleService', + surfaceKeys: ['view_environment_review'], ), 'archive_review' => new GovernanceActionRule( actionKey: 'archive_review', @@ -184,11 +184,11 @@ public static function rules(): array dangerPolicy: 'required', canonicalLabel: 'Archive review', modalHeading: 'Archive review', - modalDescription: 'Archive this tenant review so it stays historical only. TenantPilot preserves the evidence history but removes the review from active lifecycle work.', + modalDescription: 'Archive this environment review so it stays historical only. TenantPilot preserves the evidence history but removes the review from active lifecycle work.', successTitle: 'Review archived', auditVerb: 'archive review', - serviceOwner: 'TenantReviewLifecycleService', - surfaceKeys: ['view_tenant_review'], + serviceOwner: 'EnvironmentReviewLifecycleService', + surfaceKeys: ['view_environment_review'], ), 'refresh_evidence' => new GovernanceActionRule( actionKey: 'refresh_evidence', @@ -313,7 +313,7 @@ public static function rules(): array modalDescription: 'Archive this environment. TenantPilot keeps it available for inspection and audit history but removes it from active management flows.', successTitle: 'Environment archived', auditVerb: 'archive environment', - serviceOwner: 'TenantResource', + serviceOwner: 'ManagedEnvironmentResource', surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'], ), 'restore_tenant' => new GovernanceActionRule( @@ -327,7 +327,7 @@ public static function rules(): array modalDescription: 'Restore this environment so it becomes available again in normal management flows.', successTitle: 'Environment restored', auditVerb: 'restore environment', - serviceOwner: 'TenantResource', + serviceOwner: 'ManagedEnvironmentResource', surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'], ), ]; @@ -438,35 +438,35 @@ public static function surfaceBindings(): array 'auditChannel' => 'workspace_audit', ], [ - 'surfaceKey' => 'view_tenant_review', - 'pageClass' => 'App\\Filament\\Resources\\TenantReviewResource\\Pages\\ViewTenantReview', + 'surfaceKey' => 'view_environment_review', + 'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview', 'actionName' => 'refresh_review', 'familyKey' => 'review_lifecycle', 'statePredicate' => 'review is mutable', 'primaryOrSecondary' => 'primary', - 'capabilityKey' => 'tenant_review.manage', + 'capabilityKey' => 'environment_review.manage', 'uiFieldKey' => null, 'auditChannel' => 'workspace_audit', ], [ - 'surfaceKey' => 'view_tenant_review', - 'pageClass' => 'App\\Filament\\Resources\\TenantReviewResource\\Pages\\ViewTenantReview', + 'surfaceKey' => 'view_environment_review', + 'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview', 'actionName' => 'publish_review', 'familyKey' => 'review_lifecycle', 'statePredicate' => 'review is mutable and ready to publish', 'primaryOrSecondary' => 'primary', - 'capabilityKey' => 'tenant_review.manage', + 'capabilityKey' => 'environment_review.manage', 'uiFieldKey' => 'publish_reason', 'auditChannel' => 'workspace_audit', ], [ - 'surfaceKey' => 'view_tenant_review', - 'pageClass' => 'App\\Filament\\Resources\\TenantReviewResource\\Pages\\ViewTenantReview', + 'surfaceKey' => 'view_environment_review', + 'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview', 'actionName' => 'archive_review', 'familyKey' => 'review_lifecycle', 'statePredicate' => 'review is not terminal', 'primaryOrSecondary' => 'secondary', - 'capabilityKey' => 'tenant_review.manage', + 'capabilityKey' => 'environment_review.manage', 'uiFieldKey' => 'archive_reason', 'auditChannel' => 'workspace_audit', ], @@ -538,7 +538,7 @@ public static function surfaceBindings(): array ], [ 'surfaceKey' => 'view_tenant', - 'pageClass' => 'App\\Filament\\Resources\\TenantResource\\Pages\\ViewTenant', + 'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\ViewManagedEnvironment', 'actionName' => 'archive', 'familyKey' => 'tenant_lifecycle', 'statePredicate' => 'tenant is active', @@ -549,7 +549,7 @@ public static function surfaceBindings(): array ], [ 'surfaceKey' => 'view_tenant', - 'pageClass' => 'App\\Filament\\Resources\\TenantResource\\Pages\\ViewTenant', + 'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\ViewManagedEnvironment', 'actionName' => 'restore', 'familyKey' => 'tenant_lifecycle', 'statePredicate' => 'tenant is archived', @@ -560,7 +560,7 @@ public static function surfaceBindings(): array ], [ 'surfaceKey' => 'edit_tenant', - 'pageClass' => 'App\\Filament\\Resources\\TenantResource\\Pages\\EditTenant', + 'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\EditManagedEnvironment', 'actionName' => 'archive', 'familyKey' => 'tenant_lifecycle', 'statePredicate' => 'tenant is active', @@ -571,7 +571,7 @@ public static function surfaceBindings(): array ], [ 'surfaceKey' => 'edit_tenant', - 'pageClass' => 'App\\Filament\\Resources\\TenantResource\\Pages\\EditTenant', + 'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\EditManagedEnvironment', 'actionName' => 'restore', 'familyKey' => 'tenant_lifecycle', 'statePredicate' => 'tenant is archived', diff --git a/apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php b/apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php index c7a2fb8f..80eb16d5 100644 --- a/apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php +++ b/apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php @@ -7,14 +7,14 @@ use App\Filament\Resources\BaselineSnapshotResource; use App\Filament\Resources\EvidenceSnapshotResource; use App\Filament\Resources\ReviewPackResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\BaselineSnapshot; use App\Models\EvidenceSnapshot; use App\Models\FindingExceptionDecision; use App\Models\OperationRun; use App\Models\ReviewPack; use App\Models\StoredReport; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Services\Baselines\BaselineSnapshotTruthResolver; use App\Services\Baselines\SnapshotRendering\FidelityState; use App\Support\Badges\BadgeCatalog; @@ -28,8 +28,8 @@ use App\Support\ReasonTranslation\ReasonPresenter; use App\Support\ReasonTranslation\ReasonResolutionEnvelope; use App\Support\ReviewPackStatus; -use App\Support\TenantReviewCompletenessState; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewCompletenessState; +use App\Support\EnvironmentReviewStatus; use App\Support\Ui\DerivedState\DerivedStateFamily; use App\Support\Ui\DerivedState\DerivedStateKey; use App\Support\Ui\DerivedState\RequestScopedDerivedStateStore; @@ -54,7 +54,7 @@ public function for(mixed $record): ?ArtifactTruthEnvelope return match (true) { $record instanceof BaselineSnapshot => $this->forBaselineSnapshot($record), $record instanceof EvidenceSnapshot => $this->forEvidenceSnapshot($record), - $record instanceof TenantReview => $this->forTenantReview($record), + $record instanceof EnvironmentReview => $this->forEnvironmentReview($record), $record instanceof ReviewPack => $this->forReviewPack($record), $record instanceof StoredReport => $this->forStoredReport($record), $record instanceof FindingExceptionDecision => $this->forFindingExceptionDecision($record), @@ -68,7 +68,7 @@ public function forFresh(mixed $record): ?ArtifactTruthEnvelope return match (true) { $record instanceof BaselineSnapshot => $this->forBaselineSnapshotFresh($record), $record instanceof EvidenceSnapshot => $this->forEvidenceSnapshotFresh($record), - $record instanceof TenantReview => $this->forTenantReviewFresh($record), + $record instanceof EnvironmentReview => $this->forEnvironmentReviewFresh($record), $record instanceof ReviewPack => $this->forReviewPackFresh($record), $record instanceof StoredReport => $this->forStoredReportFresh($record), $record instanceof FindingExceptionDecision => $this->forFindingExceptionDecisionFresh($record), @@ -469,26 +469,26 @@ private function buildEvidenceSnapshotEnvelope(EvidenceSnapshot $snapshot): Arti ); } - public function forTenantReview(TenantReview $review): ArtifactTruthEnvelope + public function forEnvironmentReview(EnvironmentReview $review): ArtifactTruthEnvelope { return $this->resolveEnvelope( record: $review, - variant: 'tenant_review', - resolver: fn (): ArtifactTruthEnvelope => $this->buildTenantReviewEnvelope($review), + variant: 'environment_review', + resolver: fn (): ArtifactTruthEnvelope => $this->buildEnvironmentReviewEnvelope($review), ); } - public function forTenantReviewFresh(TenantReview $review): ArtifactTruthEnvelope + public function forEnvironmentReviewFresh(EnvironmentReview $review): ArtifactTruthEnvelope { return $this->resolveEnvelope( record: $review, - variant: 'tenant_review', - resolver: fn (): ArtifactTruthEnvelope => $this->buildTenantReviewEnvelope($review), + variant: 'environment_review', + resolver: fn (): ArtifactTruthEnvelope => $this->buildEnvironmentReviewEnvelope($review), fresh: true, ); } - private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthEnvelope + private function buildEnvironmentReviewEnvelope(EnvironmentReview $review): ArtifactTruthEnvelope { $review->loadMissing(['tenant', 'currentExportReviewPack', 'evidenceSnapshot']); @@ -501,23 +501,23 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE $sourceEvidence = $this->evidenceTrustBurden($review->evidenceSnapshot); $artifactExistence = match ($status) { - TenantReviewStatus::Archived, TenantReviewStatus::Superseded => 'historical_only', - TenantReviewStatus::Failed => 'created_but_not_usable', + EnvironmentReviewStatus::Archived, EnvironmentReviewStatus::Superseded => 'historical_only', + EnvironmentReviewStatus::Failed => 'created_but_not_usable', default => 'created', }; $contentState = match (true) { - $completeness === TenantReviewCompletenessState::Missing->value => 'missing_input', - $completeness === TenantReviewCompletenessState::Partial->value || $sourceEvidence['isPartial'] => 'partial', + $completeness === EnvironmentReviewCompletenessState::Missing->value => 'missing_input', + $completeness === EnvironmentReviewCompletenessState::Partial->value || $sourceEvidence['isPartial'] => 'partial', $sourceEvidence['isMissing'] => 'missing_input', - $completeness === TenantReviewCompletenessState::Complete->value => 'trusted', - $completeness === TenantReviewCompletenessState::Stale->value => 'trusted', + $completeness === EnvironmentReviewCompletenessState::Complete->value => 'trusted', + $completeness === EnvironmentReviewCompletenessState::Stale->value => 'trusted', default => 'partial', }; $freshnessState = match (true) { $artifactExistence === 'historical_only' => 'stale', - $completeness === TenantReviewCompletenessState::Stale->value || $staleSections > 0 || $sourceEvidence['isStale'] => 'stale', + $completeness === EnvironmentReviewCompletenessState::Stale->value || $staleSections > 0 || $sourceEvidence['isStale'] => 'stale', default => 'current', }; @@ -526,8 +526,8 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE $publishBlockers !== [] => 'blocked', $contentState === 'missing_input' => 'blocked', $freshnessState === 'stale' || $contentState === 'partial' => 'internal_only', - $status === TenantReviewStatus::Published => 'publishable', - $status === TenantReviewStatus::Ready => 'publishable', + $status === EnvironmentReviewStatus::Published => 'publishable', + $status === EnvironmentReviewStatus::Ready => 'publishable', default => 'internal_only', }; @@ -541,7 +541,7 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE $reasonCode = match (true) { $publishBlockers !== [] => 'review_publish_blocked', - $status === TenantReviewStatus::Failed => 'review_generation_failed', + $status === EnvironmentReviewStatus::Failed => 'review_generation_failed', $contentState === 'missing_input' => 'review_missing_sections', $freshnessState === 'stale' => 'review_stale_sections', default => null, @@ -600,7 +600,7 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE if ($publishBlockers !== [] && $review->tenant !== null) { $nextActionUrl = $this->panelSafeTenantArtifactUrl( - fn (): string => TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $review->tenant) + fn (): string => EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $review->tenant) ); } elseif (($freshnessState === 'stale' || $contentState === 'partial') && $review->tenant !== null && $review->evidenceSnapshot !== null) { $nextActionUrl = $this->panelSafeTenantArtifactUrl( @@ -609,8 +609,8 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE } return $this->makeEnvelope( - artifactFamily: 'tenant_review', - artifactKey: 'tenant_review:'.$review->getKey(), + artifactFamily: 'environment_review', + artifactKey: 'environment_review:'.$review->getKey(), workspaceId: (int) $review->workspace_id, tenantId: $review->managed_environment_id !== null ? (int) $review->managed_environment_id : null, executionOutcome: null, @@ -642,7 +642,7 @@ private function buildTenantReviewEnvelope(TenantReview $review): ArtifactTruthE relatedRunId: $review->operation_run_id !== null ? (int) $review->operation_run_id : null, relatedArtifactUrl: $review->tenant !== null ? $this->panelSafeTenantArtifactUrl( - fn (): string => TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $review->tenant) + fn (): string => EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $review], $review->tenant) ) : null, includePublicationDimension: true, @@ -692,17 +692,17 @@ public function forReviewPackFresh(ReviewPack $pack): ArtifactTruthEnvelope private function buildReviewPackEnvelope(ReviewPack $pack): ArtifactTruthEnvelope { - $pack->loadMissing(['tenant', 'tenantReview', 'evidenceSnapshot']); + $pack->loadMissing(['tenant', 'environmentReview', 'evidenceSnapshot']); $summary = is_array($pack->summary) ? $pack->summary : []; $status = (string) $pack->status; $evidenceResolution = is_array($summary['evidence_resolution'] ?? null) ? $summary['evidence_resolution'] : []; - $sourceReview = $pack->tenantReview; - $sourceReviewTruth = $sourceReview instanceof TenantReview - ? $this->forTenantReviewFresh($sourceReview) + $sourceReview = $pack->environmentReview; + $sourceReviewTruth = $sourceReview instanceof EnvironmentReview + ? $this->forEnvironmentReviewFresh($sourceReview) : null; - $sourceBlockers = $sourceReview instanceof TenantReview ? $sourceReview->publishBlockers() : []; - $sourceReviewStatus = $sourceReview instanceof TenantReview ? $sourceReview->statusEnum() : null; + $sourceBlockers = $sourceReview instanceof EnvironmentReview ? $sourceReview->publishBlockers() : []; + $sourceReviewStatus = $sourceReview instanceof EnvironmentReview ? $sourceReview->statusEnum() : null; $sourceEvidence = $this->evidenceTrustBurden($pack->evidenceSnapshot); $artifactExistence = match ($status) { @@ -734,7 +734,7 @@ private function buildReviewPackEnvelope(ReviewPack $pack): ArtifactTruthEnvelop $sourceReviewTruth?->publicationReadiness === 'blocked' => 'blocked', $sourceReviewTruth?->publicationReadiness === 'internal_only' => 'internal_only', $freshnessState === 'stale' || $contentState === 'partial' => 'internal_only', - $sourceReviewStatus === TenantReviewStatus::Draft || $sourceReviewStatus === TenantReviewStatus::Failed => 'internal_only', + $sourceReviewStatus === EnvironmentReviewStatus::Draft || $sourceReviewStatus === EnvironmentReviewStatus::Failed => 'internal_only', default => $status === ReviewPackStatus::Ready->value ? 'publishable' : 'blocked', }; @@ -783,9 +783,9 @@ private function buildReviewPackEnvelope(ReviewPack $pack): ArtifactTruthEnvelop $nextActionUrl = null; - if ($sourceReview instanceof TenantReview && $pack->tenant !== null) { + if ($sourceReview instanceof EnvironmentReview && $pack->tenant !== null) { $nextActionUrl = $this->panelSafeTenantArtifactUrl( - fn (): string => TenantReviewResource::tenantScopedUrl('view', ['record' => $sourceReview], $pack->tenant) + fn (): string => EnvironmentReviewResource::tenantScopedUrl('view', ['record' => $sourceReview], $pack->tenant) ); } elseif (($freshnessState === 'stale' || $contentState === 'partial') && $pack->tenant !== null && $pack->evidenceSnapshot !== null) { $nextActionUrl = $this->panelSafeTenantArtifactUrl( @@ -1099,7 +1099,7 @@ private function buildOperationRunEnvelope(OperationRun $run): ArtifactTruthEnve contentState: $contentState, freshnessState: 'unknown', publicationReadiness: OperationCatalog::governanceArtifactFamily((string) $run->type) === 'review_pack' - || OperationCatalog::governanceArtifactFamily((string) $run->type) === 'tenant_review' + || OperationCatalog::governanceArtifactFamily((string) $run->type) === 'environment_review' ? 'blocked' : null, supportState: 'normal', @@ -1120,20 +1120,20 @@ private function buildOperationRunEnvelope(OperationRun $run): ArtifactTruthEnve relatedRunId: (int) $run->getKey(), relatedArtifactUrl: null, includePublicationDimension: OperationCatalog::governanceArtifactFamily((string) $run->type) === 'review_pack' - || OperationCatalog::governanceArtifactFamily((string) $run->type) === 'tenant_review', + || OperationCatalog::governanceArtifactFamily((string) $run->type) === 'environment_review', countDescriptors: $this->runCountDescriptors($run), ); } - private function resolveArtifactForRun(OperationRun $run): BaselineSnapshot|EvidenceSnapshot|TenantReview|ReviewPack|null + private function resolveArtifactForRun(OperationRun $run): BaselineSnapshot|EvidenceSnapshot|EnvironmentReview|ReviewPack|null { return match (OperationCatalog::governanceArtifactFamily((string) $run->type)) { 'baseline_snapshot' => $run->relatedArtifactId() !== null ? BaselineSnapshot::query()->with('baselineProfile')->find($run->relatedArtifactId()) : null, 'evidence_snapshot' => EvidenceSnapshot::query()->with('tenant')->where('operation_run_id', (int) $run->getKey())->latest('id')->first(), - 'tenant_review' => TenantReview::query()->with(['tenant', 'currentExportReviewPack'])->where('operation_run_id', (int) $run->getKey())->latest('id')->first(), - 'review_pack' => ReviewPack::query()->with(['tenant', 'tenantReview'])->where('operation_run_id', (int) $run->getKey())->latest('id')->first(), + 'environment_review' => EnvironmentReview::query()->with(['tenant', 'currentExportReviewPack'])->where('operation_run_id', (int) $run->getKey())->latest('id')->first(), + 'review_pack' => ReviewPack::query()->with(['tenant', 'environmentReview'])->where('operation_run_id', (int) $run->getKey())->latest('id')->first(), default => null, }; } @@ -1549,8 +1549,8 @@ private function reviewPackLifecycleState(ReviewPack $pack): string return 'historical'; } - if ($pack->tenantReview instanceof TenantReview && $pack->tenantReview->current_export_review_pack_id !== null) { - return $pack->tenantReview->current_export_review_pack_id === (int) $pack->getKey() + if ($pack->environmentReview instanceof EnvironmentReview && $pack->environmentReview->current_export_review_pack_id !== null) { + return $pack->environmentReview->current_export_review_pack_id === (int) $pack->getKey() ? 'current' : 'superseded'; } diff --git a/apps/platform/app/Support/Ui/GovernanceArtifactTruth/SurfaceCompressionContext.php b/apps/platform/app/Support/Ui/GovernanceArtifactTruth/SurfaceCompressionContext.php index ea95a475..e3d2befe 100644 --- a/apps/platform/app/Support/Ui/GovernanceArtifactTruth/SurfaceCompressionContext.php +++ b/apps/platform/app/Support/Ui/GovernanceArtifactTruth/SurfaceCompressionContext.php @@ -48,9 +48,9 @@ public static function evidenceSnapshot(): self return self::fromSurfaceFamily('evidence_snapshot'); } - public static function tenantReview(): self + public static function environmentReview(): self { - return self::fromSurfaceFamily('tenant_review'); + return self::fromSurfaceFamily('environment_review'); } public static function reviewPack(): self @@ -78,7 +78,7 @@ public static function defaultForArtifactFamily(string $artifactFamily): self return match ($artifactFamily) { 'baseline_snapshot' => self::baselineSnapshot(), 'evidence_snapshot' => self::evidenceSnapshot(), - 'tenant_review' => self::tenantReview(), + 'environment_review' => self::environmentReview(), 'review_pack' => self::reviewPack(), 'artifact_run' => self::operationRunArtifact(), default => throw new InvalidArgumentException(sprintf('No default compression context exists for artifact family [%s].', $artifactFamily)), @@ -106,8 +106,8 @@ public static function fromSurfaceFamily(string $surfaceFamily): self diagnosticsAllowed: true, canonicalNoun: 'Evidence snapshot', ), - 'tenant_review' => new self( - surfaceFamily: 'tenant_review', + 'environment_review' => new self( + surfaceFamily: 'environment_review', decisionRole: 'primary_decision', primaryQuestion: 'Is this review ready for real use or publication?', primaryDimensionPriority: ['publication_readiness', 'data_freshness', 'content_fidelity'], diff --git a/apps/platform/app/Support/Verification/TenantPermissionCheckClusters.php b/apps/platform/app/Support/Verification/ManagedEnvironmentPermissionCheckClusters.php similarity index 96% rename from apps/platform/app/Support/Verification/TenantPermissionCheckClusters.php rename to apps/platform/app/Support/Verification/ManagedEnvironmentPermissionCheckClusters.php index 2fd78aa0..56308d8d 100644 --- a/apps/platform/app/Support/Verification/TenantPermissionCheckClusters.php +++ b/apps/platform/app/Support/Verification/ManagedEnvironmentPermissionCheckClusters.php @@ -10,10 +10,10 @@ use App\Support\Providers\ProviderNextStepsRegistry; use App\Support\Providers\ProviderReasonCodes; -final class TenantPermissionCheckClusters +final class ManagedEnvironmentPermissionCheckClusters { /** - * @phpstan-type TenantPermissionRow array{ + * @phpstan-type ManagedEnvironmentPermissionRow array{ * key:string, * type:'application'|'delegated', * description:?string, @@ -46,7 +46,7 @@ public static function buildChecks(ManagedEnvironment $tenant, array $permission $inventoryEvidence = self::inventoryEvidence($inventory); - /** @var array $rows */ + /** @var array $rows */ $rows = collect($permissions) ->filter(fn (mixed $row): bool => is_array($row)) ->map(fn (array $row): array => self::normalizePermissionRow($row)) @@ -143,7 +143,7 @@ public static function definitions(): array /** * @param array{mode:string,prefixes?:array,keys?:array,type?:string} $definition - * @param TenantPermissionRow $row + * @param ManagedEnvironmentPermissionRow $row */ public static function matchesDefinition(array $definition, array $row): bool { @@ -181,7 +181,7 @@ public static function matchesDefinition(array $definition, array $row): bool /** * @param array> $permissions - * @return array + * @return array */ public static function rowsForRequirementKey(array $permissions, string $requirementKey): array { @@ -200,7 +200,7 @@ public static function rowsForRequirementKey(array $permissions, string $require } /** - * @param TenantPermissionRow $row + * @param ManagedEnvironmentPermissionRow $row * @return array */ public static function requirementKeysForPermissionRow(array $row): array @@ -228,7 +228,7 @@ public static function definitionForKey(string $requirementKey): ?array } /** - * @param array $clusterRows + * @param array $clusterRows * @return array */ private static function buildCheck( @@ -369,9 +369,9 @@ private static function permissionMissingReasonCode(string $key): string } /** - * @param array $missingApplication - * @param array $missingDelegated - * @param array $errored + * @param array $missingApplication + * @param array $missingDelegated + * @param array $errored * @return array */ private static function evidence(array $missingApplication, array $missingDelegated, array $errored): array @@ -472,7 +472,7 @@ private static function nextSteps(ManagedEnvironment $tenant, string $reasonCode /** * @param array $row - * @return TenantPermissionRow + * @return ManagedEnvironmentPermissionRow */ private static function normalizePermissionRow(array $row): array { diff --git a/apps/platform/app/Support/Verification/VerificationAssistViewModelBuilder.php b/apps/platform/app/Support/Verification/VerificationAssistViewModelBuilder.php index 17bcdebb..3f5725a9 100644 --- a/apps/platform/app/Support/Verification/VerificationAssistViewModelBuilder.php +++ b/apps/platform/app/Support/Verification/VerificationAssistViewModelBuilder.php @@ -6,7 +6,7 @@ use App\Models\ProviderConnection; use App\Models\ManagedEnvironment; -use App\Services\Intune\TenantRequiredPermissionsViewModelBuilder; +use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder; use App\Support\Links\RequiredPermissionsLinks; use App\Support\Providers\ProviderNextStepsRegistry; use App\Support\Providers\ProviderReasonCodes; @@ -14,7 +14,7 @@ final class VerificationAssistViewModelBuilder { public function __construct( - private readonly TenantRequiredPermissionsViewModelBuilder $requiredPermissionsViewModelBuilder, + private readonly ManagedEnvironmentRequiredPermissionsViewModelBuilder $requiredPermissionsViewModelBuilder, private readonly ProviderNextStepsRegistry $providerNextStepsRegistry, ) {} diff --git a/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedModelFamilies.php b/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedModelFamilies.php index 8d910b2b..27dc20c5 100644 --- a/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedModelFamilies.php +++ b/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedModelFamilies.php @@ -15,7 +15,7 @@ use App\Filament\Resources\PolicyVersionResource; use App\Filament\Resources\RestoreRunResource; use App\Filament\Resources\StoredReportResource; -use App\Filament\Resources\TenantReviewResource; +use App\Filament\Resources\EnvironmentReviewResource; use App\Models\BackupSchedule; use App\Models\BackupSet; use App\Models\EntraGroup; @@ -27,7 +27,7 @@ use App\Models\PolicyVersion; use App\Models\RestoreRun; use App\Models\StoredReport; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; final class TenantOwnedModelFamilies { @@ -146,14 +146,14 @@ public static function firstSlice(): array 'action_surface_reason' => 'EntraGroupResource declares its action surface contract directly.', 'notes' => 'Directory groups already support tenant-safe global search.', ], - 'TenantReview' => [ - 'table' => 'tenant_reviews', - 'model' => TenantReview::class, - 'resource' => TenantReviewResource::class, + 'EnvironmentReview' => [ + 'table' => 'environment_reviews', + 'model' => EnvironmentReview::class, + 'resource' => EnvironmentReviewResource::class, 'tenant_relationship' => 'tenant', 'search_posture' => 'disabled', 'action_surface' => 'declared', - 'action_surface_reason' => 'TenantReviewResource declares its action surface contract directly.', + 'action_surface_reason' => 'EnvironmentReviewResource declares its action surface contract directly.', 'notes' => 'ManagedEnvironment reviews stay out of global search and are surfaced through tenant detail plus the canonical register.', ], 'StoredReport' => [ @@ -190,8 +190,8 @@ public static function residualRolloutInventory(): array 'likely_surface' => 'Entra admin-role reporting and findings reference flows', 'why_not_in_first_slice' => 'Read paths remain indirect via reporting and findings surfaces, so direct tenant-owned resource parity is deferred.', ], - 'TenantPermission' => [ - 'table' => 'tenant_permissions', + 'ManagedEnvironmentPermission' => [ + 'table' => 'managed_environment_permissions', 'likely_surface' => 'Permissions and onboarding diagnostics surfaces', 'why_not_in_first_slice' => 'Permission posture is enforced through dedicated diagnostics and onboarding flows, not a first-slice primary resource.', ], diff --git a/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedTables.php b/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedTables.php index 28047a9a..0c14673f 100644 --- a/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedTables.php +++ b/apps/platform/app/Support/WorkspaceIsolation/TenantOwnedTables.php @@ -36,7 +36,7 @@ public static function firstSlice(): array 'inventory_items', 'entra_groups', 'stored_reports', - 'tenant_reviews', + 'environment_reviews', ]; } @@ -49,7 +49,7 @@ public static function residual(): array 'backup_items', 'inventory_links', 'entra_role_definitions', - 'tenant_permissions', + 'managed_environment_permissions', 'finding_exception_decisions', 'finding_exception_evidence_references', ]; diff --git a/apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php b/apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php index 29dfaffd..58c2770f 100644 --- a/apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php +++ b/apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php @@ -5,7 +5,7 @@ namespace App\Support\Workspaces; use App\Filament\Pages\BaselineCompareLanding; -use App\Filament\Pages\ChooseTenant; +use App\Filament\Pages\ChooseEnvironment; use App\Filament\Pages\Findings\FindingsHygieneReport; use App\Filament\Pages\Findings\MyFindingsInbox; use App\Filament\Resources\FindingResource; @@ -14,7 +14,7 @@ use App\Models\FindingException; use App\Models\OperationRun; use App\Models\ManagedEnvironment; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; use App\Models\Workspace; use App\Services\Auth\CapabilityResolver; @@ -36,7 +36,7 @@ use App\Support\OperationRunLinks; use App\Support\OpsUx\OperationUxPresenter; use App\Support\PortfolioTriage\PortfolioArrivalContextToken; -use App\Support\PortfolioTriage\TenantTriageReviewStateResolver; +use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewStateResolver; use App\Support\Rbac\UiTooltips; use App\Support\RestoreSafety\RestoreResultAttention; use App\Support\RestoreSafety\RestoreSafetyCopy; @@ -56,7 +56,7 @@ public function __construct( private TenantGovernanceAggregateResolver $tenantGovernanceAggregateResolver, private TenantBackupHealthResolver $tenantBackupHealthResolver, private RestoreSafetyResolver $restoreSafetyResolver, - private TenantTriageReviewStateResolver $tenantTriageReviewStateResolver, + private ManagedEnvironmentTriageReviewStateResolver $managedEnvironmentTriageReviewStateResolver, ) {} /** @@ -135,7 +135,7 @@ public function build(Workspace $workspace, User $user): array 'title' => $calmness['title'], 'body' => $calmness['body'], 'action_label' => $calmness['next_action']['label'] ?? __('localization.shell.choose_environment'), - 'action_url' => $calmness['next_action']['url'] ?? ChooseTenant::getUrl(panel: 'admin'), + 'action_url' => $calmness['next_action']['url'] ?? ChooseEnvironment::getUrl(panel: 'admin'), ]; $myFindingsSignal = $this->myFindingsSignal($workspaceId, $visibleFindingsTenantIds, $user); @@ -996,7 +996,7 @@ private function summaryMetrics( : 'No managed environments are available in this workspace yet.', color: $accessibleTenantCount > 0 ? 'primary' : 'warning', destination: $accessibleTenantCount > 0 - ? $this->chooseTenantTarget() + ? $this->chooseEnvironmentTarget() : $this->switchWorkspaceTarget(), ), $this->makeSummaryMetric( @@ -1007,7 +1007,7 @@ private function summaryMetrics( description: 'Affected visible environments with overdue findings, governance expiry, lapsed governance, or compare posture that needs review.', color: $governanceAttentionTenantCount > 0 ? 'danger' : 'gray', destination: $governanceAttentionTenantCount > 0 - ? $this->chooseTenantTarget(__('localization.shell.choose_environment')) + ? $this->chooseEnvironmentTarget(__('localization.shell.choose_environment')) : null, ), $this->makeSummaryMetric( @@ -1107,7 +1107,7 @@ private function triageReviewProgress(int $workspaceId, array $tenantContexts): $recoveryEvidenceByTenant[$tenantId] = $context['recovery_evidence'] ?? null; } - $resolved = $this->tenantTriageReviewStateResolver->resolveMany( + $resolved = $this->managedEnvironmentTriageReviewStateResolver->resolveMany( workspaceId: $workspaceId, tenantIds: $tenantIds, backupHealthByTenant: $backupHealthByTenant, @@ -1207,10 +1207,10 @@ private function triageReviewProgressFamilies(array $triageReviewSummaries): arr 'follow_up_needed_count' => (int) ($summary['follow_up_needed_count'] ?? 0), 'changed_since_review_count' => (int) ($summary['changed_since_review_count'] ?? 0), 'not_reviewed_count' => (int) ($summary['not_reviewed_count'] ?? 0), - 'reviewed_destination' => $this->triageReviewBucketDestination($family, TenantTriageReview::STATE_REVIEWED, 'Reviewed'), - 'follow_up_needed_destination' => $this->triageReviewBucketDestination($family, TenantTriageReview::STATE_FOLLOW_UP_NEEDED, 'Follow-up needed'), - 'changed_since_review_destination' => $this->triageReviewBucketDestination($family, TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, 'Changed since review'), - 'not_reviewed_destination' => $this->triageReviewBucketDestination($family, TenantTriageReview::DERIVED_STATE_NOT_REVIEWED, 'Not reviewed'), + 'reviewed_destination' => $this->triageReviewBucketDestination($family, ManagedEnvironmentTriageReview::STATE_REVIEWED, 'Reviewed'), + 'follow_up_needed_destination' => $this->triageReviewBucketDestination($family, ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, 'Follow-up needed'), + 'changed_since_review_destination' => $this->triageReviewBucketDestination($family, ManagedEnvironmentTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW, 'Changed since review'), + 'not_reviewed_destination' => $this->triageReviewBucketDestination($family, ManagedEnvironmentTriageReview::DERIVED_STATE_NOT_REVIEWED, 'Not reviewed'), ]; } @@ -1279,7 +1279,7 @@ private function attentionMetricDestination(array $tenantContexts, User $user, s ], 'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST, ], __('localization.shell.choose_environment')), - default => $this->chooseTenantTarget(__('localization.shell.choose_environment')), + default => $this->chooseEnvironmentTarget(__('localization.shell.choose_environment')), }; } @@ -1388,7 +1388,7 @@ private function calmnessState( 'checked_domains' => $checkedDomains, 'title' => 'Nothing urgent in your visible workspace slice', 'body' => 'Visible governance, backup health, recovery evidence, compare posture, and activity currently look calm. Backup health and recovery evidence are included in this visible workspace calmness check.', - 'next_action' => $this->chooseTenantTarget(), + 'next_action' => $this->chooseEnvironmentTarget(), ]; } @@ -1407,7 +1407,7 @@ private function calmnessState( 'checked_domains' => $checkedDomains, 'title' => 'Visible environments still need attention', 'body' => 'Backup health or recovery evidence still needs follow-up, or governance and activity remain open in this workspace.', - 'next_action' => $attentionItems[0]['destination'] ?? $this->chooseTenantTarget(), + 'next_action' => $attentionItems[0]['destination'] ?? $this->chooseEnvironmentTarget(), ]; } @@ -1449,10 +1449,10 @@ private function quickActions( ): array { $actions = [ [ - 'key' => 'choose_tenant', + 'key' => 'choose_environment', 'label' => __('localization.shell.choose_environment'), 'description' => 'Deliberately enter environment context from this workspace.', - 'url' => ChooseTenant::getUrl(panel: 'admin'), + 'url' => ChooseEnvironment::getUrl(panel: 'admin'), 'icon' => 'heroicon-o-building-office-2', 'color' => 'primary', 'visible' => $accessibleTenantCount > 0, @@ -1528,11 +1528,11 @@ private function tenantRouteKey(ManagedEnvironment $tenant): string /** * @return array */ - private function chooseTenantTarget(?string $label = null): array + private function chooseEnvironmentTarget(?string $label = null): array { return $this->destination( - kind: 'choose_tenant', - url: ChooseTenant::getUrl(panel: 'admin'), + kind: 'choose_environment', + url: ChooseEnvironment::getUrl(panel: 'admin'), label: $label ?? __('localization.shell.choose_environment'), ); } @@ -1544,7 +1544,7 @@ private function chooseTenantTarget(?string $label = null): array private function filteredTenantRegistryTarget(array $filters, ?string $label = null): array { return $this->destination( - kind: 'choose_tenant', + kind: 'choose_environment', url: ManagedEnvironmentLinks::indexUrl(query: $filters), label: $label ?? __('localization.shell.choose_environment'), filters: $filters, @@ -1573,7 +1573,7 @@ private function tenantDashboardTarget( ?array $arrivalState = null, ): array { - if (! $this->canAccessTenantDashboard($user, $tenant)) { + if (! $this->canAccessEnvironmentDashboard($user, $tenant)) { return $this->disabledDestination( kind: 'tenant_dashboard', label: $label, @@ -1757,7 +1757,7 @@ private function canTenantView(User $user, ManagedEnvironment $tenant): bool return $this->capabilityResolver->can($user, $tenant, Capabilities::TENANT_VIEW); } - private function canAccessTenantDashboard(User $user, ManagedEnvironment $tenant): bool + private function canAccessEnvironmentDashboard(User $user, ManagedEnvironment $tenant): bool { return $this->capabilityResolver->isMember($user, $tenant); } diff --git a/apps/platform/config/provider_boundaries.php b/apps/platform/config/provider_boundaries.php index 6b9f9e04..f7dcdfd6 100644 --- a/apps/platform/config/provider_boundaries.php +++ b/apps/platform/config/provider_boundaries.php @@ -99,7 +99,7 @@ 'implementation_paths' => [ 'app/Support/Providers/Capabilities/ProviderCapabilityRegistry.php', 'app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php', - 'app/Support/Verification/TenantPermissionCheckClusters.php', + 'app/Support/Verification/ManagedEnvironmentPermissionCheckClusters.php', ], 'neutral_terms' => [ 'provider capability', diff --git a/apps/platform/config/tenantpilot.php b/apps/platform/config/tenantpilot.php index 3c274449..647eb539 100644 --- a/apps/platform/config/tenantpilot.php +++ b/apps/platform/config/tenantpilot.php @@ -97,14 +97,14 @@ 'scheduled_reconciliation' => true, ], 'promotion.execute' => [ - 'job_class' => \App\Jobs\Operations\CrossTenantPromotionExecutionJob::class, + 'job_class' => \App\Jobs\Operations\CrossEnvironmentPromotionExecutionJob::class, 'queued_stale_after_seconds' => 300, 'running_stale_after_seconds' => 1500, 'expected_max_runtime_seconds' => 420, 'direct_failed_bridge' => false, 'scheduled_reconciliation' => true, ], - 'tenant.review_pack.generate' => [ + 'environment.review_pack.generate' => [ 'job_class' => \App\Jobs\GenerateReviewPackJob::class, 'queued_stale_after_seconds' => 300, 'running_stale_after_seconds' => 900, @@ -112,8 +112,8 @@ 'direct_failed_bridge' => false, 'scheduled_reconciliation' => true, ], - 'tenant.review.compose' => [ - 'job_class' => \App\Jobs\ComposeTenantReviewJob::class, + 'environment.review.compose' => [ + 'job_class' => \App\Jobs\ComposeEnvironmentReviewJob::class, 'queued_stale_after_seconds' => 300, 'running_stale_after_seconds' => 900, 'expected_max_runtime_seconds' => 240, diff --git a/apps/platform/database/factories/TenantReviewFactory.php b/apps/platform/database/factories/EnvironmentReviewFactory.php similarity index 78% rename from apps/platform/database/factories/TenantReviewFactory.php rename to apps/platform/database/factories/EnvironmentReviewFactory.php index 6412f67d..d181389e 100644 --- a/apps/platform/database/factories/TenantReviewFactory.php +++ b/apps/platform/database/factories/EnvironmentReviewFactory.php @@ -6,19 +6,19 @@ use App\Models\ReviewPack; use App\Models\ManagedEnvironment; -use App\Models\TenantReview; +use App\Models\EnvironmentReview; use App\Models\User; use App\Models\Workspace; -use App\Support\TenantReviewCompletenessState; -use App\Support\TenantReviewStatus; +use App\Support\EnvironmentReviewCompletenessState; +use App\Support\EnvironmentReviewStatus; use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends Factory + * @extends Factory */ -class TenantReviewFactory extends Factory +class EnvironmentReviewFactory extends Factory { - protected $model = TenantReview::class; + protected $model = EnvironmentReview::class; /** * @return array @@ -49,8 +49,8 @@ public function definition(): array 'published_by_user_id' => null, 'superseded_by_review_id' => null, 'fingerprint' => fake()->sha256(), - 'status' => TenantReviewStatus::Draft->value, - 'completeness_state' => TenantReviewCompletenessState::Complete->value, + 'status' => EnvironmentReviewStatus::Draft->value, + 'completeness_state' => EnvironmentReviewCompletenessState::Complete->value, 'summary' => [ 'publish_blockers' => [], 'required_section_count' => 6, @@ -65,8 +65,8 @@ public function definition(): array public function ready(): static { return $this->state(fn (): array => [ - 'status' => TenantReviewStatus::Ready->value, - 'completeness_state' => TenantReviewCompletenessState::Complete->value, + 'status' => EnvironmentReviewStatus::Ready->value, + 'completeness_state' => EnvironmentReviewCompletenessState::Complete->value, 'summary' => [ 'publish_blockers' => [], 'required_section_count' => 6, @@ -79,7 +79,7 @@ public function published(?ReviewPack $reviewPack = null): static { return $this->state(fn (): array => [ 'current_export_review_pack_id' => $reviewPack?->getKey(), - 'status' => TenantReviewStatus::Published->value, + 'status' => EnvironmentReviewStatus::Published->value, 'published_at' => now(), ]); } diff --git a/apps/platform/database/factories/TenantReviewSectionFactory.php b/apps/platform/database/factories/EnvironmentReviewSectionFactory.php similarity index 60% rename from apps/platform/database/factories/TenantReviewSectionFactory.php rename to apps/platform/database/factories/EnvironmentReviewSectionFactory.php index 30f65dd8..279ca8b3 100644 --- a/apps/platform/database/factories/TenantReviewSectionFactory.php +++ b/apps/platform/database/factories/EnvironmentReviewSectionFactory.php @@ -4,18 +4,18 @@ namespace Database\Factories; -use App\Models\TenantReview; -use App\Models\TenantReviewSection; -use App\Support\TenantReviewCompletenessState; +use App\Models\EnvironmentReview; +use App\Models\EnvironmentReviewSection; +use App\Support\EnvironmentReviewCompletenessState; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; /** - * @extends Factory + * @extends Factory */ -class TenantReviewSectionFactory extends Factory +class EnvironmentReviewSectionFactory extends Factory { - protected $model = TenantReviewSection::class; + protected $model = EnvironmentReviewSection::class; /** * @return array @@ -23,14 +23,14 @@ class TenantReviewSectionFactory extends Factory public function definition(): array { return [ - 'tenant_review_id' => TenantReview::factory(), + 'environment_review_id' => EnvironmentReview::factory(), 'workspace_id' => function (array $attributes): int { - $review = TenantReview::query()->whereKey((int) $attributes['tenant_review_id'])->firstOrFail(); + $review = EnvironmentReview::query()->whereKey((int) $attributes['environment_review_id'])->firstOrFail(); return (int) $review->workspace_id; }, 'managed_environment_id' => function (array $attributes): int { - $review = TenantReview::query()->whereKey((int) $attributes['tenant_review_id'])->firstOrFail(); + $review = EnvironmentReview::query()->whereKey((int) $attributes['environment_review_id'])->firstOrFail(); return (int) $review->managed_environment_id; }, @@ -38,7 +38,7 @@ public function definition(): array 'title' => fake()->sentence(3), 'sort_order' => fake()->numberBetween(0, 50), 'required' => true, - 'completeness_state' => TenantReviewCompletenessState::Complete->value, + 'completeness_state' => EnvironmentReviewCompletenessState::Complete->value, 'source_snapshot_fingerprint' => fake()->sha256(), 'summary_payload' => [ 'summary' => fake()->sentence(), diff --git a/apps/platform/database/factories/TenantOnboardingSessionFactory.php b/apps/platform/database/factories/ManagedEnvironmentOnboardingSessionFactory.php similarity index 93% rename from apps/platform/database/factories/TenantOnboardingSessionFactory.php rename to apps/platform/database/factories/ManagedEnvironmentOnboardingSessionFactory.php index a574817d..afdd2959 100644 --- a/apps/platform/database/factories/TenantOnboardingSessionFactory.php +++ b/apps/platform/database/factories/ManagedEnvironmentOnboardingSessionFactory.php @@ -5,7 +5,7 @@ namespace Database\Factories; use App\Models\ManagedEnvironment; -use App\Models\TenantOnboardingSession; +use App\Models\ManagedEnvironmentOnboardingSession; use App\Models\User; use App\Models\Workspace; use App\Support\Onboarding\OnboardingCheckpoint; @@ -13,16 +13,16 @@ use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends Factory + * @extends Factory */ -class TenantOnboardingSessionFactory extends Factory +class ManagedEnvironmentOnboardingSessionFactory extends Factory { - protected $model = TenantOnboardingSession::class; + protected $model = ManagedEnvironmentOnboardingSession::class; public function definition(): array { $entraTenantId = fake()->uuid(); - $tenantName = fake()->company(); + $environmentName = fake()->company(); return [ 'workspace_id' => Workspace::factory(), @@ -31,7 +31,7 @@ public function definition(): array 'current_step' => 'identify', 'state' => [ 'entra_tenant_id' => $entraTenantId, - 'tenant_name' => $tenantName, + 'environment_name' => $environmentName, 'environment' => 'prod', ], 'started_by_user_id' => User::factory(), @@ -63,7 +63,7 @@ public function forTenant(ManagedEnvironment $tenant): static 'state' => array_merge(is_array($attributes['state'] ?? null) ? $attributes['state'] : [], [ 'managed_environment_id' => (int) $tenant->getKey(), 'entra_tenant_id' => (string) $tenant->managed_environment_id, - 'tenant_name' => (string) $tenant->name, + 'environment_name' => (string) $tenant->name, 'environment' => (string) ($tenant->environment ?? 'prod'), ]), ]); diff --git a/apps/platform/database/factories/TenantTriageReviewFactory.php b/apps/platform/database/factories/ManagedEnvironmentTriageReviewFactory.php similarity index 89% rename from apps/platform/database/factories/TenantTriageReviewFactory.php rename to apps/platform/database/factories/ManagedEnvironmentTriageReviewFactory.php index 483616e7..443c92a7 100644 --- a/apps/platform/database/factories/TenantTriageReviewFactory.php +++ b/apps/platform/database/factories/ManagedEnvironmentTriageReviewFactory.php @@ -5,18 +5,18 @@ namespace Database\Factories; use App\Models\ManagedEnvironment; -use App\Models\TenantTriageReview; +use App\Models\ManagedEnvironmentTriageReview; use App\Models\User; use App\Models\Workspace; use App\Support\PortfolioTriage\PortfolioArrivalContextToken; use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends Factory + * @extends Factory */ -class TenantTriageReviewFactory extends Factory +class ManagedEnvironmentTriageReviewFactory extends Factory { - protected $model = TenantTriageReview::class; + protected $model = ManagedEnvironmentTriageReview::class; /** * @return array @@ -49,7 +49,7 @@ public function definition(): array return (int) $tenant->workspace_id; }, 'concern_family' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, - 'current_state' => TenantTriageReview::STATE_REVIEWED, + 'current_state' => ManagedEnvironmentTriageReview::STATE_REVIEWED, 'reviewed_at' => now()->subMinutes(5), 'reviewed_by_user_id' => User::factory(), 'review_fingerprint' => $this->hashSnapshot($snapshot), @@ -62,14 +62,14 @@ public function definition(): array public function reviewed(): static { return $this->state(fn (): array => [ - 'current_state' => TenantTriageReview::STATE_REVIEWED, + 'current_state' => ManagedEnvironmentTriageReview::STATE_REVIEWED, ]); } public function followUpNeeded(): static { return $this->state(fn (): array => [ - 'current_state' => TenantTriageReview::STATE_FOLLOW_UP_NEEDED, + 'current_state' => ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED, ]); } diff --git a/apps/platform/database/factories/ProductUsageEventFactory.php b/apps/platform/database/factories/ProductUsageEventFactory.php index fd030d05..964a9abd 100644 --- a/apps/platform/database/factories/ProductUsageEventFactory.php +++ b/apps/platform/database/factories/ProductUsageEventFactory.php @@ -46,7 +46,7 @@ public function definition(): array 'user_id' => User::factory(), 'event_name' => $eventName, 'feature_area' => $catalog->featureArea($eventName), - 'subject_type' => 'tenant_onboarding_session', + 'subject_type' => 'managed_environment_onboarding_session', 'subject_id' => (string) fake()->numberBetween(1, 999999), 'metadata' => [ 'checkpoint_key' => 'tenant_connected', diff --git a/apps/platform/database/migrations/2025_12_11_122423_create_tenant_permissions_table.php b/apps/platform/database/migrations/2025_12_11_122423_create_managed_environment_permissions_table.php similarity index 85% rename from apps/platform/database/migrations/2025_12_11_122423_create_tenant_permissions_table.php rename to apps/platform/database/migrations/2025_12_11_122423_create_managed_environment_permissions_table.php index 5c6dcfb6..d27cfecf 100644 --- a/apps/platform/database/migrations/2025_12_11_122423_create_tenant_permissions_table.php +++ b/apps/platform/database/migrations/2025_12_11_122423_create_managed_environment_permissions_table.php @@ -11,7 +11,7 @@ */ public function up(): void { - Schema::create('tenant_permissions', function (Blueprint $table) { + Schema::create('managed_environment_permissions', function (Blueprint $table) { $table->id(); $table->foreignId('managed_environment_id')->constrained()->cascadeOnDelete(); $table->string('permission_key'); @@ -30,6 +30,6 @@ public function up(): void */ public function down(): void { - Schema::dropIfExists('tenant_permissions'); + Schema::dropIfExists('managed_environment_permissions'); } }; diff --git a/apps/platform/database/migrations/2025_12_11_192942_add_is_current_to_tenants.php b/apps/platform/database/migrations/2025_12_11_192942_add_is_current_to_tenants.php index a4d24a84..cb830944 100644 --- a/apps/platform/database/migrations/2025_12_11_192942_add_is_current_to_tenants.php +++ b/apps/platform/database/migrations/2025_12_11_192942_add_is_current_to_tenants.php @@ -38,7 +38,7 @@ public function up(): void ->update(['is_current' => true]); } - DB::statement('CREATE UNIQUE INDEX tenants_current_unique ON managed_environments (is_current) WHERE is_current = true AND deleted_at IS NULL'); + DB::statement('CREATE UNIQUE INDEX managed_environments_current_unique ON managed_environments (is_current) WHERE is_current = true AND deleted_at IS NULL'); } /** @@ -46,7 +46,7 @@ public function up(): void */ public function down(): void { - DB::statement('DROP INDEX IF EXISTS tenants_current_unique'); + DB::statement('DROP INDEX IF EXISTS managed_environments_current_unique'); Schema::table('managed_environments', function (Blueprint $table) { $table->dropColumn('is_current'); diff --git a/apps/platform/database/migrations/2025_12_12_150000_add_rbac_fields_to_tenants.php b/apps/platform/database/migrations/2025_12_12_150000_add_rbac_fields_to_tenants.php index 9648d218..f54bc927 100644 --- a/apps/platform/database/migrations/2025_12_12_150000_add_rbac_fields_to_tenants.php +++ b/apps/platform/database/migrations/2025_12_12_150000_add_rbac_fields_to_tenants.php @@ -15,14 +15,14 @@ public function up(): void $table->string('rbac_scope_mode')->nullable()->after('rbac_role_key'); $table->string('rbac_scope_id')->nullable()->after('rbac_scope_mode'); - $table->index(['rbac_group_id', 'rbac_role_assignment_id'], 'tenants_rbac_artifacts_idx'); + $table->index(['rbac_group_id', 'rbac_role_assignment_id'], 'managed_environments_rbac_artifacts_idx'); }); } public function down(): void { Schema::table('managed_environments', function (Blueprint $table) { - $table->dropIndex('tenants_rbac_artifacts_idx'); + $table->dropIndex('managed_environments_rbac_artifacts_idx'); $table->dropColumn([ 'rbac_group_id', 'rbac_role_assignment_id', diff --git a/apps/platform/database/migrations/2026_01_31_230304_add_workspace_id_to_tenants_table.php b/apps/platform/database/migrations/2026_01_31_230304_add_workspace_id_to_tenants_table.php index 01248412..3bea6ff6 100644 --- a/apps/platform/database/migrations/2026_01_31_230304_add_workspace_id_to_tenants_table.php +++ b/apps/platform/database/migrations/2026_01_31_230304_add_workspace_id_to_tenants_table.php @@ -25,8 +25,8 @@ public function up(): void if ($driver === 'sqlite') { // SQLite table rebuilds can drop/flatten the partial index defined in // 2025_12_11_192942_add_is_current_to_tenants.php. Recreate it here. - DB::statement('DROP INDEX IF EXISTS tenants_current_unique'); - DB::statement('CREATE UNIQUE INDEX tenants_current_unique ON managed_environments (is_current) WHERE is_current = 1 AND deleted_at IS NULL'); + DB::statement('DROP INDEX IF EXISTS managed_environments_current_unique'); + DB::statement('CREATE UNIQUE INDEX managed_environments_current_unique ON managed_environments (is_current) WHERE is_current = 1 AND deleted_at IS NULL'); } } diff --git a/apps/platform/database/migrations/2026_02_03_090449_create_tenant_onboarding_sessions_table.php b/apps/platform/database/migrations/2026_02_03_090449_create_managed_environment_onboarding_sessions_table.php similarity index 82% rename from apps/platform/database/migrations/2026_02_03_090449_create_tenant_onboarding_sessions_table.php rename to apps/platform/database/migrations/2026_02_03_090449_create_managed_environment_onboarding_sessions_table.php index 7e9477df..5bfed2ae 100644 --- a/apps/platform/database/migrations/2026_02_03_090449_create_tenant_onboarding_sessions_table.php +++ b/apps/platform/database/migrations/2026_02_03_090449_create_managed_environment_onboarding_sessions_table.php @@ -11,11 +11,11 @@ */ public function up(): void { - if (Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (Schema::hasTable('managed_environment_onboarding_sessions')) { return; } - Schema::create('managed_tenant_onboarding_sessions', function (Blueprint $table) { + Schema::create('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->id(); $table->foreignId('workspace_id')->constrained()->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained()->cascadeOnDelete(); @@ -38,6 +38,6 @@ public function up(): void */ public function down(): void { - Schema::dropIfExists('managed_tenant_onboarding_sessions'); + Schema::dropIfExists('managed_environment_onboarding_sessions'); } }; diff --git a/apps/platform/database/migrations/2026_02_03_150001_create_managed_tenant_onboarding_sessions_table.php b/apps/platform/database/migrations/2026_02_03_150001_create_managed_environment_onboarding_sessions_table.php similarity index 81% rename from apps/platform/database/migrations/2026_02_03_150001_create_managed_tenant_onboarding_sessions_table.php rename to apps/platform/database/migrations/2026_02_03_150001_create_managed_environment_onboarding_sessions_table.php index d367be73..54d9b38f 100644 --- a/apps/platform/database/migrations/2026_02_03_150001_create_managed_tenant_onboarding_sessions_table.php +++ b/apps/platform/database/migrations/2026_02_03_150001_create_managed_environment_onboarding_sessions_table.php @@ -10,11 +10,11 @@ { public function up(): void { - if (Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (Schema::hasTable('managed_environment_onboarding_sessions')) { return; } - Schema::create('managed_tenant_onboarding_sessions', function (Blueprint $table) { + Schema::create('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->id(); $table->foreignId('workspace_id')->constrained()->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained()->cascadeOnDelete(); @@ -35,6 +35,6 @@ public function up(): void public function down(): void { - Schema::dropIfExists('managed_tenant_onboarding_sessions'); + Schema::dropIfExists('managed_environment_onboarding_sessions'); } }; diff --git a/apps/platform/database/migrations/2026_02_04_090010_update_tenant_onboarding_sessions_constraints.php b/apps/platform/database/migrations/2026_02_04_090010_update_managed_environment_onboarding_sessions_constraints.php similarity index 65% rename from apps/platform/database/migrations/2026_02_04_090010_update_tenant_onboarding_sessions_constraints.php rename to apps/platform/database/migrations/2026_02_04_090010_update_managed_environment_onboarding_sessions_constraints.php index 88e90fba..929a5ff1 100644 --- a/apps/platform/database/migrations/2026_02_04_090010_update_tenant_onboarding_sessions_constraints.php +++ b/apps/platform/database/migrations/2026_02_04_090010_update_managed_environment_onboarding_sessions_constraints.php @@ -9,7 +9,7 @@ { public function up(): void { - if (! Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (! Schema::hasTable('managed_environment_onboarding_sessions')) { return; } @@ -18,18 +18,18 @@ public function up(): void if ($driver === 'sqlite') { Schema::disableForeignKeyConstraints(); - Schema::rename('managed_tenant_onboarding_sessions', 'managed_tenant_onboarding_sessions_old'); + Schema::rename('managed_environment_onboarding_sessions', 'managed_environment_onboarding_sessions_old'); foreach ([ - 'managed_tenant_onboarding_sessions_workspace_id_tenant_id_unique', - 'managed_tenant_onboarding_sessions_tenant_id_index', - 'managed_tenant_onboarding_sessions_workspace_id_managed_environment_id_unique', - 'managed_tenant_onboarding_sessions_managed_environment_id_index', + 'managed_environment_onboarding_sessions_workspace_id_environment_id_unique', + 'managed_environment_onboarding_sessions_environment_id_index', + 'managed_environment_onboarding_sessions_workspace_id_managed_environment_id_unique', + 'managed_environment_onboarding_sessions_managed_environment_id_index', ] as $indexName) { DB::statement("DROP INDEX IF EXISTS {$indexName}"); } - Schema::create('managed_tenant_onboarding_sessions', function (Blueprint $table) { + Schema::create('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->id(); $table->foreignId('workspace_id')->constrained()->cascadeOnDelete(); $table->foreignId('managed_environment_id')->nullable()->constrained()->cascadeOnDelete(); @@ -45,7 +45,7 @@ public function up(): void $table->index('entra_tenant_id'); }); - DB::table('managed_tenant_onboarding_sessions_old') + DB::table('managed_environment_onboarding_sessions_old') ->orderBy('id') ->chunkById(500, function ($rows): void { foreach ($rows as $row) { @@ -70,7 +70,7 @@ public function up(): void $entraTenantId = sprintf('unknown-%d', (int) $row->id); } - DB::table('managed_tenant_onboarding_sessions')->insert([ + DB::table('managed_environment_onboarding_sessions')->insert([ 'id' => $row->id, 'workspace_id' => $row->workspace_id, 'managed_environment_id' => $row->managed_environment_id, @@ -86,18 +86,18 @@ public function up(): void } }, 'id'); - Schema::drop('managed_tenant_onboarding_sessions_old'); + Schema::drop('managed_environment_onboarding_sessions_old'); - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_workspace_entra_unique ON managed_tenant_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_tenant_unique ON managed_tenant_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_workspace_entra_unique ON managed_environment_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_environment_unique ON managed_environment_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); Schema::enableForeignKeyConstraints(); return; } - if (! Schema::hasColumn('managed_tenant_onboarding_sessions', 'entra_tenant_id')) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table) { + if (! Schema::hasColumn('managed_environment_onboarding_sessions', 'entra_tenant_id')) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->string('entra_tenant_id')->nullable()->after('managed_environment_id'); }); } @@ -105,22 +105,22 @@ public function up(): void $this->backfillEntraTenantId($driver); if ($driver === 'pgsql') { - DB::statement('ALTER TABLE managed_tenant_onboarding_sessions ALTER COLUMN managed_environment_id DROP NOT NULL'); - DB::statement('ALTER TABLE managed_tenant_onboarding_sessions ALTER COLUMN entra_tenant_id SET NOT NULL'); + DB::statement('ALTER TABLE managed_environment_onboarding_sessions ALTER COLUMN managed_environment_id DROP NOT NULL'); + DB::statement('ALTER TABLE managed_environment_onboarding_sessions ALTER COLUMN entra_tenant_id SET NOT NULL'); } - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->dropUnique(['workspace_id', 'managed_environment_id']); $table->index('entra_tenant_id'); }); - DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS managed_tenant_onboarding_sessions_active_workspace_entra_unique ON managed_tenant_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); - DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS managed_tenant_onboarding_sessions_active_tenant_unique ON managed_tenant_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); + DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS managed_environment_onboarding_sessions_active_workspace_entra_unique ON managed_environment_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); + DB::statement('CREATE UNIQUE INDEX IF NOT EXISTS managed_environment_onboarding_sessions_active_environment_unique ON managed_environment_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); } public function down(): void { - if (! Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (! Schema::hasTable('managed_environment_onboarding_sessions')) { return; } @@ -129,19 +129,19 @@ public function down(): void if ($driver === 'sqlite') { Schema::disableForeignKeyConstraints(); - Schema::rename('managed_tenant_onboarding_sessions', 'managed_tenant_onboarding_sessions_new'); + Schema::rename('managed_environment_onboarding_sessions', 'managed_environment_onboarding_sessions_new'); foreach ([ - 'managed_tenant_onboarding_sessions_active_workspace_entra_unique', - 'managed_tenant_onboarding_sessions_active_tenant_unique', - 'managed_tenant_onboarding_sessions_tenant_id_index', - 'managed_tenant_onboarding_sessions_managed_environment_id_index', - 'managed_tenant_onboarding_sessions_entra_tenant_id_index', + 'managed_environment_onboarding_sessions_active_workspace_entra_unique', + 'managed_environment_onboarding_sessions_active_environment_unique', + 'managed_environment_onboarding_sessions_environment_id_index', + 'managed_environment_onboarding_sessions_managed_environment_id_index', + 'managed_environment_onboarding_sessions_entra_tenant_id_index', ] as $indexName) { DB::statement("DROP INDEX IF EXISTS {$indexName}"); } - Schema::create('managed_tenant_onboarding_sessions', function (Blueprint $table) { + Schema::create('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->id(); $table->foreignId('workspace_id')->constrained()->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained()->cascadeOnDelete(); @@ -156,12 +156,12 @@ public function down(): void $table->index(['managed_environment_id']); }); - DB::table('managed_tenant_onboarding_sessions_new') + DB::table('managed_environment_onboarding_sessions_new') ->whereNotNull('managed_environment_id') ->orderBy('id') ->chunkById(500, function ($rows): void { foreach ($rows as $row) { - DB::table('managed_tenant_onboarding_sessions')->insert([ + DB::table('managed_environment_onboarding_sessions')->insert([ 'id' => $row->id, 'workspace_id' => $row->workspace_id, 'managed_environment_id' => $row->managed_environment_id, @@ -176,21 +176,21 @@ public function down(): void } }, 'id'); - Schema::drop('managed_tenant_onboarding_sessions_new'); + Schema::drop('managed_environment_onboarding_sessions_new'); Schema::enableForeignKeyConstraints(); return; } foreach ([ - 'managed_tenant_onboarding_sessions_active_workspace_entra_unique', - 'managed_tenant_onboarding_sessions_active_tenant_unique', + 'managed_environment_onboarding_sessions_active_workspace_entra_unique', + 'managed_environment_onboarding_sessions_active_environment_unique', ] as $indexName) { DB::statement("DROP INDEX IF EXISTS {$indexName}"); } - if (Schema::hasColumn('managed_tenant_onboarding_sessions', 'entra_tenant_id')) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table) { + if (Schema::hasColumn('managed_environment_onboarding_sessions', 'entra_tenant_id')) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table) { $table->dropIndex(['entra_tenant_id']); $table->dropColumn('entra_tenant_id'); $table->unique(['workspace_id', 'managed_environment_id']); @@ -202,15 +202,15 @@ private function backfillEntraTenantId(string $driver): void { if ($driver === 'pgsql') { DB::statement(<<<'SQL' - UPDATE managed_tenant_onboarding_sessions - SET entra_tenant_id = COALESCE(managed_tenant_onboarding_sessions.entra_tenant_id, managed_tenant_onboarding_sessions.state->>'entra_tenant_id', managed_tenant_onboarding_sessions.state->>'managed_environment_id', managed_environments.slug) + UPDATE managed_environment_onboarding_sessions + SET entra_tenant_id = COALESCE(managed_environment_onboarding_sessions.entra_tenant_id, managed_environment_onboarding_sessions.state->>'entra_tenant_id', managed_environment_onboarding_sessions.state->>'managed_environment_id', managed_environments.slug) FROM managed_environments - WHERE managed_tenant_onboarding_sessions.entra_tenant_id IS NULL - AND managed_tenant_onboarding_sessions.managed_environment_id = managed_environments.id + WHERE managed_environment_onboarding_sessions.entra_tenant_id IS NULL + AND managed_environment_onboarding_sessions.managed_environment_id = managed_environments.id SQL); DB::statement(<<<'SQL' - UPDATE managed_tenant_onboarding_sessions + UPDATE managed_environment_onboarding_sessions SET entra_tenant_id = state->>'managed_environment_id' WHERE entra_tenant_id IS NULL SQL); @@ -218,7 +218,7 @@ private function backfillEntraTenantId(string $driver): void return; } - DB::table('managed_tenant_onboarding_sessions') + DB::table('managed_environment_onboarding_sessions') ->whereNull('entra_tenant_id') ->orderBy('id') ->chunkById(500, function ($rows): void { @@ -240,7 +240,7 @@ private function backfillEntraTenantId(string $driver): void $entraTenantId = sprintf('unknown-%d', (int) $row->id); } - DB::table('managed_tenant_onboarding_sessions') + DB::table('managed_environment_onboarding_sessions') ->where('id', $row->id) ->update(['entra_tenant_id' => $entraTenantId]); } diff --git a/apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_tenant_permissions_table.php b/apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_managed_environment_permissions_table.php similarity index 59% rename from apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_tenant_permissions_table.php rename to apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_managed_environment_permissions_table.php index 09ade547..f447be93 100644 --- a/apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_tenant_permissions_table.php +++ b/apps/platform/database/migrations/2026_02_14_220112_add_workspace_id_to_managed_environment_permissions_table.php @@ -8,11 +8,11 @@ { public function up(): void { - if (! Schema::hasTable('tenant_permissions') || Schema::hasColumn('tenant_permissions', 'workspace_id')) { + if (! Schema::hasTable('managed_environment_permissions') || Schema::hasColumn('managed_environment_permissions', 'workspace_id')) { return; } - Schema::table('tenant_permissions', function (Blueprint $table): void { + Schema::table('managed_environment_permissions', function (Blueprint $table): void { $table->unsignedBigInteger('workspace_id')->nullable(); $table->index('workspace_id'); $table->index(['workspace_id', 'managed_environment_id']); @@ -21,11 +21,11 @@ public function up(): void public function down(): void { - if (! Schema::hasTable('tenant_permissions') || ! Schema::hasColumn('tenant_permissions', 'workspace_id')) { + if (! Schema::hasTable('managed_environment_permissions') || ! Schema::hasColumn('managed_environment_permissions', 'workspace_id')) { return; } - Schema::table('tenant_permissions', function (Blueprint $table): void { + Schema::table('managed_environment_permissions', function (Blueprint $table): void { $table->dropIndex(['workspace_id', 'managed_environment_id']); $table->dropIndex(['workspace_id']); $table->dropColumn('workspace_id'); diff --git a/apps/platform/database/migrations/2026_02_14_220113_add_tenants_id_workspace_id_unique.php b/apps/platform/database/migrations/2026_02_14_220113_add_tenants_id_workspace_id_unique.php index 8e59fa4c..6e0d8ff3 100644 --- a/apps/platform/database/migrations/2026_02_14_220113_add_tenants_id_workspace_id_unique.php +++ b/apps/platform/database/migrations/2026_02_14_220113_add_tenants_id_workspace_id_unique.php @@ -13,7 +13,7 @@ public function up(): void } Schema::table('managed_environments', function (Blueprint $table): void { - $table->unique(['id', 'workspace_id'], 'tenants_id_workspace_id_unique'); + $table->unique(['id', 'workspace_id'], 'managed_environments_id_workspace_id_unique'); }); } @@ -24,7 +24,7 @@ public function down(): void } Schema::table('managed_environments', function (Blueprint $table): void { - $table->dropUnique('tenants_id_workspace_id_unique'); + $table->dropUnique('managed_environments_id_workspace_id_unique'); }); } }; diff --git a/apps/platform/database/migrations/2026_02_14_220114_enforce_workspace_id_not_null_on_tenant_owned_tables.php b/apps/platform/database/migrations/2026_02_14_220114_enforce_workspace_id_not_null_on_tenant_owned_tables.php index ca3d35f8..12449cc9 100644 --- a/apps/platform/database/migrations/2026_02_14_220114_enforce_workspace_id_not_null_on_tenant_owned_tables.php +++ b/apps/platform/database/migrations/2026_02_14_220114_enforce_workspace_id_not_null_on_tenant_owned_tables.php @@ -23,7 +23,7 @@ private function tenantOwnedTables(): array 'entra_groups', 'findings', 'entra_role_definitions', - 'tenant_permissions', + 'managed_environment_permissions', ]; } diff --git a/apps/platform/database/migrations/2026_02_14_220115_add_workspace_isolation_constraints_to_tenant_owned_tables.php b/apps/platform/database/migrations/2026_02_14_220115_add_workspace_isolation_constraints_to_tenant_owned_tables.php index 448a194d..2454d82e 100644 --- a/apps/platform/database/migrations/2026_02_14_220115_add_workspace_isolation_constraints_to_tenant_owned_tables.php +++ b/apps/platform/database/migrations/2026_02_14_220115_add_workspace_isolation_constraints_to_tenant_owned_tables.php @@ -24,7 +24,7 @@ private function tenantOwnedTables(): array 'entra_groups', 'findings', 'entra_role_definitions', - 'tenant_permissions', + 'managed_environment_permissions', ]; } @@ -42,7 +42,7 @@ public function up(): void } $workspaceConstraint = sprintf('%s_workspace_fk', $tableName); - $tenantWorkspaceConstraint = sprintf('%s_tenant_workspace_fk', $tableName); + $tenantWorkspaceConstraint = sprintf('%s_environment_workspace_fk', $tableName); Schema::table($tableName, function (Blueprint $table) use ($workspaceConstraint, $tenantWorkspaceConstraint): void { $table->foreign('workspace_id', $workspaceConstraint) @@ -72,7 +72,7 @@ public function down(): void } $workspaceConstraint = sprintf('%s_workspace_fk', $tableName); - $tenantWorkspaceConstraint = sprintf('%s_tenant_workspace_fk', $tableName); + $tenantWorkspaceConstraint = sprintf('%s_environment_workspace_fk', $tableName); Schema::table($tableName, function (Blueprint $table) use ($workspaceConstraint, $tenantWorkspaceConstraint): void { $table->dropForeign($tenantWorkspaceConstraint); diff --git a/apps/platform/database/migrations/2026_02_15_005041_ensure_workspace_id_fks_on_tenant_owned_tables.php b/apps/platform/database/migrations/2026_02_15_005041_ensure_workspace_id_fks_on_tenant_owned_tables.php index 5b491b3e..549ba9eb 100644 --- a/apps/platform/database/migrations/2026_02_15_005041_ensure_workspace_id_fks_on_tenant_owned_tables.php +++ b/apps/platform/database/migrations/2026_02_15_005041_ensure_workspace_id_fks_on_tenant_owned_tables.php @@ -22,7 +22,7 @@ private function tenantOwnedTables(): array 'entra_groups', 'findings', 'entra_role_definitions', - 'tenant_permissions', + 'managed_environment_permissions', ]; } diff --git a/apps/platform/database/migrations/2026_02_15_120001_create_tenant_settings_table.php b/apps/platform/database/migrations/2026_02_15_120001_create_tenant_settings_table.php index 39ae9417..bba8e5de 100644 --- a/apps/platform/database/migrations/2026_02_15_120001_create_tenant_settings_table.php +++ b/apps/platform/database/migrations/2026_02_15_120001_create_tenant_settings_table.php @@ -21,7 +21,7 @@ public function up(): void $table->unique(['managed_environment_id', 'domain', 'key']); $table->index(['workspace_id', 'managed_environment_id']); - $table->foreign(['managed_environment_id', 'workspace_id'], 'tenant_settings_tenant_workspace_fk') + $table->foreign(['managed_environment_id', 'workspace_id'], 'tenant_settings_managed_environment_workspace_fk') ->references(['id', 'workspace_id']) ->on('managed_environments') ->cascadeOnDelete(); diff --git a/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_environment_onboarding_sessions.php b/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_environment_onboarding_sessions.php new file mode 100644 index 00000000..7327b66d --- /dev/null +++ b/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_environment_onboarding_sessions.php @@ -0,0 +1,49 @@ +timestamp('cancelled_at')->nullable()->after('completed_at'); + }); + } + + DB::statement('DROP INDEX IF EXISTS managed_environment_onboarding_sessions_active_workspace_entra_unique'); + DB::statement('DROP INDEX IF EXISTS managed_environment_onboarding_sessions_active_environment_unique'); + + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_workspace_entra_unique ON managed_environment_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL AND cancelled_at IS NULL'); + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_environment_unique ON managed_environment_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND cancelled_at IS NULL AND managed_environment_id IS NOT NULL'); + } + + public function down(): void + { + if (! Schema::hasTable('managed_environment_onboarding_sessions')) { + return; + } + + DB::statement('DROP INDEX IF EXISTS managed_environment_onboarding_sessions_active_workspace_entra_unique'); + DB::statement('DROP INDEX IF EXISTS managed_environment_onboarding_sessions_active_environment_unique'); + + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_workspace_entra_unique ON managed_environment_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); + DB::statement('CREATE UNIQUE INDEX managed_environment_onboarding_sessions_active_environment_unique ON managed_environment_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); + + if (Schema::hasColumn('managed_environment_onboarding_sessions', 'cancelled_at')) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table): void { + $table->dropColumn('cancelled_at'); + }); + } + } +}; diff --git a/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_tenant_onboarding_sessions.php b/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_tenant_onboarding_sessions.php deleted file mode 100644 index 7484c548..00000000 --- a/apps/platform/database/migrations/2026_03_13_120000_add_cancelled_at_to_managed_tenant_onboarding_sessions.php +++ /dev/null @@ -1,49 +0,0 @@ -timestamp('cancelled_at')->nullable()->after('completed_at'); - }); - } - - DB::statement('DROP INDEX IF EXISTS managed_tenant_onboarding_sessions_active_workspace_entra_unique'); - DB::statement('DROP INDEX IF EXISTS managed_tenant_onboarding_sessions_active_tenant_unique'); - - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_workspace_entra_unique ON managed_tenant_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL AND cancelled_at IS NULL'); - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_tenant_unique ON managed_tenant_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND cancelled_at IS NULL AND managed_environment_id IS NOT NULL'); - } - - public function down(): void - { - if (! Schema::hasTable('managed_tenant_onboarding_sessions')) { - return; - } - - DB::statement('DROP INDEX IF EXISTS managed_tenant_onboarding_sessions_active_workspace_entra_unique'); - DB::statement('DROP INDEX IF EXISTS managed_tenant_onboarding_sessions_active_tenant_unique'); - - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_workspace_entra_unique ON managed_tenant_onboarding_sessions (workspace_id, entra_tenant_id) WHERE completed_at IS NULL'); - DB::statement('CREATE UNIQUE INDEX managed_tenant_onboarding_sessions_active_tenant_unique ON managed_tenant_onboarding_sessions (managed_environment_id) WHERE completed_at IS NULL AND managed_environment_id IS NOT NULL'); - - if (Schema::hasColumn('managed_tenant_onboarding_sessions', 'cancelled_at')) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table): void { - $table->dropColumn('cancelled_at'); - }); - } - } -}; diff --git a/apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_tenant_onboarding_sessions.php b/apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_environment_onboarding_sessions.php similarity index 78% rename from apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_tenant_onboarding_sessions.php rename to apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_environment_onboarding_sessions.php index 67e9201b..4e164799 100644 --- a/apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_tenant_onboarding_sessions.php +++ b/apps/platform/database/migrations/2026_03_14_000001_add_lifecycle_and_version_to_managed_environment_onboarding_sessions.php @@ -13,19 +13,19 @@ { public function up(): void { - if (! Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (! Schema::hasTable('managed_environment_onboarding_sessions')) { return; } - $needsVersion = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'version'); - $needsLifecycleState = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'lifecycle_state'); - $needsCurrentCheckpoint = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'current_checkpoint'); - $needsLastCompletedCheckpoint = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'last_completed_checkpoint'); - $needsReasonCode = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'reason_code'); - $needsBlockingReasonCode = ! Schema::hasColumn('managed_tenant_onboarding_sessions', 'blocking_reason_code'); + $needsVersion = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'version'); + $needsLifecycleState = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'lifecycle_state'); + $needsCurrentCheckpoint = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'current_checkpoint'); + $needsLastCompletedCheckpoint = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'last_completed_checkpoint'); + $needsReasonCode = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'reason_code'); + $needsBlockingReasonCode = ! Schema::hasColumn('managed_environment_onboarding_sessions', 'blocking_reason_code'); if ($needsVersion || $needsLifecycleState || $needsCurrentCheckpoint || $needsLastCompletedCheckpoint || $needsReasonCode || $needsBlockingReasonCode) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table) use ($needsVersion, $needsLifecycleState, $needsCurrentCheckpoint, $needsLastCompletedCheckpoint, $needsReasonCode, $needsBlockingReasonCode): void { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table) use ($needsVersion, $needsLifecycleState, $needsCurrentCheckpoint, $needsLastCompletedCheckpoint, $needsReasonCode, $needsBlockingReasonCode): void { if ($needsVersion) { $table->unsignedBigInteger('version')->default(1); } @@ -52,7 +52,7 @@ public function up(): void }); } - DB::table('managed_tenant_onboarding_sessions') + DB::table('managed_environment_onboarding_sessions') ->orderBy('id') ->chunkById(500, function ($rows): void { foreach ($rows as $row) { @@ -63,7 +63,7 @@ public function up(): void $lastCompletedCheckpoint = $this->lastCompletedCheckpoint($currentCheckpoint, $state, $row->completed_at); $lifecycleState = $this->lifecycleState($row->completed_at, $row->cancelled_at, $currentCheckpoint, $state); - DB::table('managed_tenant_onboarding_sessions') + DB::table('managed_environment_onboarding_sessions') ->where('id', $row->id) ->update([ 'version' => max(1, (int) ($row->version ?? 1)), @@ -76,28 +76,28 @@ public function up(): void } }, 'id'); - if (! $this->hasIndex('managed_tenant_onboarding_sessions_lifecycle_state_index')) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table): void { - $table->index('lifecycle_state', 'managed_tenant_onboarding_sessions_lifecycle_state_index'); + if (! $this->hasIndex('managed_environment_onboarding_sessions_lifecycle_state_index')) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table): void { + $table->index('lifecycle_state', 'managed_environment_onboarding_sessions_lifecycle_state_index'); }); } } public function down(): void { - if (! Schema::hasTable('managed_tenant_onboarding_sessions')) { + if (! Schema::hasTable('managed_environment_onboarding_sessions')) { return; } - if ($this->hasIndex('managed_tenant_onboarding_sessions_lifecycle_state_index')) { - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table): void { - $table->dropIndex('managed_tenant_onboarding_sessions_lifecycle_state_index'); + if ($this->hasIndex('managed_environment_onboarding_sessions_lifecycle_state_index')) { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table): void { + $table->dropIndex('managed_environment_onboarding_sessions_lifecycle_state_index'); }); } - Schema::table('managed_tenant_onboarding_sessions', function (Blueprint $table): void { + Schema::table('managed_environment_onboarding_sessions', function (Blueprint $table): void { foreach (['version', 'lifecycle_state', 'current_checkpoint', 'last_completed_checkpoint', 'reason_code', 'blocking_reason_code'] as $column) { - if (Schema::hasColumn('managed_tenant_onboarding_sessions', $column)) { + if (Schema::hasColumn('managed_environment_onboarding_sessions', $column)) { $table->dropColumn($column); } } @@ -220,7 +220,7 @@ private function hasIndex(string $indexName): bool ->where('schemaname', 'public') ->where('indexname', $indexName) ->exists(), - 'sqlite' => collect(DB::select("PRAGMA index_list('managed_tenant_onboarding_sessions')")) + 'sqlite' => collect(DB::select("PRAGMA index_list('managed_environment_onboarding_sessions')")) ->contains(fn (object $index): bool => ($index->name ?? null) === $indexName), default => false, }; diff --git a/apps/platform/database/migrations/2026_03_19_000001_create_finding_exceptions_table.php b/apps/platform/database/migrations/2026_03_19_000001_create_finding_exceptions_table.php index 9445f011..4d02e930 100644 --- a/apps/platform/database/migrations/2026_03_19_000001_create_finding_exceptions_table.php +++ b/apps/platform/database/migrations/2026_03_19_000001_create_finding_exceptions_table.php @@ -44,7 +44,7 @@ public function up(): void $table->index(['managed_environment_id', 'requested_at'], 'finding_exceptions_requested_at_idx'); $table - ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exceptions_tenant_workspace_fk') + ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exceptions_managed_environment_workspace_fk') ->references(['id', 'workspace_id']) ->on('managed_environments') ->cascadeOnDelete(); diff --git a/apps/platform/database/migrations/2026_03_19_000002_create_finding_exception_decisions_table.php b/apps/platform/database/migrations/2026_03_19_000002_create_finding_exception_decisions_table.php index ebfc4792..6188cd4b 100644 --- a/apps/platform/database/migrations/2026_03_19_000002_create_finding_exception_decisions_table.php +++ b/apps/platform/database/migrations/2026_03_19_000002_create_finding_exception_decisions_table.php @@ -30,7 +30,7 @@ public function up(): void $table->index(['managed_environment_id', 'actor_user_id'], 'finding_exception_decisions_actor_idx'); $table - ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exception_decisions_tenant_workspace_fk') + ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exception_decisions_managed_environment_workspace_fk') ->references(['id', 'workspace_id']) ->on('managed_environments') ->cascadeOnDelete(); diff --git a/apps/platform/database/migrations/2026_03_19_000003_create_finding_exception_evidence_references_table.php b/apps/platform/database/migrations/2026_03_19_000003_create_finding_exception_evidence_references_table.php index 86863bb5..459f8c40 100644 --- a/apps/platform/database/migrations/2026_03_19_000003_create_finding_exception_evidence_references_table.php +++ b/apps/platform/database/migrations/2026_03_19_000003_create_finding_exception_evidence_references_table.php @@ -29,7 +29,7 @@ public function up(): void $table->index(['managed_environment_id', 'source_type'], 'finding_exception_evidence_refs_source_idx'); $table - ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exception_evidence_refs_tenant_workspace_fk') + ->foreign(['managed_environment_id', 'workspace_id'], 'finding_exception_evidence_refs_environment_workspace_fk') ->references(['id', 'workspace_id']) ->on('managed_environments') ->cascadeOnDelete(); diff --git a/apps/platform/database/migrations/2026_03_20_000000_create_tenant_reviews_table.php b/apps/platform/database/migrations/2026_03_20_000000_create_environment_reviews_table.php similarity index 84% rename from apps/platform/database/migrations/2026_03_20_000000_create_tenant_reviews_table.php rename to apps/platform/database/migrations/2026_03_20_000000_create_environment_reviews_table.php index 2b18da47..9d93c165 100644 --- a/apps/platform/database/migrations/2026_03_20_000000_create_tenant_reviews_table.php +++ b/apps/platform/database/migrations/2026_03_20_000000_create_environment_reviews_table.php @@ -11,7 +11,7 @@ { public function up(): void { - Schema::create('tenant_reviews', function (Blueprint $table): void { + Schema::create('environment_reviews', function (Blueprint $table): void { $table->id(); $table->foreignId('workspace_id')->constrained('workspaces')->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained('managed_environments')->cascadeOnDelete(); @@ -20,7 +20,7 @@ public function up(): void $table->foreignId('operation_run_id')->nullable()->constrained('operation_runs')->nullOnDelete(); $table->foreignId('initiated_by_user_id')->nullable()->constrained('users')->nullOnDelete(); $table->foreignId('published_by_user_id')->nullable()->constrained('users')->nullOnDelete(); - $table->foreignId('superseded_by_review_id')->nullable()->constrained('tenant_reviews')->nullOnDelete(); + $table->foreignId('superseded_by_review_id')->nullable()->constrained('environment_reviews')->nullOnDelete(); $table->string('fingerprint', 64)->nullable(); $table->string('status')->default('draft'); $table->string('completeness_state')->default('missing'); @@ -35,14 +35,14 @@ public function up(): void }); DB::statement(" - CREATE UNIQUE INDEX tenant_reviews_fingerprint_mutable_unique - ON tenant_reviews (workspace_id, managed_environment_id, fingerprint) + CREATE UNIQUE INDEX environment_reviews_fingerprint_mutable_unique + ON environment_reviews (workspace_id, managed_environment_id, fingerprint) WHERE fingerprint IS NOT NULL AND status IN ('draft', 'ready', 'failed') "); } public function down(): void { - Schema::dropIfExists('tenant_reviews'); + Schema::dropIfExists('environment_reviews'); } }; diff --git a/apps/platform/database/migrations/2026_03_20_000100_create_tenant_review_sections_table.php b/apps/platform/database/migrations/2026_03_20_000100_create_environment_review_sections_table.php similarity index 79% rename from apps/platform/database/migrations/2026_03_20_000100_create_tenant_review_sections_table.php rename to apps/platform/database/migrations/2026_03_20_000100_create_environment_review_sections_table.php index f0830d04..eedf2f8e 100644 --- a/apps/platform/database/migrations/2026_03_20_000100_create_tenant_review_sections_table.php +++ b/apps/platform/database/migrations/2026_03_20_000100_create_environment_review_sections_table.php @@ -10,9 +10,9 @@ { public function up(): void { - Schema::create('tenant_review_sections', function (Blueprint $table): void { + Schema::create('environment_review_sections', function (Blueprint $table): void { $table->id(); - $table->foreignId('tenant_review_id')->constrained('tenant_reviews')->cascadeOnDelete(); + $table->foreignId('environment_review_id')->constrained('environment_reviews')->cascadeOnDelete(); $table->foreignId('workspace_id')->constrained('workspaces')->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained('managed_environments')->cascadeOnDelete(); $table->string('section_key'); @@ -26,7 +26,7 @@ public function up(): void $table->timestampTz('measured_at')->nullable(); $table->timestamps(); - $table->unique(['tenant_review_id', 'section_key']); + $table->unique(['environment_review_id', 'section_key']); $table->index(['workspace_id', 'managed_environment_id', 'section_key']); $table->index(['managed_environment_id', 'completeness_state']); }); @@ -34,6 +34,6 @@ public function up(): void public function down(): void { - Schema::dropIfExists('tenant_review_sections'); + Schema::dropIfExists('environment_review_sections'); } }; diff --git a/apps/platform/database/migrations/2026_03_20_000200_add_tenant_review_id_to_review_packs_table.php b/apps/platform/database/migrations/2026_03_20_000200_add_environment_review_id_to_review_packs_table.php similarity index 69% rename from apps/platform/database/migrations/2026_03_20_000200_add_tenant_review_id_to_review_packs_table.php rename to apps/platform/database/migrations/2026_03_20_000200_add_environment_review_id_to_review_packs_table.php index e6757d82..4d06f35b 100644 --- a/apps/platform/database/migrations/2026_03_20_000200_add_tenant_review_id_to_review_packs_table.php +++ b/apps/platform/database/migrations/2026_03_20_000200_add_environment_review_id_to_review_packs_table.php @@ -11,20 +11,20 @@ public function up(): void { Schema::table('review_packs', function (Blueprint $table): void { - $table->foreignId('tenant_review_id') + $table->foreignId('environment_review_id') ->nullable() ->after('evidence_snapshot_id') - ->constrained('tenant_reviews') + ->constrained('environment_reviews') ->nullOnDelete(); - $table->index(['tenant_review_id', 'generated_at']); + $table->index(['environment_review_id', 'generated_at']); }); } public function down(): void { Schema::table('review_packs', function (Blueprint $table): void { - $table->dropConstrainedForeignId('tenant_review_id'); + $table->dropConstrainedForeignId('environment_review_id'); }); } }; diff --git a/apps/platform/database/migrations/2026_04_10_000003_create_tenant_triage_reviews_table.php b/apps/platform/database/migrations/2026_04_10_000003_create_managed_environment_triage_reviews_table.php similarity index 65% rename from apps/platform/database/migrations/2026_04_10_000003_create_tenant_triage_reviews_table.php rename to apps/platform/database/migrations/2026_04_10_000003_create_managed_environment_triage_reviews_table.php index 2b388a4c..85f67b21 100644 --- a/apps/platform/database/migrations/2026_04_10_000003_create_tenant_triage_reviews_table.php +++ b/apps/platform/database/migrations/2026_04_10_000003_create_managed_environment_triage_reviews_table.php @@ -11,7 +11,7 @@ { public function up(): void { - Schema::create('tenant_triage_reviews', function (Blueprint $table): void { + Schema::create('managed_environment_triage_reviews', function (Blueprint $table): void { $table->id(); $table->foreignId('workspace_id')->constrained('workspaces')->cascadeOnDelete(); $table->foreignId('managed_environment_id')->constrained('managed_environments')->cascadeOnDelete(); @@ -27,24 +27,24 @@ public function up(): void $table->index( ['workspace_id', 'concern_family', 'resolved_at', 'managed_environment_id'], - 'tenant_triage_reviews_lookup_index', + 'managed_environment_triage_reviews_lookup_index', ); $table->index( ['managed_environment_id', 'concern_family', 'resolved_at'], - 'tenant_triage_reviews_tenant_family_index', + 'managed_environment_triage_reviews_environment_family_index', ); }); DB::statement(" - CREATE UNIQUE INDEX tenant_triage_reviews_active_unique - ON tenant_triage_reviews (workspace_id, managed_environment_id, concern_family) + CREATE UNIQUE INDEX managed_environment_triage_reviews_active_unique + ON managed_environment_triage_reviews (workspace_id, managed_environment_id, concern_family) WHERE resolved_at IS NULL "); if (DB::getDriverName() !== 'sqlite') { DB::statement(" - ALTER TABLE tenant_triage_reviews - ADD CONSTRAINT tenant_triage_reviews_current_state_check + ALTER TABLE managed_environment_triage_reviews + ADD CONSTRAINT managed_environment_triage_reviews_current_state_check CHECK (current_state IN ('reviewed', 'follow_up_needed')) "); } @@ -52,12 +52,12 @@ public function up(): void public function down(): void { - DB::statement('DROP INDEX IF EXISTS tenant_triage_reviews_active_unique'); + DB::statement('DROP INDEX IF EXISTS managed_environment_triage_reviews_active_unique'); if (DB::getDriverName() !== 'sqlite') { - DB::statement('ALTER TABLE tenant_triage_reviews DROP CONSTRAINT IF EXISTS tenant_triage_reviews_current_state_check'); + DB::statement('ALTER TABLE managed_environment_triage_reviews DROP CONSTRAINT IF EXISTS managed_environment_triage_reviews_current_state_check'); } - Schema::dropIfExists('tenant_triage_reviews'); + Schema::dropIfExists('managed_environment_triage_reviews'); } }; diff --git a/apps/platform/database/migrations/2026_05_07_000001_add_workspace_removal_fields_to_managed_environments_table.php b/apps/platform/database/migrations/2026_05_07_000001_add_workspace_removal_fields_to_managed_environments_table.php index 34a3578e..821d7d28 100644 --- a/apps/platform/database/migrations/2026_05_07_000001_add_workspace_removal_fields_to_managed_environments_table.php +++ b/apps/platform/database/migrations/2026_05_07_000001_add_workspace_removal_fields_to_managed_environments_table.php @@ -18,8 +18,8 @@ public function up(): void }); if (DB::getDriverName() === 'sqlite') { - DB::statement('DROP INDEX IF EXISTS tenants_current_unique'); - DB::statement('CREATE UNIQUE INDEX tenants_current_unique ON managed_environments (is_current) WHERE is_current = 1 AND deleted_at IS NULL'); + DB::statement('DROP INDEX IF EXISTS managed_environments_current_unique'); + DB::statement('CREATE UNIQUE INDEX managed_environments_current_unique ON managed_environments (is_current) WHERE is_current = 1 AND deleted_at IS NULL'); } } diff --git a/apps/platform/lang/de/localization.php b/apps/platform/lang/de/localization.php index 85060857..3d2b5d8b 100644 --- a/apps/platform/lang/de/localization.php +++ b/apps/platform/lang/de/localization.php @@ -457,8 +457,8 @@ 'workspace_next_step_review_open' => 'Review öffnen', 'workspace_next_step_package_review' => 'Paket prüfen', 'workspace_next_step_control_mapping' => 'Kontrollzuordnung prüfen', - 'no_tenant_reviews_yet' => 'Noch keine Tenant-Reviews', - 'create_first_review_description' => 'Erstellen Sie das erste Review aus einem verankerten Evidence-Snapshot, um die wiederkehrende Review-Historie für diesen Tenant zu starten.', + 'no_environment_reviews_yet' => 'Noch keine Environment-Reviews', + 'create_first_review_description' => 'Erstellen Sie das erste Review aus einem verankerten Evidence-Snapshot, um die wiederkehrende Review-Historie für diese Managed Environment zu starten.', 'create_first_review' => 'Erstes Review erstellen', 'create_review' => 'Review erstellen', 'evidence_basis' => 'Evidence-Basis', diff --git a/apps/platform/lang/en/localization.php b/apps/platform/lang/en/localization.php index 4c668f54..147afaf8 100644 --- a/apps/platform/lang/en/localization.php +++ b/apps/platform/lang/en/localization.php @@ -389,7 +389,7 @@ 'governance_package_blocked_description' => 'This account can read the released review but cannot download the current export review pack.', 'no_entitled_tenants' => 'No entitled tenants match this view', 'no_released_customer_reviews' => 'No released customer reviews match this view', - 'no_released_customer_reviews_description' => 'Publish a tenant review before it appears in the customer-safe workspace.', + 'no_released_customer_reviews_description' => 'Publish an environment review before it appears in the customer-safe workspace.', 'clear_filters_description' => 'Clear the current filters to return to the full customer review workspace for your entitled tenants.', 'adjust_filters_description' => 'Adjust filters to return to the full customer review workspace for your entitled tenants.', 'no_published_review' => 'No published review', @@ -457,8 +457,8 @@ 'workspace_next_step_review_open' => 'Open review', 'workspace_next_step_package_review' => 'Review package', 'workspace_next_step_control_mapping' => 'Review control mapping', - 'no_tenant_reviews_yet' => 'No tenant reviews yet', - 'create_first_review_description' => 'Create the first review from an anchored evidence snapshot to start the recurring review history for this tenant.', + 'no_environment_reviews_yet' => 'No environment reviews yet', + 'create_first_review_description' => 'Create the first review from an anchored evidence snapshot to start the recurring review history for this managed environment.', 'create_first_review' => 'Create first review', 'create_review' => 'Create review', 'evidence_basis' => 'Evidence basis', diff --git a/apps/platform/resources/views/filament/forms/components/managed-tenant-onboarding-verification-report.blade.php b/apps/platform/resources/views/filament/forms/components/managed-environment-onboarding-verification-report.blade.php similarity index 99% rename from apps/platform/resources/views/filament/forms/components/managed-tenant-onboarding-verification-report.blade.php rename to apps/platform/resources/views/filament/forms/components/managed-environment-onboarding-verification-report.blade.php index 4b8c785e..d748282a 100644 --- a/apps/platform/resources/views/filament/forms/components/managed-tenant-onboarding-verification-report.blade.php +++ b/apps/platform/resources/views/filament/forms/components/managed-environment-onboarding-verification-report.blade.php @@ -57,7 +57,7 @@
- Use the workflow action above to start verification for this tenant. + Use the workflow action above to start verification for this environment.
@elseif ($runState === 'active') diff --git a/apps/platform/resources/views/filament/infolists/entries/tenant-review-section.blade.php b/apps/platform/resources/views/filament/infolists/entries/environment-review-section.blade.php similarity index 100% rename from apps/platform/resources/views/filament/infolists/entries/tenant-review-section.blade.php rename to apps/platform/resources/views/filament/infolists/entries/environment-review-section.blade.php diff --git a/apps/platform/resources/views/filament/infolists/entries/tenant-review-summary.blade.php b/apps/platform/resources/views/filament/infolists/entries/environment-review-summary.blade.php similarity index 100% rename from apps/platform/resources/views/filament/infolists/entries/tenant-review-summary.blade.php rename to apps/platform/resources/views/filament/infolists/entries/environment-review-summary.blade.php diff --git a/apps/platform/resources/views/filament/pages/choose-tenant.blade.php b/apps/platform/resources/views/filament/pages/choose-environment.blade.php similarity index 97% rename from apps/platform/resources/views/filament/pages/choose-tenant.blade.php rename to apps/platform/resources/views/filament/pages/choose-environment.blade.php index 48d9b734..0608fdfa 100644 --- a/apps/platform/resources/views/filament/pages/choose-tenant.blade.php +++ b/apps/platform/resources/views/filament/pages/choose-environment.blade.php @@ -31,7 +31,7 @@ class="h-7 w-7 text-primary-500 dark:text-primary-400"
@@ -82,11 +82,11 @@ class="inline-flex items-center gap-1.5 text-sm text-gray-500 transition-colors