Repository navigation
feat(customer): customers - #5
Merged
Merged
Conversation
Customer is the table-shaped class documented with the jakarta.persistence annotations and CustomerDto is the business shape the service exposes. The telephone, email and address are optional, so they are nullable on both sides. The two shapes stay separate classes even though their fields are identical.
The RowMapper reads one row into a Customer and keeps the three optional columns as null when the database holds NULL. The entity mapper converts between Customer and CustomerDto in both directions. Neither queries the database or contains a business rule.
CustomerDaoImpl runs the SQL with JdbcTemplate through AbstractDao: a page ordered by id with LIMIT and OFFSET, a count, a lookup, INSERT ... RETURNING id, an update that returns the number of affected rows and a delete. Returning the affected row count lets the service detect that a row was deleted concurrently. The DAO works in entity types only and has no stereotype annotation.
CustomerServiceImpl trims and bounds the names, turns blank optional fields into null, checks the format of an email when one is given, and reports an update that affected no row as a not-found error. A customer referenced by orders cannot be deleted: the foreign key raises a DataIntegrityViolationException which the service turns into a business refusal, so no order code is needed yet. The service works in dto types, pages through PageDto and is transactional through its interface proxy.
DaoConfig and ServiceConfig declare the beans typed by interface, and ServiceConfig imports DaoConfig so importing it alone is enough. The service bean is proxied for @transactional through its interface.
CustomerRequest requires the two names and bounds every field, and accepts an absent or empty optional value while checking the email format when one is given. CustomerConverter maps to and from the core dto and builds the PageResponse. Payload classes stay distinct from core dto classes.
CustomerController follows the README table with declarative @PreAuthorize("hasPermission('CUSTOMER', 'READ'|'WRITE')"), calls only CustomerService and answers with an ApiResponse. The list validates page and size, and a creation returns 201. There is no business logic in the controller.
The customer ServiceConfig is added to the WebMvcConfig import list by fully qualified name, because every core module has a class with that simple name. Its DaoConfig comes along through the ServiceConfig import.
… module The customer DAO tests run against a real PostgreSQL, so the module declares the Testcontainers JUnit and PostgreSQL artifacts and the common test-jar holding the shared singleton container, all with test scope, like the auth and catalog modules.
The DAO test loads its own dedicated fixture, which truncates the tables it touches and loads customers, one of them with NULL optional columns. It checks CRUD, the NULL round trip, page ordering, offset and an out-of-range page, the count, an update returning one affected row for a known id and zero for an unknown one, and a delete blocked by the orders foreign key. The order that blocks the delete is inserted by SQL in the test, so the constraint is proven before the order module exists.
The RowMapper is fed a mocked ResultSet, including NULL telephone, email and address, and the entity mapper is checked with hand-built objects and no mocks.
With a mocked DAO the tests cover the page bounds, the 404 cases, trimming, blank optional fields becoming null, the length limits at their exact boundaries, every email format case, an update that affects no row, and the foreign key race on delete becoming a business refusal.
The real security configuration and a real signed JWT are used with a mocked service. Every endpoint is checked for status and JSON shape, NULL optional fields in the response, optional fields absent or empty, validation errors per field, page and size violations, an out-of-range page keeping content as an empty array, and the 404 and 422 mappings.
A parameterized test asserts, for each of the five endpoints, that no token or a revoked one gives 401, that a token holding every other permission or none gives 403, and that a token holding only the required CUSTOMER permission succeeds.
Real services and a real database prove the CRUD, NULL optional fields on create and update, the two email failure modes (400 from Bean Validation, 422 from the service), the 404 cases and the pagination bounds. A customer with an order, inserted by SQL, cannot be deleted: the answer is 422 "Customer is referenced by orders" and the customer stays, then the delete succeeds once the order is gone. Permission-less and write-only users get 403.
The three customer tasks are checked: the entity, dto, RowMapper, mapper, DAO, service and configuration of core/customer, the controller and converter in ws with the WebMvcConfig import, and the tests at all five layers with a dedicated fixture for the DAO test class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Branch
feature/customer
Task checklist
core/customer:Customerentity,CustomerDto,CustomerRowMapper,CustomerMapper,CustomerDao+ impl,CustomerService+ impl,DaoConfig/ServiceConfigws:CustomerController,CustomerConverterWebMvcConfigimportscore/customer's configCustomerDaowith its own fixture datasetCommit summary
Limits documented in the project notes: email optional and not unique, 400 (request validation) versus 422 (service) for email formats, concurrent double delete is idempotent.
Test plan
mvn clean verifyis green on the whole reactor