Institut Pasteur de Dakar

Epidemiological Surveillance Platform

Design and progressive replacement of the forms service of a national health surveillance programme, in service in Senegal and ready for the other countries where the platform is deployed.

Role
Full-Stack Software Engineer - Consultant
Period
March – August 2026
in service, multi‑country ready
Senegal
forms put into service
4
lines of code for the 4th
0
  • NestJS
  • Angular
  • TypeScript
  • PostgreSQL
  • Docker

Context

Institut Pasteur de Dakar is one of West Africa’s leading public health institutions, and runs health surveillance programmes.

In practice: health workers enter epidemiological forms in the field, some of them with samples. At the laboratory, specimens are linked to a form. Both applications send their data to the forms service, which processes it and then forwards it to the biobank.

When I joined, the field data entry application was already deployed. I added the building blocks that make forms configurable without a developer: the forms management backend, the administration console, and a shared component library. The forms are in service in Senegal today; the solution is delivered and configured to be used in the other countries where the platform is deployed.

The problem

The system relied on a legacy service in which every new form meant writing code: a hard-coded list of types, and a backend redeployment to publish a form. A software delivery timeline imposed on a public health need.

The difficulty was not designing a better system. It was substituting it for one already in production, used in several countries, without interruption. You do not take a health surveillance chain offline for the duration of a migration.

The constraints

No downtime available. Client applications in production, across several countries, depended on the existing service.

Heterogeneous deployment environments. Countries are not all equally equipped. A single release has to reach targets of different kinds.

The network is not guaranteed. Field workers enter data where they meet patients, not where there is connectivity.

A form crosses several roles. It is split into steps assigned to different roles, with handover, review, and distinct permissions depending on whether you read, start, or fill it.

Several authentication boundaries. The consuming applications do not share a directory.

Health data. Strict compartmentalisation, traceability, and sample integrity once a specimen has entered the laboratory circuit.

What I designed and built

Forms management service

Design and development

The core of the platform, written to replace the legacy service one route at a time.

See details (4)Hide details
  • Progressive migration at constant contract. The new service reproduces the legacy HTTP contract exactly. Each route can switch over independently, with no change required in any client application and no downtime window.
  • Hexagonal architecture. Domain, ports, infrastructure, and presentation kept separate, with ports injected by token. End-to-end tests run against in-memory doubles, with no real infrastructure.
  • Reliable messaging. Events are written to the database in the same transaction as the data, then published by a dedicated worker. The database stays the source of truth: a messaging incident never causes a field worker's submission to fail.
  • Data-driven forms. A new form feeds the sample circuit as soon as its schema declares the corresponding block. No hard-coded list, no backend redeployment to publish a form.

Shared component library

Design and maintenance

Nineteen components shared by three applications, built on a kit-first strategy: extract rather than duplicate. Wizard and sub-step navigation, editable grids, text, select, chip, tile, counter, date and time fields, upload, geolocation, autosave.

Forms administration console

Design and development

The application for designing, versioning, publishing, and managing access to forms. It is what makes the rest usable without a developer.

Field data entry application

Major contributor

The Progressive Web App used by health workers, already in production when I joined.

See details (3)Hide details
  • Custom form rendering engine, roughly 4,400 lines, with no dependency on the third-party library used until then: wizard, conditional fields, grids, per-step validation, prefilling.
  • Offline-first: drafts persisted locally and resumed without a connection.
  • Community surveillance: moving from a community alert to a prefilled clinical form.

Laboratory application

Integration

Linking specimens to a form: pick a project, then a form, fill it in and send it to the forms service, which then forwards the data to the biobank. Mostly backend work, along with realigning this application's rendering engine with the field application's.

Infrastructure and delivery

Per-environment configuration, continuous integration and deployment pipelines, secrets management.

Decisions and trade-offs

Reproducing the legacy HTTP contract exactly
This means inheriting API choices you would not have made yourself, and carrying them into a new architecture. In exchange, the switchover happens route by route, every step is reversible, and no client application had to change. On a health surveillance system, reversibility is worth more than elegance.
Writing events to the database before publishing them
One more worker and one more purge to operate, against the guarantee that a messaging outage never reaches the field worker. When data entry happens in the field, a failed submission cannot be retried: the person has already left.
In-memory doubles rather than test containers
This imposes design discipline — anything leaving the domain has to go through a port — but the end-to-end suite runs anywhere, with no database, no messaging, and no identity provider.
Declaring the sample circuit in the form schema
The alternative, a list of types maintained in the backend, would have preserved exactly the coupling we were trying to remove. The success criterion was that a new form should no longer require a developer.
Writing a custom rendering engine on the field side
Rather than keeping the existing dependency. Roughly 4,400 lines to maintain, against full control of offline behaviour, per-step validation, and prefilling — precisely what real-world use depended on.
Extracting components before duplicating them
Three applications, one versioned and published library: a fix made once benefits all three, and visual drift never sets in.

The forms delivered

A forms engine is only worth what it is willing to carry. Four forms went into service in Senegal, deliberately different in nature.

  • A hospital circuit

    Samples attached to the form, processed by the forms service and then forwarded to the biobank.

  • A community circuit

    Community-based surveillance picks up signals where they appear, before they reach a care facility. The circuit has two steps, from a community worker to a health professional who validates, with automatic routing into the validator's queue. A bidirectional bridge links these alerts to the corresponding clinical form, prefilled from the source.

  • An irreversible notification

    A notification, not a clinical observation: transmission is final, which calls for an exhaustive summary before sending.

  • A fourth form, published under pressure

    Put into service through the intended path, with no developer involved.

The first three were delivered while the platform was being built. They are what tested the engine's generality: a hospital circuit, a community circuit with two-stage validation, and an irreversible notification have almost nothing in common, and having to fit them into the same abstraction is what shaped the design.

The proof

The fourth demonstrates something else.

The whole platform rests on one promise: publishing a new form should no longer require a developer. Under the pressure of a health response, the corresponding form went into service through the administration console, with no code written and no backend redeployment.

That is the only validation that counts for a system of this kind. Until a form has been published under pressure, through the intended path, a decoupled architecture remains an intention.