Week 046 — First Tests, Product Classes, and QR Unassign
The tests really helped out. That's worth putting in writing.
Week of September 29, 2025
Progress
Subscription reward allocation was the week's main lift. When a user subscribes, they should receive points. Wiring that up required knowing which product they subscribed to and how many points it carries — information that needed its own model.
The solution was a Product and Price class hierarchy following the DTO/Service/Repo pattern, backed by a JSON file instead of a database table. The DTOs define the shape, the service owns the logic, the repo handles reads (and the JSON file can be edited by hand for now, since there's no admin UI for products). The pattern was probably more structure than strictly necessary for a JSON-backed store, but it's consistent with the rest of the codebase and leaves the door open for database-backing later.
The webhook was updated to call into the new classes when a subscription event arrives.
Tests were written — the first real tests in the project. Not PHPUnit (the PHP version in the current container would need an upgrade), but a custom test harness that could be run directly. The tests isolated the Product and Price retrieval logic and caught problems before they reached real code. When things broke during implementation, the tests showed exactly where the break was rather than requiring a trace through the full request cycle.
QR code unassignment shipped Thursday — a trash-can button on the item page that detaches the QR code. Straightforward to implement; a strange console error appeared on click that had nothing to do with the unassignment itself and was set aside.
The Hard Part
The JSON backing for products introduced a fragility: if the JSON has a structural mistake, the code that reads it can produce a fatal error. Two mitigations considered — a JSON validator that runs as part of CI, and defensive code in the reader that fails gracefully. Neither was fully implemented; the JSON is simple enough right now that hand-editing is low-risk. This is the kind of technical debt that's visible and named, which is better than invisible.
Decision Made
Tests belong in this project even without a test framework. The return on investment was immediate: the Product class retrieval logic was working cleanly before it was ever called from real application code. The test harness will stay.
Next Week
Production. The application has only ever run on macbaby.local. That changes now.
