The context
The school delivers medical training to an international audience of practitioners. Its activity combines two worlds that rarely coexist in one product: on one side an online shop with catalogue, stock, payment, physical shipping and VAT; on the other a learning platform with exams, progress tracking and named certifications.
This is an existing production codebase, live and serving real customers: my work there is as much about evolution and hardening as it is about new features.
What I built and evolved
Deep catalogue
books, courses, cycles, modules, packages and event tickets, with a three-level taxonomy, tags, reviews and per-product translations.
Dual payment rails
PayPal and Revolut, with confirmation webhooks, guest orders and coupon validation.
International shipping
two carrier integrations, destination-based rate calculation, packing slips and pickups.
Exam engine
questions with predefined answers, online sittings, grading, per-student statistics and PDF certificate generation.
Scheduled reporting
automatic delivery of configurable activity summaries.
Marketing
synchronisation with email tooling for campaigns and transactional messages.
Auto-generated API documentation
an always-current contract for the two front-end applications (customer area and back-office).
Architecture & technical decisions
The Laravel API serves two separate applications — the customer area and the admin back-office. It is therefore treated as a product in its own right, with documentation generated from the code rather than maintained by hand: on a project where front and back evolve at different rhythms, that is what prevents silent regressions.
Document generation is a subject of its own. Depending on the document — invoice, shipping label, certificate — layout constraints differ radically, which led to several PDF engines coexisting: a lightweight engine for simple high-volume documents, and a headless-browser engine for complex renders that must match the HTML exactly.
External integrations (payment, shipping, email) are encapsulated behind dedicated services. A carrier changing its API should affect one file, not the entire checkout flow.
Technical challenges
Two business models in one product. A book ships, a course is followed, a seminar is booked: three lifecycles sharing the same cart and checkout.
Shipping cost calculation. Negotiated rates vary by destination, weight and service — a pricing domain in itself, tested separately from the rest of checkout.
Catalogue internationalisation. Product content is translated in the database, not just the interface, with a clean fallback when a translation is missing.
Evolving a living codebase. Working on an application already in production demands incremental, reversible changes and constant attention to side effects.
Certificate integrity. A named certificate must be reproducible identically months later: the generation data is retained, not just the output file.