IVD Document Portal with Operator Panel
A regulatory document and electronic Instructions For Use (eIFU) portal I built at Vitrosens Biotechnology for in vitro diagnostic products, live at docs.vitrosens.com. It has two sides: a public resource portal where customers look up a lot and download the right documents, and an operator panel where the team manages products, lots, and documents. The two are kept apart by network, database, and storage, and connect only through a one-way, cryptographically signed channel. Built with FastAPI, React 19, and PostgreSQL.
- Python
- FastAPI
- React
- TypeScript
- PostgreSQL
- Docker
- Nginx
- Keycloak
Summary. A regulatory document and electronic Instructions For Use (eIFU) portal I built at Vitrosens Biotechnology for in vitro diagnostic products, live at docs.vitrosens.com. It has two sides: a public resource portal where customers look up a lot and download the right documents, and an operator panel where the team manages everything behind it. The two are kept apart by network, database, and storage, and connect only through a one-way, signed channel.
Two sides, one secure channel
The operator side
The operator panel is where the team manages the catalogue: products, their lots (batches), and more than twenty regulated document types such as Instructions For Use, Certificates of Analysis, and safety data sheets. Documents move through a draft, active, and archived workflow with roles and an approval trail, plus CSV import and export and a built-in translation helper. Behind it is a FastAPI service with async SQLAlchemy on PostgreSQL, files in MinIO, and sign-in through Keycloak single sign-on.
The public side
The public resource portal is where customers search a lot number or browse the eIFU directory and download the right document in their language. It runs on its own network, database, and storage, with a read-only API, so a spike of public traffic or a bad actor never reaches the operator system. Lot lookups are rate-limited and guarded against enumeration, so the catalogue cannot be scraped by guessing lot numbers in sequence.
How they connect securely
The two sides share nothing directly. When a document is published, the operator side pushes it to the public side over a one-way ingest channel that only exists on an internal network and is blocked at the edge. Each payload is cryptographically signed and checked with a nonce and an audience value, so the public side only accepts genuine, fresh data and can never call back into the operator system. Every change is written to a tamper-evident audit log built as a hash chain.
Stack and delivery
Python and FastAPI on the back, React 19 with TypeScript, Vite, and Tailwind on the front, PostgreSQL and MinIO for data and files, and Keycloak for OIDC single sign-on. Everything is localized in English and Turkish, packaged with multi-stage Docker images that run as a non-root user, and served behind nginx with TLS. Sessions use httpOnly JWT cookies with CSRF protection and rate limiting, and the build is checked with ruff, mypy, and ESLint.
Questions
Why split it into two separate sides?
So the public internet never touches the operator database or its files. The public side runs on its own network, database, and storage, and only ever receives what has been published, delivered over a signed one-way channel.
What is an eIFU?
Electronic Instructions For Use: the regulated documents a diagnostic product ships with, made available online so customers can look them up by lot number and download the right version in their language.