1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 15:49:35 +01:00

fix(infra): no-db Profil robuster machen und Stub-Beans ergänzen

DatabaseProfileInitializer setzt Autoconfigure-Exclusions programmatisch,
da application-no-db.yml bei spätem Profil-Aktivierung nicht geladen wird.
SpringUnitOfWork mit @Profile("!no-db") ausgeschlossen. Stub-Beans für
BatchNumberGenerator, BatchRepository, ProductionOrderRepository,
StockMovementRepository und UnitOfWork ergänzt. generate-openapi.sh
nutzt korrektes -Dspring-boot.run.profiles=no-db.
This commit is contained in:
Sebastian Frick 2026-02-25 21:43:53 +01:00
parent 72d59b4948
commit 0e58cbfacf
8 changed files with 258 additions and 3 deletions

View file

@ -5,21 +5,41 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.sql.DriverManager;
import java.util.Map;
/**
* Prüft vor dem Context-Start, ob die Datenbank erreichbar ist.
* Schlägt die Verbindung fehl, wird das Spring-Profil "no-db" aktiviert.
* Damit werden JPA, DataSource und Liquibase ausgeschlossen und Stub-Beans registriert.
*
* WICHTIG: Die Autoconfiguration-Exclusions werden hier programmatisch gesetzt,
* weil application-no-db.yml nicht geladen wird, wenn das Profil erst im
* ApplicationContextInitializer (nach prepareEnvironment) hinzugefügt wird.
*/
public class DatabaseProfileInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger log = LoggerFactory.getLogger(DatabaseProfileInitializer.class);
private static final String AUTOCONFIGURE_EXCLUDE = String.join(",",
"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration",
"org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration",
"org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration",
"org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration",
"org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration");
@Override
public void initialize(ConfigurableApplicationContext ctx) {
var env = ctx.getEnvironment();
var env = (ConfigurableEnvironment) ctx.getEnvironment();
if (env.acceptsProfiles(org.springframework.core.env.Profiles.of("no-db"))) {
log.info("Profil 'no-db' bereits aktiv überspringe DB-Check.");
applyNoDbProperties(env);
return;
}
var url = env.getProperty("spring.datasource.url", "jdbc:postgresql://localhost:5432/effigenix");
var user = env.getProperty("spring.datasource.username", "effigenix");
var pass = env.getProperty("spring.datasource.password", "effigenix");
@ -28,7 +48,14 @@ public class DatabaseProfileInitializer implements ApplicationContextInitializer
log.debug("Datenbankverbindung erfolgreich normaler Start.");
} catch (Exception e) {
log.warn("⚠️ Keine Datenbankverbindung Stub-Modus aktiv. Einige Features sind nicht verfügbar. ({})", e.getMessage());
((ConfigurableEnvironment) env).addActiveProfile("no-db");
env.addActiveProfile("no-db");
applyNoDbProperties(env);
}
}
private void applyNoDbProperties(ConfigurableEnvironment env) {
env.getPropertySources().addFirst(new MapPropertySource("no-db-overrides", Map.of(
"spring.autoconfigure.exclude", AUTOCONFIGURE_EXCLUDE
)));
}
}

View file

@ -2,6 +2,7 @@ package de.effigenix.infrastructure.config;
import de.effigenix.shared.common.Result;
import de.effigenix.shared.persistence.UnitOfWork;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@ -9,6 +10,7 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.function.Supplier;
@Component
@Profile("!no-db")
public class SpringUnitOfWork implements UnitOfWork {
private final PlatformTransactionManager txManager;

View file

@ -0,0 +1,20 @@
package de.effigenix.infrastructure.stub;
import de.effigenix.domain.production.BatchError;
import de.effigenix.domain.production.BatchNumber;
import de.effigenix.domain.production.BatchNumberGenerator;
import de.effigenix.shared.common.Result;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
@Component
@Profile("no-db")
public class StubBatchNumberGenerator implements BatchNumberGenerator {
@Override
public Result<BatchError, BatchNumber> generateNext(LocalDate date) {
return Result.failure(new BatchError.RepositoryFailure("Stub-Modus: keine Datenbankverbindung"));
}
}

View file

@ -0,0 +1,79 @@
package de.effigenix.infrastructure.stub;
import de.effigenix.domain.production.Batch;
import de.effigenix.domain.production.BatchId;
import de.effigenix.domain.production.BatchNumber;
import de.effigenix.domain.production.BatchRepository;
import de.effigenix.domain.production.BatchStatus;
import de.effigenix.domain.production.RecipeId;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
@Repository
@Profile("no-db")
public class StubBatchRepository implements BatchRepository {
private static final RepositoryError.DatabaseError STUB_ERROR =
new RepositoryError.DatabaseError("Stub-Modus: keine Datenbankverbindung");
@Override
public Result<RepositoryError, Optional<Batch>> findById(BatchId id) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findAll() {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, Optional<Batch>> findByBatchNumber(BatchNumber batchNumber) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByStatus(BatchStatus status) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByProductionDate(LocalDate date) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByRecipeIds(List<RecipeId> recipeIds) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findAllSummary() {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByStatusSummary(BatchStatus status) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByProductionDateSummary(LocalDate date) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<Batch>> findByRecipeIdsSummary(List<RecipeId> recipeIds) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, Void> save(Batch batch) {
return Result.failure(STUB_ERROR);
}
}

View file

@ -0,0 +1,35 @@
package de.effigenix.infrastructure.stub;
import de.effigenix.domain.production.ProductionOrder;
import de.effigenix.domain.production.ProductionOrderId;
import de.effigenix.domain.production.ProductionOrderRepository;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
@Profile("no-db")
public class StubProductionOrderRepository implements ProductionOrderRepository {
private static final RepositoryError.DatabaseError STUB_ERROR =
new RepositoryError.DatabaseError("Stub-Modus: keine Datenbankverbindung");
@Override
public Result<RepositoryError, Optional<ProductionOrder>> findById(ProductionOrderId id) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<ProductionOrder>> findAll() {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, Void> save(ProductionOrder productionOrder) {
return Result.failure(STUB_ERROR);
}
}

View file

@ -0,0 +1,74 @@
package de.effigenix.infrastructure.stub;
import de.effigenix.domain.inventory.MovementType;
import de.effigenix.domain.inventory.StockId;
import de.effigenix.domain.inventory.StockMovement;
import de.effigenix.domain.inventory.StockMovementId;
import de.effigenix.domain.inventory.StockMovementRepository;
import de.effigenix.domain.masterdata.ArticleId;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
@Repository
@Profile("no-db")
public class StubStockMovementRepository implements StockMovementRepository {
private static final RepositoryError.DatabaseError STUB_ERROR =
new RepositoryError.DatabaseError("Stub-Modus: keine Datenbankverbindung");
@Override
public Result<RepositoryError, Optional<StockMovement>> findById(StockMovementId id) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAll() {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByStockId(StockId stockId) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByArticleId(ArticleId articleId) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByMovementType(MovementType movementType) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByBatchReference(String batchReference) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByPerformedAtBetween(Instant from, Instant to) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByPerformedAtAfter(Instant from) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, List<StockMovement>> findAllByPerformedAtBefore(Instant to) {
return Result.failure(STUB_ERROR);
}
@Override
public Result<RepositoryError, Void> save(StockMovement stockMovement) {
return Result.failure(STUB_ERROR);
}
}

View file

@ -0,0 +1,18 @@
package de.effigenix.infrastructure.stub;
import de.effigenix.shared.common.Result;
import de.effigenix.shared.persistence.UnitOfWork;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import java.util.function.Supplier;
@Component
@Profile("no-db")
public class StubUnitOfWork implements UnitOfWork {
@Override
public <E, T> Result<E, T> executeAtomically(Supplier<Result<E, T>> work) {
return work.get();
}
}