Skip to content

Startup improvements#3928

Draft
jmendeza wants to merge 10 commits into
craftercms:developfrom
jmendeza:feature/8652-5x
Draft

Startup improvements#3928
jmendeza wants to merge 10 commits into
craftercms:developfrom
jmendeza:feature/8652-5x

Conversation

@jmendeza
Copy link
Copy Markdown
Member

@jmendeza jmendeza commented May 21, 2026

Startup improvements
craftercms/craftercms#8652

Summary by CodeRabbit

  • New Features

    • Added site bootstrap completion requirement enforcement and state tracking.
    • Added new error code for incomplete site bootstrap operations.
  • Bug Fixes

    • Updated API error codes to reflect site bootstrap state instead of organization status.
  • Chores

    • Removed deprecated WebDAV v1 service and Elastic Transcoder functionality.
    • Removed organization management features from the system.
    • Simplified group and user management by removing organization-scoped operations.
    • Updated database schema (version 5.0.0.18) with organization removal and bootstrap state tracking.
    • Refactored bootstrap startup flow with improved event-driven coordination.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Walkthrough

This PR removes organization-scoped group and user management APIs, introduces per-site bootstrap state tracking with annotation-based operation gating, refactors the startup event flow using semaphore-based coordination between system and site upgrades, removes deprecated WebDAV and ElasticTranscoder features, and updates the database schema to version 5.0.0.18.

Changes

Organization Removal & Site Bootstrap State Gating

Layer / File(s) Summary
Site Bootstrap State Tracking Interface & Implementation
src/main/java/org/craftercms/studio/api/v2/utils/spring/context/SiteBootstrapStateProvider.java, src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/SiteBootstrapStateProviderImpl.java, src/main/java/org/craftercms/studio/impl/v2/service/site/internal/SitesServiceInternalImpl.java
Introduces SiteBootstrapStateProvider interface for querying/marking per-site bootstrap readiness, implements with thread-safe in-memory tracking, wires into SitesServiceInternalImpl.getAllSites() to check bootstrap state and return sites in BOOTSTRAPPING state when not ready.
Bootstrap Completion Annotation & AspectJ Guard Handler
src/main/java/org/craftercms/studio/api/v2/annotation/RequireSiteBootstrapComplete.java, src/main/java/org/craftercms/studio/api/v2/annotation/RequireSiteBootstrapCompleteAnnotationHandler.java
Adds @RequireSiteBootstrapComplete annotation targeting methods/types, implements AspectJ @Around handler that intercepts annotated calls, extracts site ID, checks siteBootstrapStateProvider.isSiteReady(siteId), and throws SiteBootstrapNotCompleteException when bootstrap incomplete.
Organization Removal from Service Contracts
src/main/java/org/craftercms/studio/api/v2/service/security/GroupService.java, src/main/java/org/craftercms/studio/api/v2/service/security/UserService.java
Updates GroupService to remove organization-scoped overloads (getAllGroups, getAllGroupsTotal, createGroup, updateGroup that accepted orgId), updates UserService to remove orgId from getAllUsersForSite and getAllUsersForSiteTotal.
Organization Removal from Service Implementations
src/main/java/org/craftercms/studio/impl/v2/service/security/GroupServiceImpl.java, src/main/java/org/craftercms/studio/impl/v2/service/security/UserServiceImpl.java, src/main/java/org/craftercms/studio/impl/v2/service/security/internal/GroupServiceInternalImpl.java, src/main/java/org/craftercms/studio/impl/v2/service/security/internal/UserServiceInternalImpl.java
Removes OrganizationServiceInternal dependency from GroupServiceImpl constructor, updates group/user listing methods to omit orgId parameter and organization-existence validation, delegates directly to internal service counterparts.
Organization Removal from DAL & Models
src/main/java/org/craftercms/studio/api/v2/dal/GroupDAO.java, src/main/java/org/craftercms/studio/api/v2/dal/Organization.java, src/main/java/org/craftercms/studio/api/v2/dal/AuditLog.java, src/main/java/org/craftercms/studio/api/v2/dal/Group.java, src/main/java/org/craftercms/studio/api/v2/dal/QueryParameterNames.java, src/main/java/org/craftercms/studio/api/v2/exception/OrganizationNotFoundException.java
Removes Organization DAL class, OrganizationNotFoundException exception, ORG_ID query parameter, organizationId from AuditLog, organization association from Group, and updates GroupDAO signatures to omit orgId.
REST Controller Organization Removal
src/main/java/org/craftercms/studio/controller/rest/v2/GroupsController.java, src/main/java/org/craftercms/studio/controller/rest/v2/UsersController.java, src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java
Removes DEFAULT_ORGANIZATION_ID usage from controller endpoints, updates service call signatures to omit orgId, removes OrganizationNotFoundException from throws clauses and exception handler.
Bootstrap Completion Gating Applied to Content Service
src/main/java/org/craftercms/studio/impl/v2/service/content/ContentServiceImpl.java
Adds @RequireSiteBootstrapComplete to all public content operation endpoints (exists checks, retrieval, deletion, locking, moving, reads, version history, writes, copies, duplicates, listing).
Bootstrap Completion Gating Applied to Sites Service
src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java
Adds @RequireSiteBootstrapComplete to site operation endpoints (updateSite, unlockSite, deleteSite, getPublishingStatus, enablePublishing, duplicate).
Bootstrap/Upgrade Event Flow Refactoring
src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/BootstrapManagerImpl.java, src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSitesBootstrapEvent.java, src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSitesUpgradeEvent.java, src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSystemUpgradeEvent.java
Refactors BootstrapManagerImpl to use semaphore-based coordination, splits upgrade flow into StartSystemUpgradeEvent (blueprint/db) and StartSitesUpgradeEvent (per-site), renames events, adds ApplicationEventPublisherAware for event publication.
Upgrade Manager Bootstrap State Integration
src/main/java/org/craftercms/studio/impl/v2/upgrade/StudioUpgradeManagerImpl.java
Wires SiteBootstrapStateProvider into constructor, marks sites as ready after configuration upgrade, splits startUpgrade() listener into separate system and sites upgrade handlers.
Startup Configuration & Event Listener Updates
src/main/java/org/craftercms/studio/impl/v2/repository/GitStartupConfig.java, src/main/java/org/craftercms/studio/impl/v2/repository/RepositoryStartupCleanup.java, src/main/java/org/craftercms/studio/api/v2/utils/spring/context/BootstrapManager.java
Updates GitStartupConfig to listen on ContextRefreshedEvent (root context) with execution-time logging, adds @LogExecutionTime to RepositoryStartupCleanup, introduces BootstrapManager interface for lifecycle hooks.
Database Schema & DAL Mapper Updates
src/main/resources/crafter/studio/database/createDDL.sql, src/main/resources/crafter/studio/database/upgrade/5.0.x/5.0.0.17-to-5.0.0.18.sql, src/main/resources/org/craftercms/studio/api/v2/dal/AuditDAO.xml, src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml
Updates schema to version 5.0.0.18, removes organization and organization_user tables, removes org_id from group, updates migration script to drop organization references, removes organizationId mapping from AuditDAO.xml, updates GroupDAO.xml queries to omit org_id.
Spring Bean & XML Configuration
src/main/resources/crafter/studio/studio-services-context.xml, src/main/resources/crafter/studio/security/common.xml, src/main/resources/crafter/studio/studio-config.yaml, src/main/resources/crafter/studio/studio-upgrade-context.xml, src/main/resources/crafter/studio/studio-websocket-context.xml, src/main/resources/crafter/studio/upgrade/pipelines.yaml
Converts repositoryStartupCleanup to conditional bean, changes bootstrapManager to BootstrapManagerImpl, adds siteBootstrapStateProvider bean, removes organizationServiceInternal, removes transcoder/WebDAV beans, adds bootstrap annotation handler bean, adds startup cleanup config property, corrects pipeline YAML structure.
Legacy Feature & Deprecation Cleanup
src/main/java/org/craftercms/studio/api/v1/aws/elastictranscoder/ElasticTranscoder.java, src/main/java/org/craftercms/studio/impl/v1/aws/elastictranscoder/TranscoderProfileMapper.java, src/main/java/org/craftercms/studio/api/v1/service/webdav/WebDavService.java, src/main/java/org/craftercms/studio/impl/v1/service/webdav/WebDavServiceImpl.java, src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/plugin/DescriptorV2UpgradeOperation.java, src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AddSiteUuidOperation.java, src/main/java/org/craftercms/studio/api/v1/constant/StudioConstants.java, src/main/java/org/craftercms/studio/model/rest/ApiResponse.java
Removes ElasticTranscoder interface and TranscoderProfileMapper implementation, removes deprecated WebDAV v1 WebDavService interface and WebDavServiceImpl, removes DescriptorV2UpgradeOperation and AddSiteUuidOperation upgrade operations, removes DEFAULT_ORGANIZATION_ID constant, removes organization-related ApiResponse codes (ORG_NOT_FOUND, ORG_ALREADY_EXISTS), adds SITE_BOOTSTRAP_NOT_COMPLETE code.
Miscellaneous Updates & Tests
src/main/java/org/craftercms/studio/impl/v1/service/content/DmPageNavigationOrderServiceImpl.java, src/test/java/org/craftercms/studio/impl/v2/service/content/ContentServiceImplTest.java, src/main/java/org/craftercms/studio/impl/v2/service/audit/internal/AuditServiceInternalImpl.java
Updates copyright years across files (2025/2022 → 2026), reorders imports, updates test to use AnnotationUtils.getAnnotation() for annotation presence checks, adds Site.State.BOOTSTRAPPING constant.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • craftercms/studio#3923: Aligns with main PR's organization removal from API response documentation and organization model cleanup.
  • craftercms/studio#3922: Overlaps with bootstrap annotation/handler additions and updated API response codes for site bootstrap state.

Suggested reviewers

  • sumerjabri
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java`:
- Around line 129-132: The enablePublishing method is annotated with
`@RequireSiteBootstrapComplete` but its siteId parameter lacks the `@SiteId`
annotation so the bootstrap aspect cannot reliably resolve the target site;
update the method signature for enablePublishing to annotate the siteId
parameter with `@SiteId` in addition to the existing
`@ProtectedResourceId`(SITE_ID_RESOURCE_ID) so the bootstrap gating aspect can
correctly resolve and validate the site before calling
sitesServiceInternal.enablePublishing.

In
`@src/main/java/org/craftercms/studio/impl/v2/upgrade/StudioUpgradeManagerImpl.java`:
- Around line 139-141: The call to siteBootstrapStateProvider.markSiteAsReady is
executed unconditionally even though upgradeSiteConfiguration catches and
swallows errors; change the flow so the site is only marked ready when the
config upgrade actually succeeded by having upgradeSiteConfiguration report
success (e.g., return boolean or throw on failure) and update
StudioUpgradeManagerImpl to check that result before calling
siteBootstrapStateProvider.markSiteAsReady(context.getTarget()); alternatively
catch specific exceptions around upgradeSiteConfiguration here and skip marking
ready on failure, ensuring upgradeSiteConfiguration and/or the caller use clear
success/failure signaling rather than logging-only.

In
`@src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/BootstrapManagerImpl.java`:
- Around line 87-94: The catch for InterruptedException in BootstrapManagerImpl
currently logs and restores the interrupt but then lets execution continue and
returns a StartSitesUpgradeEvent; change the catch to stop the flow by either
rethrowing a runtime exception or returning a no-op (do not produce
StartSitesUpgradeEvent). Concretely, inside the catch where
upgradeSemaphore.acquire() is handled, after Thread.currentThread().interrupt()
either throw a new IllegalStateException("Interrupted waiting for system
upgrade", e) (so callers won't start site upgrades) or return null/a dedicated
abort event instead of falling through to return new
StartSitesUpgradeEvent(this); update any callers if you choose to return null to
handle the abort case.

In `@src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml`:
- Around line 53-71: The mapper IDs in GroupDAO.xml don't match the DAO method
names; rename the <select> id "getAllGroups" to "getAllGroupsForOrganization"
and "getAllGroupsTotal" to "getAllGroupsForOrganizationTotal" so MyBatis can
bind to the GroupDAO methods; keep the existing resultMap/resultType, parameter
bindings (keyword -> pattern bind), and SQL clauses unchanged, only update the
id attributes to exactly match the GroupDAO method names.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5a58e55f-7793-42e2-afec-b0517e741d2c

📥 Commits

Reviewing files that changed from the base of the PR and between c7abf4e and 32a6f03.

📒 Files selected for processing (54)
  • src/main/api/studio-api.yaml
  • src/main/java/org/craftercms/studio/api/v1/aws/elastictranscoder/ElasticTranscoder.java
  • src/main/java/org/craftercms/studio/api/v1/constant/StudioConstants.java
  • src/main/java/org/craftercms/studio/api/v1/service/webdav/WebDavService.java
  • src/main/java/org/craftercms/studio/api/v2/annotation/RequireSiteBootstrapComplete.java
  • src/main/java/org/craftercms/studio/api/v2/annotation/RequireSiteBootstrapCompleteAnnotationHandler.java
  • src/main/java/org/craftercms/studio/api/v2/dal/AuditLog.java
  • src/main/java/org/craftercms/studio/api/v2/dal/Group.java
  • src/main/java/org/craftercms/studio/api/v2/dal/GroupDAO.java
  • src/main/java/org/craftercms/studio/api/v2/dal/Organization.java
  • src/main/java/org/craftercms/studio/api/v2/dal/QueryParameterNames.java
  • src/main/java/org/craftercms/studio/api/v2/dal/Site.java
  • src/main/java/org/craftercms/studio/api/v2/exception/OrganizationNotFoundException.java
  • src/main/java/org/craftercms/studio/api/v2/exception/SiteBootstrapNotCompleteException.java
  • src/main/java/org/craftercms/studio/api/v2/service/security/GroupService.java
  • src/main/java/org/craftercms/studio/api/v2/service/security/UserService.java
  • src/main/java/org/craftercms/studio/api/v2/utils/spring/context/BootstrapManager.java
  • src/main/java/org/craftercms/studio/api/v2/utils/spring/context/SiteBootstrapStateProvider.java
  • src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java
  • src/main/java/org/craftercms/studio/controller/rest/v2/GroupsController.java
  • src/main/java/org/craftercms/studio/controller/rest/v2/UsersController.java
  • src/main/java/org/craftercms/studio/impl/v1/aws/elastictranscoder/TranscoderProfileMapper.java
  • src/main/java/org/craftercms/studio/impl/v1/service/content/DmPageNavigationOrderServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v1/service/webdav/WebDavServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/repository/GitStartupConfig.java
  • src/main/java/org/craftercms/studio/impl/v2/repository/RepositoryStartupCleanup.java
  • src/main/java/org/craftercms/studio/impl/v2/service/audit/internal/AuditServiceInternalImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/content/ContentServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/security/GroupServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/security/UserServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/security/internal/GroupServiceInternalImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/security/internal/UserServiceInternalImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/service/site/internal/SitesServiceInternalImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/upgrade/StudioUpgradeManagerImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/plugin/DescriptorV2UpgradeOperation.java
  • src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AddSiteUuidOperation.java
  • src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/BootstrapManagerImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/SiteBootstrapStateProviderImpl.java
  • src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSitesBootstrapEvent.java
  • src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSitesUpgradeEvent.java
  • src/main/java/org/craftercms/studio/impl/v2/utils/spring/event/StartSystemUpgradeEvent.java
  • src/main/java/org/craftercms/studio/model/rest/ApiResponse.java
  • src/main/resources/crafter/studio/database/createDDL.sql
  • src/main/resources/crafter/studio/database/upgrade/5.0.x/5.0.0.17-to-5.0.0.18.sql
  • src/main/resources/crafter/studio/security/common.xml
  • src/main/resources/crafter/studio/studio-config.yaml
  • src/main/resources/crafter/studio/studio-services-context.xml
  • src/main/resources/crafter/studio/studio-upgrade-context.xml
  • src/main/resources/crafter/studio/studio-websocket-context.xml
  • src/main/resources/crafter/studio/upgrade/pipelines.yaml
  • src/main/resources/org/craftercms/studio/api/v2/dal/AuditDAO.xml
  • src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml
  • src/test/java/org/craftercms/studio/impl/v2/service/content/ContentServiceImplTest.java
💤 Files with no reviewable changes (11)
  • src/main/java/org/craftercms/studio/api/v1/constant/StudioConstants.java
  • src/main/java/org/craftercms/studio/api/v1/aws/elastictranscoder/ElasticTranscoder.java
  • src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java
  • src/main/java/org/craftercms/studio/impl/v1/aws/elastictranscoder/TranscoderProfileMapper.java
  • src/main/java/org/craftercms/studio/api/v1/service/webdav/WebDavService.java
  • src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AddSiteUuidOperation.java
  • src/main/java/org/craftercms/studio/api/v2/dal/Organization.java
  • src/main/java/org/craftercms/studio/api/v2/exception/OrganizationNotFoundException.java
  • src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/plugin/DescriptorV2UpgradeOperation.java
  • src/main/resources/crafter/studio/studio-upgrade-context.xml
  • src/main/java/org/craftercms/studio/impl/v1/service/webdav/WebDavServiceImpl.java

Comment on lines +129 to 132
@RequireSiteBootstrapComplete
@HasPermission(type = DefaultPermission.class, action = PERMISSION_START_STOP_PUBLISHER)
public void enablePublishing(@ProtectedResourceId(SITE_ID_RESOURCE_ID) String siteId, boolean enabled) {
sitesServiceInternal.enablePublishing(siteId, enabled);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add @SiteId to enablePublishing so bootstrap gating can resolve the target site.

This method is now guarded by @RequireSiteBootstrapComplete, but its siteId argument is not annotated with @SiteId. The bootstrap aspect resolves site IDs via @SiteId, so this can cause incorrect/null resolution and block valid calls.

💡 Proposed fix
-	public void enablePublishing(`@ProtectedResourceId`(SITE_ID_RESOURCE_ID) String siteId, boolean enabled) {
+	public void enablePublishing(`@SiteId` `@ProtectedResourceId`(SITE_ID_RESOURCE_ID) String siteId, boolean enabled) {
 		sitesServiceInternal.enablePublishing(siteId, enabled);
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@RequireSiteBootstrapComplete
@HasPermission(type = DefaultPermission.class, action = PERMISSION_START_STOP_PUBLISHER)
public void enablePublishing(@ProtectedResourceId(SITE_ID_RESOURCE_ID) String siteId, boolean enabled) {
sitesServiceInternal.enablePublishing(siteId, enabled);
`@RequireSiteBootstrapComplete`
`@HasPermission`(type = DefaultPermission.class, action = PERMISSION_START_STOP_PUBLISHER)
public void enablePublishing(`@SiteId` `@ProtectedResourceId`(SITE_ID_RESOURCE_ID) String siteId, boolean enabled) {
sitesServiceInternal.enablePublishing(siteId, enabled);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java`
around lines 129 - 132, The enablePublishing method is annotated with
`@RequireSiteBootstrapComplete` but its siteId parameter lacks the `@SiteId`
annotation so the bootstrap aspect cannot reliably resolve the target site;
update the method signature for enablePublishing to annotate the siteId
parameter with `@SiteId` in addition to the existing
`@ProtectedResourceId`(SITE_ID_RESOURCE_ID) so the bootstrap gating aspect can
correctly resolve and validate the site before calling
sitesServiceInternal.enablePublishing.

Comment on lines 139 to 141
upgradeSiteConfiguration((StudioUpgradeContext) context);
siteBootstrapStateProvider.markSiteAsReady(context.getTarget());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid marking sites ready when config upgrade errors are swallowed.

Line 140 marks the site as ready unconditionally. Since upgradeSiteConfiguration(...) catches broad exceptions and only logs them, failed config upgrades can still transition a site to ready.

🛠️ Proposed fix
-        } catch (Exception e) {
-            logger.error("Failed to upgrade the configuration file '{}'", configPath, e);
+        } catch (Exception e) {
+            logger.error("Failed to upgrade the configuration file '{}'", configPath, e);
+            throw new UpgradeException("Failed to upgrade site configuration for site '" + site + "'", e);
         } finally {
             context.clearCurrentConfig();
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/craftercms/studio/impl/v2/upgrade/StudioUpgradeManagerImpl.java`
around lines 139 - 141, The call to siteBootstrapStateProvider.markSiteAsReady
is executed unconditionally even though upgradeSiteConfiguration catches and
swallows errors; change the flow so the site is only marked ready when the
config upgrade actually succeeded by having upgradeSiteConfiguration report
success (e.g., return boolean or throw on failure) and update
StudioUpgradeManagerImpl to check that result before calling
siteBootstrapStateProvider.markSiteAsReady(context.getTarget()); alternatively
catch specific exceptions around upgradeSiteConfiguration here and skip marking
ready on failure, ensuring upgradeSiteConfiguration and/or the caller use clear
success/failure signaling rather than logging-only.

Comment on lines +87 to +94
try {
upgradeSemaphore.acquire();
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting for system upgrade to complete, starting sites upgrade anyway", e);
Thread.currentThread().interrupt(); // restore interrupt status
}
logger.info("Start upgrade ...");
return new StartSitesUpgradeEvent(this);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Do not continue to sites upgrade after interruption.

If semaphore wait is interrupted, the code currently still returns StartSitesUpgradeEvent, which can violate bootstrap ordering and run site upgrades before system upgrade completion.

🛠️ Proposed fix
  try {
      upgradeSemaphore.acquire();
  } catch (InterruptedException e) {
-     logger.warn("Interrupted while waiting for system upgrade to complete, starting sites upgrade anyway", e);
-     Thread.currentThread().interrupt(); // restore interrupt status
+     logger.warn("Interrupted while waiting for system upgrade to complete; skipping sites upgrade start", e);
+     Thread.currentThread().interrupt(); // restore interrupt status
+     return null;
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
upgradeSemaphore.acquire();
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting for system upgrade to complete, starting sites upgrade anyway", e);
Thread.currentThread().interrupt(); // restore interrupt status
}
logger.info("Start upgrade ...");
return new StartSitesUpgradeEvent(this);
try {
upgradeSemaphore.acquire();
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting for system upgrade to complete; skipping sites upgrade start", e);
Thread.currentThread().interrupt(); // restore interrupt status
return null;
}
logger.info("Start upgrade ...");
return new StartSitesUpgradeEvent(this);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/craftercms/studio/impl/v2/utils/spring/context/BootstrapManagerImpl.java`
around lines 87 - 94, The catch for InterruptedException in BootstrapManagerImpl
currently logs and restores the interrupt but then lets execution continue and
returns a StartSitesUpgradeEvent; change the catch to stop the flow by either
rethrowing a runtime exception or returning a no-op (do not produce
StartSitesUpgradeEvent). Concretely, inside the catch where
upgradeSemaphore.acquire() is handled, after Thread.currentThread().interrupt()
either throw a new IllegalStateException("Interrupted waiting for system
upgrade", e) (so callers won't start site upgrades) or return null/a dedicated
abort event instead of falling through to return new
StartSitesUpgradeEvent(this); update any callers if you choose to return null to
handle the abort case.

Comment on lines +53 to +71
<select id="getAllGroups" resultMap="GroupMap">
SELECT * FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
<if test="sort != null and sort != '' ">
ORDER BY ${sort}
</if>
LIMIT #{offset}, #{limit}
</select>

<select id="getAllGroupsTotal" resultType="Integer" >
SELECT count(1) FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
</select>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare DAO interface method names with mapper query IDs

echo "=== DAO interface method names ==="
rg -n 'List<Group> getAllGroups|int getAllGroupsTotal|getAllGroupsForOrganization' --type java src/main/java/org/craftercms/studio/api/v2/dal/GroupDAO.java

echo ""
echo "=== Mapper query IDs ==="
rg -n 'select id="getAllGroups|select id="getAllGroupsForOrganization' src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml

Repository: craftercms/studio

Length of output: 385


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "=== Mapper statement ids for getAllGroups* ==="
rg -n 'id="getAllGroups(ForOrganization)?(Total)?"' src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml

echo ""
echo "=== Any other mapper ids matching DAO methods ==="
rg -n 'getAllGroupsForOrganization(Total)?' src/main/resources/org/craftercms/studio/api/v2/dal

Repository: craftercms/studio

Length of output: 272


Fix MyBatis mapper IDs to match GroupDAO method names

GroupDAO.java declares getAllGroupsForOrganization / getAllGroupsForOrganizationTotal, but GroupDAO.xml defines getAllGroups / getAllGroupsTotal. The statement id must match the DAO method name for MyBatis to bind it.

🐛 Proposed fix
-	<select id="getAllGroups" resultMap="GroupMap">
+	<select id="getAllGroupsForOrganization" resultMap="GroupMap">
         SELECT * FROM `group`
         <if test="keyword != null" >
             <bind name="pattern" value="'%' + keyword + '%'" />
             WHERE group_name like #{pattern}
         </if>
         <if test="sort != null and sort != '' ">
             ORDER BY ${sort}
         </if>
         LIMIT #{offset}, #{limit}
     </select>

-    <select id="getAllGroupsTotal" resultType="Integer" >
+    <select id="getAllGroupsForOrganizationTotal" resultType="Integer" >
         SELECT count(1) FROM `group`
         <if test="keyword != null" >
             <bind name="pattern" value="'%' + keyword + '%'" />
             WHERE group_name like #{pattern}
         </if>
     </select>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<select id="getAllGroups" resultMap="GroupMap">
SELECT * FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
<if test="sort != null and sort != '' ">
ORDER BY ${sort}
</if>
LIMIT #{offset}, #{limit}
</select>
<select id="getAllGroupsTotal" resultType="Integer" >
SELECT count(1) FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
</select>
<select id="getAllGroupsForOrganization" resultMap="GroupMap">
SELECT * FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
<if test="sort != null and sort != '' ">
ORDER BY ${sort}
</if>
LIMIT #{offset}, #{limit}
</select>
<select id="getAllGroupsForOrganizationTotal" resultType="Integer" >
SELECT count(1) FROM `group`
<if test="keyword != null" >
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE group_name like #{pattern}
</if>
</select>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml` around
lines 53 - 71, The mapper IDs in GroupDAO.xml don't match the DAO method names;
rename the <select> id "getAllGroups" to "getAllGroupsForOrganization" and
"getAllGroupsTotal" to "getAllGroupsForOrganizationTotal" so MyBatis can bind to
the GroupDAO methods; keep the existing resultMap/resultType, parameter bindings
(keyword -> pattern bind), and SQL clauses unchanged, only update the id
attributes to exactly match the GroupDAO method names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant