mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 15:59:35 +01:00
feat(loadtest): Gatling-Lasttests mit ~2500 Requests für komprimiertes Jahres-Volumen
Szenarien: Stammdaten-CRUD, Produktions-Workflow, Lagerverwaltung, Read-Only-Zugriffe. Batch-Repository auf Summary-Projektion umgestellt, Permissions-Changeset Merge-Konflikt aufgelöst, Unit-Enum im JsonBodyBuilder korrigiert (KILOGRAM → KG).
This commit is contained in:
parent
8a9bf849a9
commit
11fb62383b
21 changed files with 1856 additions and 38 deletions
|
|
@ -28,7 +28,7 @@ public class ListBatches {
|
|||
return Result.failure(new BatchError.Unauthorized("Not authorized to read batches"));
|
||||
}
|
||||
|
||||
switch (batchRepository.findAll()) {
|
||||
switch (batchRepository.findAllSummary()) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new BatchError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var batches) ->
|
||||
|
|
@ -41,7 +41,7 @@ public class ListBatches {
|
|||
return Result.failure(new BatchError.Unauthorized("Not authorized to read batches"));
|
||||
}
|
||||
|
||||
switch (batchRepository.findByStatus(status)) {
|
||||
switch (batchRepository.findByStatusSummary(status)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new BatchError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var batches) ->
|
||||
|
|
@ -54,7 +54,7 @@ public class ListBatches {
|
|||
return Result.failure(new BatchError.Unauthorized("Not authorized to read batches"));
|
||||
}
|
||||
|
||||
switch (batchRepository.findByProductionDate(date)) {
|
||||
switch (batchRepository.findByProductionDateSummary(date)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new BatchError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var batches) ->
|
||||
|
|
@ -75,7 +75,7 @@ public class ListBatches {
|
|||
return Result.success(List.of());
|
||||
}
|
||||
List<RecipeId> recipeIds = recipes.stream().map(Recipe::id).toList();
|
||||
switch (batchRepository.findByRecipeIds(recipeIds)) {
|
||||
switch (batchRepository.findByRecipeIdsSummary(recipeIds)) {
|
||||
case Result.Failure(var batchErr) ->
|
||||
{ return Result.failure(new BatchError.RepositoryFailure(batchErr.message())); }
|
||||
case Result.Success(var batches) ->
|
||||
|
|
|
|||
|
|
@ -21,5 +21,13 @@ public interface BatchRepository {
|
|||
|
||||
Result<RepositoryError, List<Batch>> findByRecipeIds(List<RecipeId> recipeIds);
|
||||
|
||||
Result<RepositoryError, List<Batch>> findAllSummary();
|
||||
|
||||
Result<RepositoryError, List<Batch>> findByStatusSummary(BatchStatus status);
|
||||
|
||||
Result<RepositoryError, List<Batch>> findByProductionDateSummary(LocalDate date);
|
||||
|
||||
Result<RepositoryError, List<Batch>> findByRecipeIdsSummary(List<RecipeId> recipeIds);
|
||||
|
||||
Result<RepositoryError, Void> save(Batch batch);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@ package de.effigenix.infrastructure.masterdata.persistence.repository;
|
|||
import de.effigenix.infrastructure.masterdata.persistence.entity.FrameContractEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FrameContractJpaRepository extends JpaRepository<FrameContractEntity, String> {
|
||||
|
||||
Optional<FrameContractEntity> findByCustomerId(String customerId);
|
||||
|
||||
List<FrameContractEntity> findByCustomerIdIn(List<String> customerIds);
|
||||
|
||||
void deleteByCustomerId(String customerId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.CustomerEntity;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.FrameContractEntity;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.mapper.CustomerMapper;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
|
|
@ -12,7 +13,9 @@ import org.springframework.stereotype.Repository;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
|
|
@ -52,13 +55,7 @@ public class JpaCustomerRepository implements CustomerRepository {
|
|||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findAll() {
|
||||
try {
|
||||
List<Customer> result = jpaRepository.findAll().stream()
|
||||
.map(entity -> {
|
||||
var fc = frameContractJpaRepository.findByCustomerId(entity.getId()).orElse(null);
|
||||
return mapper.toDomain(entity, fc);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findAll()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
|
|
@ -68,13 +65,7 @@ public class JpaCustomerRepository implements CustomerRepository {
|
|||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByType(CustomerType type) {
|
||||
try {
|
||||
List<Customer> result = jpaRepository.findByType(type.name()).stream()
|
||||
.map(entity -> {
|
||||
var fc = frameContractJpaRepository.findByCustomerId(entity.getId()).orElse(null);
|
||||
return mapper.toDomain(entity, fc);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findByType(type.name())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByType", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
|
|
@ -84,19 +75,24 @@ public class JpaCustomerRepository implements CustomerRepository {
|
|||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByStatus(CustomerStatus status) {
|
||||
try {
|
||||
List<Customer> result = jpaRepository.findByStatus(status.name()).stream()
|
||||
.map(entity -> {
|
||||
var fc = frameContractJpaRepository.findByCustomerId(entity.getId()).orElse(null);
|
||||
return mapper.toDomain(entity, fc);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findByStatus(status.name())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Customer> mapWithFrameContracts(List<CustomerEntity> entities) {
|
||||
List<String> customerIds = entities.stream()
|
||||
.map(CustomerEntity::getId)
|
||||
.toList();
|
||||
Map<String, FrameContractEntity> fcMap = frameContractJpaRepository.findByCustomerIdIn(customerIds).stream()
|
||||
.collect(Collectors.toMap(FrameContractEntity::getCustomerId, Function.identity()));
|
||||
return entities.stream()
|
||||
.map(entity -> mapper.toDomain(entity, fcMap.get(entity.getId())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Customer customer) {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,38 @@ public class BatchMapper {
|
|||
);
|
||||
}
|
||||
|
||||
public Batch toDomainSummary(BatchEntity entity) {
|
||||
Quantity actualQuantity = entity.getActualQuantityAmount() != null
|
||||
? Quantity.reconstitute(entity.getActualQuantityAmount(), UnitOfMeasure.valueOf(entity.getActualQuantityUnit()))
|
||||
: null;
|
||||
Quantity waste = entity.getWasteAmount() != null
|
||||
? Quantity.reconstitute(entity.getWasteAmount(), UnitOfMeasure.valueOf(entity.getWasteUnit()))
|
||||
: null;
|
||||
|
||||
return Batch.reconstitute(
|
||||
BatchId.of(entity.getId()),
|
||||
new BatchNumber(entity.getBatchNumber()),
|
||||
RecipeId.of(entity.getRecipeId()),
|
||||
BatchStatus.valueOf(entity.getStatus()),
|
||||
Quantity.reconstitute(
|
||||
entity.getPlannedQuantityAmount(),
|
||||
UnitOfMeasure.valueOf(entity.getPlannedQuantityUnit())
|
||||
),
|
||||
actualQuantity,
|
||||
waste,
|
||||
entity.getRemarks(),
|
||||
entity.getProductionDate(),
|
||||
entity.getBestBeforeDate(),
|
||||
entity.getCreatedAt(),
|
||||
entity.getUpdatedAt(),
|
||||
entity.getCompletedAt(),
|
||||
entity.getCancellationReason(),
|
||||
entity.getCancelledAt(),
|
||||
entity.getVersion(),
|
||||
List.of()
|
||||
);
|
||||
}
|
||||
|
||||
private ConsumptionEntity toConsumptionEntity(Consumption c, BatchEntity parent) {
|
||||
return new ConsumptionEntity(
|
||||
c.id().value(),
|
||||
|
|
|
|||
|
|
@ -108,6 +108,59 @@ public class JpaBatchRepository implements BatchRepository {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Batch>> findAllSummary() {
|
||||
try {
|
||||
List<Batch> result = jpaRepository.findAll().stream()
|
||||
.map(mapper::toDomainSummary)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAllSummary", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Batch>> findByStatusSummary(BatchStatus status) {
|
||||
try {
|
||||
List<Batch> result = jpaRepository.findByStatus(status.name()).stream()
|
||||
.map(mapper::toDomainSummary)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatusSummary", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Batch>> findByProductionDateSummary(LocalDate date) {
|
||||
try {
|
||||
List<Batch> result = jpaRepository.findByProductionDate(date).stream()
|
||||
.map(mapper::toDomainSummary)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByProductionDateSummary", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Batch>> findByRecipeIdsSummary(List<RecipeId> recipeIds) {
|
||||
try {
|
||||
List<String> ids = recipeIds.stream().map(RecipeId::value).toList();
|
||||
List<Batch> result = jpaRepository.findByRecipeIdIn(ids).stream()
|
||||
.map(mapper::toDomainSummary)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByRecipeIdsSummary", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Batch batch) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,16 @@
|
|||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
|
||||
|
||||
<changeSet id="025-seed-production-order-permissions" author="effigenix">
|
||||
<comment>Add PRODUCTION_ORDER_READ and PRODUCTION_ORDER_WRITE permissions for ADMIN and PRODUCTION_MANAGER roles (idempotent)</comment>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<sqlCheck expectedResult="1">
|
||||
SELECT COUNT(*) FROM role_permissions
|
||||
WHERE role_id = 'c0a80121-0000-0000-0000-000000000001'
|
||||
AND permission = 'PRODUCTION_ORDER_READ'
|
||||
</sqlCheck>
|
||||
</not>
|
||||
</preConditions>
|
||||
<comment>Add PRODUCTION_ORDER_READ and PRODUCTION_ORDER_WRITE permissions for ADMIN and PRODUCTION_MANAGER roles (skipped if already present from 002)</comment>
|
||||
|
||||
<sql>
|
||||
INSERT INTO role_permissions (role_id, permission) VALUES
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue