Why D288 Feels Broken (and Why It Isn't You)
Most students arrive at D288 expecting a normal course and find a performance assessment instead. You are handed a working Angular front end and a populated MySQL database, then asked to build the Spring Boot layer that connects them. Nothing in the middle is written for you, and that is the assignment.
The first shock is silence. The front end will not populate until you finish Task E, and your order tracking number will not appear until Task H. Students reach Task F, see a broken page, and assume they have wrecked the project. Nothing was supposed to render yet.
The second shock is that both provided diagrams are wrong in small ways. The UML and the ERD PDF disagree with each other and with the live schema, so treat the running MySQL database and the Angular DTOs as your sources of truth.
Dependency drift is the other moving target. Spring Boot 3.3.6 with Lombok 1.18.36 is the combination that consistently works, while students on 3.4.x report getters and setters that silently fail to generate. One instructor-issued POM downgraded Spring Boot to 3.0.6 to clear a connection error, so expect some version archaeology along the way.
Two administrative details matter before you begin. The lab environment resets after 40 hours, and marking it complete wipes everything, which makes your GitLab commits your only real backup. Task G was also listed as not evaluated in late 2024, and evaluator feedback is often vague enough to need a second read.
Your Study Stack: Which 20% of the Materials Actually Carries the Project
The Udemy course is the spine of this project, not a supplement. The assessment was built from Chad Darby's full-stack Angular and Spring Boot e-commerce course, so watch it while you code rather than reading about the concepts first. Section 9, videos 49 through 51, covers packages, entities, and repositories. Section 23, videos 204 through 208, walks through the purchase flow, the checkout service, and the controller.
One link has moved, and this trips up students following older guides. The ManyToMany video from "Spring Framework 5: Beginner to Guru" is no longer in the WGU Udemy subscription. The replacement material sits in Section 17 of the newer Spring Boot 4 course, with video 173 covering OneToMany mappings and video 177 covering ManyToMany.
ZyBooks is largely skippable, with two exceptions. The JavaBits video in 1.1 shows the expected package layout and the reactivity code your Division entity needs, and chapter 6.1 covers the Cart enum setup.
Everything else you need lives in a few places:
C:\LabFilesholdsRestDataConfig.java,application.properties, and the README explaining the MySQL script andng serve.- WGU Connect and Course Chatter carry version notices and fix announcements.
- The webinar archive has two videos worth watching: "Debugging Common Problems" and "Demonstration of a completed performance assessment."
That last video is your ground truth for what a finished front end should look like. Commit after every task with a real message, because the branch history is graded and cannot be reconstructed later.
Task D: The Entity Mapping That Decides Your Whole Project
One rule resolves most of the confusion in Task D. Your @Column names mirror the database, and your Java variable names mirror the Angular front end. Never mix the two sources.
Read the CREATE TABLE statements in the SQL script and copy names and data types character for character. Typos here generate no IDE warnings and cost hours of silent debugging. Case sensitivity is the usual culprit: the database column is image_url while the front end expects image_URL, and the capital letters matter. Pull your variable names from the src/app/model/dto folder, then fill in gaps from cart.ts and country.ts, since the DTO constructors do not list every field.
Relationships follow a pattern. Any <> collection is a OneToMany, its counterpart is a ManyToOne, and both sides carry annotations. For the excursion_cartitem join table, put @JoinTable on CartItem as the owning side and skip creating a separate entity file for it.
The enum catches people every term. The ERD spells it "cancelled," the database stores "canceled," and you map to the database. Apply @Enumerated(EnumType.STRING) to the enum type and to the Cart status field. If the country and division dropdown stays blank, the JavaBits reactivity code plus a @JsonProperty on the division field usually clears it. Fix the RestDataConfig import path and run the backend before you commit.
Task E and the CORS Wall: Getting localhost:4200 to Talk to localhost:8080
@CrossOrigin belongs above every repository interface, since port 8080 and port 4200 are separate origins as far as your browser is concerned. Three mistakes explain nearly every CORS failure students report: skipping the annotation, writing https when the front end runs on http, and dropping the colon between host and port. Leave @RepositoryRestResource out on your first pass, though some students later added it with pluralized paths to fix tables that would not save.
When the page loads but the data looks wrong, debug in order. Open the browser console, check the Network tab, then request localhost:8080/api/vacations directly. Missing data there points to Lombok or a mapping problem. A healthy response points to CORS or a field mismatch.
A TypeError: Cannot read properties of undefined (reading 'toString') almost always means a getter never generated. Confirm your pom.xml versions, enable annotation processing with "Obtain processors from project classpath" selected, remove stray <optional>true</optional> or <scope>provided</scope> tags, run mvn clean install, then fully restart IntelliJ rather than reloading. If Lombok still misbehaves, delete the annotations and generate getters and setters through the IDE. Confirm your config package sits under the scanned base package too, because a misplaced package makes the dropdown and tracking number fail quietly.
Task F and Beyond: Translating the Udemy "Order" Videos to Cart and CartItem
Task F is where the videos stop matching your project, so keep the translation key visible. The instructor's Order is your Cart, his OrderItem is your CartItem, and everything about shipping and billing addresses gets ignored. Build four files in the services package: Purchase, PurchaseResponse, CheckoutService, and CheckoutServiceImpl.
The repository decision breaks more checkouts than anything else. Save the cart to the cart repository, not the customer to the customer repository. Following the video literally leaves you with a 500 error on /api/checkout/purchase and no tracking number, which is the exact symptom described across a dozen threads.
Set the cart status to ordered as soon as you pull the cart from the purchase object, and implement the add method on both Cart and Customer. That method checks for a null item, initializes the HashSet, adds the item, and sets the back-reference so each object knows its owner. None of it is testable until the controller exists, so commit once the rubric items are met and plan to revisit.
Tasks G Through J: Validation, Seeding, and Final Verification
Task G asks for nullable = false constraints on the fields a customer must fill in before checkout: first name, last name, phone, address, and postal code. Apply them inside the @Column annotation, and leave create date, last update, and every auto-generated field alone. A stray nullable = false on the wrong field is a documented cause of a tracking number that never generates, so double check each one against the Add Customer form. Keep in mind that empty strings are not null values, so this constraint stops nulls but not blanks, and the evaluator checks for null cells in the table.
Task H covers the checkout flow itself. Inside placeOrder, branch before you return anything: check whether the cart is null, whether its cart items are null, and whether the collection is empty. If any condition is true, return an error message string instead of a tracking number. Since PurchaseResponse returns a string, the message cannot crash the application, and the front end stays untouched.
Verification is the other half of Task H. Add a customer, select two excursions rather than one, and complete the checkout. Confirm the order tracking number renders, the console and Network tab stay clean, and the cart, cart_items, and excursion_cartitem tables fill in MySQL Workbench.
Task I is the seeding step. Create a BootStrapData class that inserts five sample customers programmatically, matching the approach you used for sample inventory in D287. Guard the whole block with a repository count check of one or fewer, otherwise every restart duplicates your rows. Initialize each fillable field, skip the auto-generated ones, and never set a cart ID to zero, since the database expects null and treats zero as an existing record. Run the application twice to confirm the data does not double up.
Task J is cleanup and submission. Remove leftover files, fix import paths, and verify your branch history in GitLab shows a commit for each task. Export that history as a PDF instead of a screenshot, because evaluators have rejected plain images. Capture the checkout page with the console open before and after you click the button, the same view with the Network tab, and the four MySQL tables. Run this final pass in the lab environment even if you built locally, and zip the project from your file explorer if IntelliJ export fails.
An Actionable 6-Step Milestone Routine to Pass D288 in Under 10 Days
- Day 1, environment and scaffolding. Set up GitLab and IntelliJ, create your five packages, copy
RestDataConfig.javaandapplication.propertiesfromC:\LabFiles, and commit tasks A through C. - Days 2 and 3, entities. Build every entity in Task D, annotate the OneToMany and ManyToMany relationships, map the enum, fix the
RestDataConfigimport, and get a clean backend run. - Day 4, repositories. Add the DAO interfaces with
@CrossOriginon each one, then loadlocalhost:4200and confirm images and dropdowns populate before moving on. - Days 5 and 6, services and controller. Translate videos 204 through 208 into
Purchase,PurchaseResponse,CheckoutService, andCheckoutServiceImpl, save the cart to the cart repository, then wire the controller and test the tracking number. - Days 7 and 8, validation and seeding. Add your
nullable = falseconstraints, the empty cart branch, and the guarded customer seeding, verifying all four tables after each checkout. - Days 9 and 10, verification and submission. Clean imports, confirm the GitLab branch history, take the required screenshots in the lab environment, zip the project, and submit with the repo link.