- SystemUpdateService: split runUpdate() (pull+recreate) and runReset() (recreate only) - SystemUpdateController: add POST /api/system/reset endpoint - SdkAppProvisioningService: remove ensureBootstrapApp/ensureApp/ensureFeatureDefaults; resolveApp now throws 404 instead of auto-creating - SdkAppInitializer: remove ensureBootstrapApp call; only runs one-time migration marking existing system apps as isDefault=true - PrivateTenantBootstrapInitializer: remove bootstrap app creation; only ensures admin tenant account exists Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 行
2.9 KiB
Java
77 行
2.9 KiB
Java
package com.xuqm.tenant.config;
|
|
|
|
import com.xuqm.tenant.entity.TenantEntity;
|
|
import com.xuqm.tenant.repository.TenantRepository;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.boot.ApplicationArguments;
|
|
import org.springframework.boot.ApplicationRunner;
|
|
import org.springframework.core.annotation.Order;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.time.LocalDateTime;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* Runs only when DEPLOYMENT_MODE=PRIVATE.
|
|
* Ensures the bootstrap main tenant and app exist without overwriting existing data.
|
|
*/
|
|
@Component
|
|
@Order(20)
|
|
public class PrivateTenantBootstrapInitializer implements ApplicationRunner {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(PrivateTenantBootstrapInitializer.class);
|
|
|
|
private final PrivateDeploymentProperties deployProps;
|
|
private final TenantRepository tenantRepository;
|
|
private final PasswordEncoder passwordEncoder;
|
|
|
|
@Value("${tenant.bootstrap.email:admin@customer.com}")
|
|
private String bootstrapEmail;
|
|
|
|
@Value("${tenant.bootstrap.password:ChangeMe@2026}")
|
|
private String bootstrapPassword;
|
|
|
|
@Value("${tenant.bootstrap.username:admin}")
|
|
private String bootstrapUsername;
|
|
|
|
public PrivateTenantBootstrapInitializer(PrivateDeploymentProperties deployProps,
|
|
TenantRepository tenantRepository,
|
|
PasswordEncoder passwordEncoder) {
|
|
this.deployProps = deployProps;
|
|
this.tenantRepository = tenantRepository;
|
|
this.passwordEncoder = passwordEncoder;
|
|
}
|
|
|
|
@Override
|
|
@Transactional
|
|
public void run(ApplicationArguments args) {
|
|
if (!deployProps.isPrivate() || !deployProps.isTenantBootstrapEnabled()) {
|
|
return;
|
|
}
|
|
|
|
TenantEntity tenant = tenantRepository.findByEmail(bootstrapEmail)
|
|
.or(() -> tenantRepository.findByUsername(bootstrapUsername))
|
|
.orElse(null);
|
|
|
|
if (tenant == null) {
|
|
tenant = new TenantEntity();
|
|
tenant.setId(UUID.randomUUID().toString());
|
|
tenant.setUsername(bootstrapUsername);
|
|
tenant.setPassword(passwordEncoder.encode(bootstrapPassword));
|
|
tenant.setEmail(bootstrapEmail);
|
|
tenant.setNickname("Admin");
|
|
tenant.setType(TenantEntity.Type.MAIN);
|
|
tenant.setStatus(TenantEntity.Status.ACTIVE);
|
|
tenant.setCreatedAt(LocalDateTime.now());
|
|
tenantRepository.save(tenant);
|
|
log.info("[PRIVATE] Bootstrap tenant created: {}", bootstrapEmail);
|
|
} else {
|
|
log.info("[PRIVATE] Bootstrap tenant already exists: {}", bootstrapEmail);
|
|
}
|
|
}
|
|
}
|