Full-stack developer in Catania. Most of what I build ends up in a clinic, a radiology archive, or somebody's back office. In places like those, being approximately right is worse than being obviously wrong, because nobody notices.
I reconstruct that work here, from scratch, so there is something to open and run. Not to show that it runs: to show what it took to be sure it was right. What carries over is the shape of the problem; the code is newly written and the data invented. Not all of it: two projects are mine from the start, and one is a fork of the open-source viewer its original was built on. The note at the bottom says which.
That is the one thing these have in common, and it is the point of them. Each repository opens with a sentence that could be wrong, and each has a command that goes red if it becomes wrong. That command is a measurement, not a badge.
Orders rebuilt from a folder of email, read by rules or by a language model.
A value has to point at the words it was read from. A rule knows where it matched. A model is asked for the text it read and never for an offset, because asked for a character offset it will give you a plausible integer. Every quote it gives back is searched for in the message, and what it could not have read is dropped rather than stored with a confidence beside it. Anthropic, Mistral or OpenAI, chosen on the first screen: the checking is the same for all three, because it is about the contract and not about whose model honours it, and
npm testruns each of them with the network stubbed out.
Questions about a set of manuals, answered two ways side by side.
A vector search is the wrong tool for a large share of what people ask a manual, and it fails confidently, with a citation. Twelve questions with a known answer, judged on the first result only: similarity alone gets 6 right, looking at the kind of question first gets 9. The difference is all in two places, codes like
E-4412that have no semantic neighbours and questions phrased in the document's own words, and the run fails if any question plain similarity got right is traded away. Where the question's words are not the document's, both score zero, and the page says so.
A job that deletes medical images it cannot get back.
A dry run and a real run choose the same studies. Give the dry run its own branch, the way it usually gets one, and it failed to mention 9 of the 255 studies it was about to delete.
Nothing is deleted because the record system said nothing. An empty result set is an ordinary return value, so it falls through to whatever the last line of the function happens to be. That cost 23 patients' studies, on a run where nothing errored and every total looked plausible.
When the second of two deletions fails, the next run can finish it. Removing the catalogue row first leaves 25 folders that nothing will ever look for again. Same failure, same frequency, and one of them is permanent.
A form is authored as a tree and asked about as a table.
The same 120 submissions, stored three ways, asked the same eight questions. Not speed: whether the answer is right, and whether a wrong answer announces itself. A pile of JSON documents is quietly wrong three times and cannot express three of the questions at all. Flattening fixes all of them but the rename, which needs an id, and that is the whole finding.
A portal where patients read their own reports, and only their own.
Four routes that begin identically: read the signed-in patient from the session, load them, write them into the audit line. Two then put that patient into the question asked of the archive and two do not, and reading the four methods will not tell you which. Over 90 questions, the two that do not hand over 70 documents belonging to somebody else, and write 70 audit lines saying those documents were handed to their owner.
The repair is not four checks. A check is a line that can be absent, and this is a demonstration that an absent line is invisible. The archive has no method that takes a document identifier on its own, so the wrong version does not fail review: it fails to compile.
Analytics over an archive whose schema you do not own and that differs at every installation.
Six installations holding the same studies. The side that reads the schema first gets every question right on all six. The side with the SQL written straight gets 7 answers wrong with nothing to show for it. They are not errors but numbers, four times too high, because a one-to-many join took the storage with it.
My own
a page builder and CMS, on Rails and React · GPS audio guides for Sicilian cities, live at walkaround.cloud
Medical imaging
DICOM viewer, web · DICOM viewer, desktop · archive analytics · archive maintenance
Healthcare, patient-facing
multi-tenant booking · a booking agent that knows when to hand over · reports, to the patient they belong to
Documents
OCR as an internal service · questions about a document set · rebuilding an order from a folder of email, with rules or a language model · forms as a relational schema
Desktop and devices
teaching somebody a Windows application · printer meters over SNMP · deciding from pixels whether anybody is logged in
The rest
campaigns that cannot write to somebody who said stop · booking a boat in a system the website does not own, at a price the browser cannot set · a TOTP authenticator
Where a standard was the interesting part, it is implemented rather than
installed. SMTP is spoken by hand, one line at a time, so the conversation is
visible. SNMP is decoded from ASN.1/BER on the standard Printer MIB, not
through a vendor's own interface. MIME is parsed with its own byte counts
because a {n} in IMAP is bytes and not characters, and getting that wrong
gives you mojibake and no error. DICOM dates are VARCHAR(8) and sort
lexicographically, which is the one gift that format gives you.
The Node projects have no runtime dependencies at all and no build step. The
imports look like node:sqlite, node:http and node:fs, and what Node runs
is the TypeScript itself, with erasableSyntaxOnly set so the type check is
also the proof that they still run without one. The C# ones carry no packages
beyond the test runner, and the PHP one carries none beyond it either.
Three of them also make an argument about types rather than checks. A document archive with no method that takes an identifier on its own; a booking that takes a quote reference and has nowhere to put a price; a receipt for a second factor whose constructor is internal, so a page cannot decide on its own that a code was verified. In each case the dangerous version is not guarded. It cannot be written at all, and a test asserts that by reflection so it stays that way.
TypeScript · Node.js · C# · .NET 9 · ASP.NET Core · WPF · PHP ·
WordPress · Angular · React · Electron · Python · FastAPI ·
LangGraph · Anthropic, Mistral and OpenAI APIs · Ruby on Rails · Ruby ·
PostgreSQL · SQL Server · SQLite · Docker
Most projects here are based on a real production system I designed or developed. The originals stay in private repositories: confidentiality and intellectual property constraints mean none of them can be published.
Those repositories are reconstructions. Each was rebuilt from scratch so it could be shown and run, preserving the core architecture, the workflows and the technical challenges of the production solution, with newly written code and fictional data. No proprietary source code, confidential data or client assets from an original are included in any of them. What the data describes is invented in the repository itself: no clinic, no patient, no real archive, no customer list.
One is not a reconstruction: the web DICOM viewer is an independent version built on the same open-source base as its original, OHIF, at the same version, and it reads real studies from public research collections, cited with their licences. Its original stays with the client and is not there either.
Two are mine from the start, with no client and no original: Page Builder CMS and Walk Around. Their repositories are the projects themselves, except that Walk Around's leaves out the audio guides, which are the product.
Each README says what the original did, what the reconstruction does differently, and why.
The limits are in the READMEs too, in their own section, and they are real ones. A portfolio piece without them is a brochure.
Write to me: [email protected].