Projects07 of 15
Winnow
A free, self-hostable platform for systematic reviews
Why it exists
The tools a research group needs to run a systematic review are commercial and closed, and unpublished review data has to be uploaded to them. Winnow is the whole pipeline instead: free, open source, and running on a server the lab owns.
From search results to a PRISMA diagram
- Import. Twenty search exports at once, in RIS, PubMed MEDLINE and XML, BibTeX, EndNote XML, Zotero RDF or CSV.
- Deduplicate. Automatically, with the uncertain pairs shown side by side for a person to decide.
- Screen. Keyboard-first, blind or open, by two reviewers, with conflict resolution.
- Full texts. Uploaded, or fetched from Unpaywall and PubMed Central, and virus-scanned before anyone opens them.
- Extract. Versioned extraction forms, with dual extraction and a consensus step.
- Risk of bias. RoB 2, ROBINS-I, Newcastle–Ottawa or QUADAS-2, with traffic-light plots.
- Report. The PRISMA 2020 flow diagram, Cohen’s and Fleiss’ kappa, a methods paragraph to paste, and a backup that restores anywhere.
Ranking, kept optional
A relevance model retrains from each reviewer’s own decisions, puts the likely includes first, and estimates when stopping is defensible. The suggestions are optional, because a review that cannot say why a record was excluded is not a review.
Security on the server
Security is server-side or it does not count.
- Every query is checked against review membership, and a non-member gets a 404.
- PostgreSQL row-level security sits behind that as a second line.
- Blind mode is enforced in the database, not hidden in the interface.
- Argon2id passwords, two-factor sign-in, account lockout, Google and ORCID sign-in, and an append-only audit log.
- An OWASP ZAP baseline scan runs in CI, with no high-risk findings.
Budgets first, then measured
Every performance number was written as a budget first, then measured on reviews of 100,000 records.
| Measure | Budget | Measured |
|---|---|---|
| Screening, 95th percentile | 80 ms | 32–69 ms |
| Record list, across 15 filters, sorts and searches | 150 ms | 12–64 ms |
| Import of 100,000 records | 60 s | 49 s |
| Deduplication of 50,000 records | 30 s | 13 s |
| Page load on 4G (largest contentful paint) | 1.5 s | 0.7 s |
Under load, 50 reviewers deciding every three seconds for ten minutes gave a 95th percentile of 37 ms, with 0 errors in 19,920 requests.
Quality
- WCAG 2.2 AA, with zero serious or critical axe findings across 43 pages, four screen sizes and both themes.
- 900 backend tests at 95% coverage, Playwright end-to-end tests, mypy —strict and strict TypeScript, with CI on every push.
- One command brings up the production stack, with automatic HTTPS, encrypted nightly backups and a restore test that CI runs monthly.
Status
Not live yet, for an honest reason: Winnow runs its own database, background worker and virus scanner, so it needs a paid server rather than free static hosting. It goes up at winnow.sandhiresearch.org for SANDHI Research Lab once that server is in place. Until then, the Winnow page says what it does.
Built with
FastAPI, PostgreSQL, Redis, React, TypeScript, Docker and Caddy. Specified as a ten-phase plan with acceptance criteria for each phase, and built with AI coding agents against those gates, over about 150 commits.