Laravel in Hamburg
Laravel development for Hamburg logistics and publishing
A Laravel development company for Hamburg freight and publishing firms. EDI messages that arrive twice and out of order, nightly imports of hundreds of thousands of rows, and rates that change by date
Hamburg's two large industries ask a backend for the same uncomfortable thing: be correct about data you did not produce and cannot correct at the source.
Freight forwarders, shipping lines and port logistics operators sit downstream of terminal systems, customs platforms and partner EDI feeds. Publishers sit downstream of wires, syndication and an archive that predates every system currently running. Neither can fix the upstream, so the application has to absorb the mess without passing it on.
Hamburg EDI messages repeat, arrive late, and arrive out of order
This is the defining property of logistics integration and the source of most of its bugs.
A partner sends a status message twice because their retry fired. A customs update for Tuesday arrives after the one for Wednesday. A correction arrives for a consignment that the system has already closed. None of these are exceptional and an application that treats them as exceptional will produce wrong totals quietly for months.
What works is unexciting. The sender's reference becomes a unique constraint, so a duplicate is rejected by the database rather than by a check somebody might remove. Events carry the time they happened as well as the time they arrived, so ordering is a property of the data rather than of the delivery. And the raw payload is stored before parsing, which is what settles the eventual disagreement about whose system was wrong.
Laravel's queue retries by design, which is a feature here and a trap if the job was never written to be safe to run twice.
The nightly Laravel batch is a reliability problem, not a speed problem
Every Hamburg logistics system has an import that runs at three in the morning and everybody is slightly afraid of.
Making it faster is mostly mechanical - insert in chunks rather than instantiating a model per row, stop querying inside the loop, and let the database do the aggregation it is better at. That work is covered under database and Eloquent engineering and it is the half that gets attention.
The half that matters more is what happens when it dies at row 240,000. If the job cannot say what it has already processed, the operator has two bad options and no good one. So the import records progress as it goes, and a restart resumes - which also means the job can be deliberately stopped, which turns a six-hour commitment into something you can interrupt.
Hamburg freight rates are true on a date
Reference data in this industry is not a lookup table. It is a history.
A freight rate, a surcharge, a port tariff, a currency conversion - each was true for a period and then was replaced. If the row is updated in place, the system loses the ability to explain a charge from three months ago, and in a dispute with a customer that is the only thing anybody wants.
The fix is a validity period on the reference row and a stored reference to the version actually used on the charge. It is slightly more schema and it is the difference between an invoice you can defend and one you can only apologise for. The same reasoning applies to money and dates generally, which are the two things in a logistics system that cannot be fixed afterwards.
A Hamburg title exists before it is published, and that is a lifecycle
In publishing, a product has an identity, a catalogue entry and a sales history before anything has been printed, and the system has to describe something that does not yet exist.
A title is announced with a provisional publication date, a provisional price and metadata that is incomplete by design. Retailers take that feed, list the product, and accept pre-orders. Then the date moves, which it does, and everything downstream has to be told. Modelling the publication date as a single field that somebody edits loses the fact that it moved, and the publication date having moved is precisely what a retailer's system needs to know.
Editions and formats are where the hierarchy gets decided. One work, several editions, each with its own identifier, price, territory rights and availability. Hardback available everywhere, paperback not yet, audio in two territories only, ebook excluded from one because the rights were sold separately. A flat product table cannot express that, and the rights dimension is the one that causes real trouble when it is missing - a product offered where it may not be sold is a contractual problem, not a display bug.
The metadata feed is an obligation with a format. Retailers consume a structured record and reject what does not conform, so the catalogue has to be able to produce a valid record per edition per territory, and know which retailer has been sent which version. That last part is what makes "why is the price wrong on that site" answerable.
Laravel royalty statements for a Hamburg publisher
Royalties are the calculation that teaches a team why versioned reference data matters, usually the hard way.
Sales arrive from a dozen channels at different granularities and on different schedules - some per transaction, some as a monthly summary, some net of returns and some gross. Normalising that into a single sales ledger, with the source and its granularity recorded, is most of the work. A summary that cannot be decomposed is still usable, provided the system knows it is a summary and does not later attempt to attribute it to a territory it never specified.
Returns arrive late, which is the structural problem. A statement for the first half of the year is issued, and returns against those sales keep coming for months afterwards. Reserves against returns are how the trade handles it - a proportion withheld, released later - and that is a balance with a policy attached rather than an adjustment somebody makes by hand.
Rates escalate on cumulative sales, which means a rate depends on the history and not just on the period. Ten per cent to five thousand copies, twelve and a half after that, counted across the life of the edition. Compute that from the period alone and the answer is wrong for every author who crossed a threshold. Compute it from cumulative units with the threshold state stored per edition and the statement is reproducible, which is the requirement - because an author is entitled to understand their statement, and a figure nobody can explain is a dispute waiting to happen.
Commercially
Scope fixed in writing before work starts, priced per project. The country-level ground - German data protection obligations on a supplier, the e-invoicing format, hosting - is on the Germany market page.
Invoiced by Codefacture Yazılım A.Ş. in Türkiye, in euros, by bank transfer to an IBAN, with no Turkish VAT under the export-of-services exemption.
