For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Make forge-business tenant business datasource routing work through baomidou dynamic-datasource so MyBatis-Plus Mapper/XML queries hit the current tenant's configured business database.
Architecture: Keep lowcode dynamic CRUD on its existing runtime JDBC-template context. Replace forge-business's main routing path with a dynamic-datasource adapter: resolve the current tenant to a configured dynamic-datasource dsKey, validate that the key exists in DynamicRoutingDataSource, push/pop the dsKey around annotated business service methods, and provide an executor/task decorator for async or no-login contexts.
Implementation boundary after review: Generic tenant business datasource contracts and context helpers live in forge-starter-tenant; sys_tenant/sys_config-backed resolution lives in forge-plugin-system. forge-business-core only contains a small demo endpoint for manual verification. Business tenant datasource routing does not listen to or dynamically register lowcode gen_datasource entries.
Tech Stack: Java 17, Spring Boot 3, MyBatis-Plus, baomidou dynamic-datasource 4.3.1, Forge sys_tenant/gen_datasource/sys_config.
Files:
forge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSource.javaforge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/BusinessDataSourceProperties.javaforge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceInfo.javaforge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceResolver.javaCreate: forge-server/forge-framework/forge-plugin-parent/forge-plugin-system/src/main/java/com/mdframe/forge/plugin/system/datasource/SysTenantBusinessDataSourceResolver.java
[x] Step 1: Define the annotation and properties
Create @TenantBusinessDataSource for service method/class usage and BusinessDataSourceProperties with enabled=false as the configuration default.
Make the resolver return TenantBusinessDataSourceInfo with dsKey, datasource metadata, and master fallback instead of lowcode LowcodeRuntimeDataSourceContext.
Files:
Modify: forge-server/forge-framework/forge-plugin-parent/forge-plugin-system/src/main/java/com/mdframe/forge/plugin/system/datasource/SysTenantBusinessDataSourceResolver.java
[x] Step 1: Validate configured dsKey
Read sys_tenant.default_business_datasource_code as the business datasource dsKey and verify it exists in DynamicRoutingDataSource#getDataSources().
Do not listen to gen_datasource changes and do not dynamically register lowcode datasource rows for business tenant routing.
Files:
forge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceAspect.javaforge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceExecutor.javaforge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceTaskDecorator.javaCreate: forge-server/forge-framework/forge-starter-parent/forge-starter-tenant/src/main/java/com/mdframe/forge/starter/tenant/datasource/TenantBusinessDataSourceTaskDecoratorPostProcessor.java
[x] Step 1: Add AOP route
Before annotated methods, resolve the current tenant datasource and push it with DynamicDataSourceContextHolder.push(dsKey); always call poll() in finally.
Support execute(Long tenantId, Supplier<T>) for scheduled jobs and message consumers without login context.
Capture tenant id and current dynamic datasource key when tasks are submitted, restore them inside async execution, and clear them after execution.
Files:
code-copilot/changes/lowcode-runtime-datasource-isolation/tasks.mdcode-copilot/changes/lowcode-runtime-datasource-isolation/test-spec.mdModify: code-copilot/changes/lowcode-runtime-datasource-isolation/execution-log.md
[x] Step 1: Update task status
Mark implemented core routing tasks complete and leave integration tests pending if no external test databases are available.
Run git diff --check and cd forge-server && JAVA_HOME=... mvn -pl forge-admin-server -am compile -DskipTests.
Files:
forge-server/forge-business/forge-business-core/src/main/java/com/mdframe/forge/business/core/demo/**forge-server/forge-business/forge-business-core/src/main/resources/mapper/business/BusinessDatasourceDemoMapper.xmlModify: forge-server/forge-admin-server/pom.xml
[x] Step 1: Add a mapper-backed demo
Expose /business/datasource-demo/current, /business/datasource-demo/prepare, and /business/datasource-demo/list. The demo uses MyBatis Mapper/XML, creates business_datasource_demo in the routed business database, inserts a record, and returns the current database name plus dynamic-datasource key.
Add forge-business-core to forge-admin-server so the demo controller is available when the admin server is started.