In April 2020, every healthcare startup in Germany suddenly became important. Pharmacies were overwhelmed. Doctors were doing video consultations for the first time. Patients were mailing in paper prescriptions. The whole country woke up and noticed that the prescription pipeline — the path from a doctor writing a script to a patient getting their medication — was almost entirely analogue. In Hamburg, I joined meinrezept.online to help build the backend that would sit in the middle of that.

This is not a “we saved lives” post. It is a “here is what the actual engineering looked like” post, because the engineering was genuinely interesting and a lot of it is invisible from the outside.

The prescription format problem

Before you can route a prescription to a pharmacy, you have to read it. In Germany in 2020, this meant dealing with multiple formats: the Muster-16 paper form, early digital prescription formats that were not yet standardized, fax images, and the occasional PDF that a doctor’s office had generated from whatever practice management software they were running.

Each of these has a different extraction path. The paper form has a known layout but comes in as a scan. The digital formats have structured data but not all pharmacies could consume all of them. The PDF from the practice management software is the worst case: structured data locked inside a document format that was never meant to be parsed programmatically.

The backend’s job was to normalize all of these into a single internal representation that the rest of the system — the pharmacy routing layer, the order tracking service, the patient notification service — could consume without caring about the input format. This is a surprisingly hard problem when the input formats are evolving under you in real time, which they were in 2020 as the German government was actively pushing the Elektronisches Rezept (eRezept) rollout.

Pharmacy integration is legacy-heavy by design

Here is what the pharmacy integration space looks like from the backend: every major pharmacy chain has its own ordering system, many independent pharmacies are running WINAPO, ProFit, or ADG — practice management systems that are decades old and that expose ordering interfaces via protocols you have not heard of in a modern backend context. HTTP/JSON is not the dominant wire format. EDIFACT and HL7 variants show up. Some pharmacies have a web portal and an unofficial API that someone reverse-engineered. Some have nothing and you are back to sending a structured email.

This is not a complaint. This is just what healthcare integration looks like at the consumer-facing end. The hospital-scale EHR work I’ve done elsewhere (AFAQ, HAKEEM) operates at a different abstraction level — you’re working with HL7 FHIR, you have dedicated integration engines, you have a technical counterpart at the pharmacy or lab. At the consumer pharmacy app scale, you are often working with whatever the pharmacy actually has, which is frequently much less than you would choose.

RabbitMQ was the message broker here, which makes sense for this scale. We were not doing Kafka-level volume; we were doing reliable delivery between a manageable number of services with retry semantics, dead-letter handling, and the ability to decouple the inbound order receipt from the outbound pharmacy dispatch. RabbitMQ handles this cleanly. The exchange topology — topic exchanges routing based on pharmacy region, prescription type, and fulfillment path — let us add routing logic without touching every consumer.

Microservices with three languages and six weeks

The stack was PHP 7, Python, and Node.js. This is the real world. You inherit the language your first service was written in, you pick the best tool for the next problem (Python for the extraction work, Node.js for the real-time status API), and you end up with a polyglot codebase that is held together by the message contracts between services rather than by language consistency.

The message contract discipline matters more than the language consistency, honestly. If every service agrees on what an order.received event looks like — the schema, the versioning, the required fields — then the fact that the producer is PHP and the consumer is Node.js is an implementation detail. The dangerous failure mode is letting each service evolve its understanding of the domain independently, so that order.received means something slightly different to the pharmacy dispatch service than it does to the patient notification service. You find this out at the worst possible time, which is when a patient calls support saying they got a “prescription dispatched” notification but the pharmacy says they have no record of the order.

ReactJS on the frontend, which I was not primarily responsible for, but which connected to the same domain model through the status API. Consistency between what the patient sees in the UI and what the backend’s event log says is an underrated integration concern that became very visible when pandemic-era order volume revealed timing gaps we’d not tested at scale.

The pandemic timeline amplified everything

Joining in April 2020 meant joining a team where the product was suddenly load-tested by real user demand in a way that no staging environment had anticipated. Healthcare anxiety is a real traffic driver. The inbound order volume spikes around any news event — a lockdown announcement, a change in pharmacy opening hours, a news story about medication shortages. You learn very quickly which parts of your service are stateful and which are not, because the stateful parts are the ones that fail non-gracefully when load spikes.

What this taught me, in a very concrete way: the extraction pipeline needed to be decoupled from the order acceptance path. A slow pharmacy integration should not prevent a patient’s prescription from being received and acknowledged. The acknowledgment and the fulfillment are different concerns and they should fail independently. We made this change under load, which is not ideal, but it is a real engineering memory.

The range across healthcare domains

I have shipped healthcare software at two very different scales: large enterprise EHR and clinical workflow systems (hospital-scale, hundreds of thousands of patient records, complex clinical decision support), and consumer-facing healthcare apps (prescription ordering, patient notifications, pharmacy routing). They share regulatory requirements — patient data handling, prescription validity, audit trails — but almost nothing else.

The consumer-facing side has faster iteration cycles, less formal integration partner relationships, and more pressure to handle the long tail of edge cases in the data (the weird prescription format, the pharmacy that doesn’t respond on weekends). The enterprise side has more structured integration, formal HL7 and FHIR contracts, and slower change cycles. Both are hard. The range is useful.

I’ve been building Fulcrum — a local-first agent control plane — partly because the coordination patterns I learned in distributed healthcare backends apply directly to agent orchestration. Reliable delivery, dead-letter handling, schema-versioned event contracts: the problems are the same, the domain is different.