Research software for meta-analysis: semi-automated effect-size extraction from academic PDFs with a vendor-neutral large-language-model adapter, human-in-the-loop verification by the principal investigator, and an immutable data-lock workflow that exports a reproducible effect-size dataset for three-level meta-analytic regression.
Authors
Built to support the P6 (meta-analysis) component of the first author’s doctoral dissertation on the internationalization-performance relationship.
Scope: which kinds of literature review this serves. M-AIDA is an extraction-and-verification engine at the data-collection stage of PRISMA; it does not search the literature, does not screen records, and does not run the final statistical model. It serves a meta-analysis in full (its design target), the data-extraction stage of a systematic review (evidence-gated coding, recorded exclusion reasons, two independent coders), and small-scale evidence tables that ground the hypotheses of a proposal. It is of partial use for scoping reviews, marginal use for narrative reviews, and no use for bibliometric analysis, which is a different class of tool.
frontend (React 19, :3000)
calls --> backend (FastAPI, :8765)
|-- extractor.py vendor-neutral LLM parsing
|-- engines.py provider adapter (LLM_PROVIDER / LLM_API_KEY / LLM_MODEL)
|-- models.py Pydantic domain models
|-- notion_sync.py optional Notion database sync
The language model is reached through a configurable adapter. Set LLM_PROVIDER,
LLM_API_KEY and LLM_MODEL to your own provider; the software is not tied to any
single vendor.
# 1. Configure environment
cp backend/.env.example backend/.env
# Edit backend/.env: LLM_PROVIDER, LLM_API_KEY, LLM_MODEL, NOTION_TOKEN, NOTION_DATABASE_ID
# 2. Start with Docker Compose
docker compose up
# 3. Open the app
open http://localhost:3000
Extracting, verifying, locking, and Notion sync all require an admin key
(X-MAIDA-Admin-Key), so a visitor can never mutate studies through the API
alone. MAIDA_ADMIN_KEY is unset above on purpose for a fast local start: the
backend generates one and prints it to the console on every startup instead.
Paste that value into the “Admin key” field in the app header once per
browser (kept only in localStorage, never in the built JS). Set
MAIDA_ADMIN_KEY in backend/.env for a key that survives a restart, and
always set it before a real deployment - see Production deployment below.
For demonstrations (e.g. a thesis defense) the repository ships a packaging harness that starts the real backend pre-seeded with real effect-size records from the dissertation’s locked P6 database and serves a dependency-free web console at the same port. No response is simulated; every action goes through the live API.
pip install -r backend/requirements.txt
python demo/run_defense.py
# Windows one-click alternative: demo\\start_defense_windows.bat
# macOS/Linux alternative: sh demo/start_defense_unix.sh
# open http://localhost:8765/ (interactive API docs at /docs)
Seeding rules and options (full-database seed, lock-all mode) are documented in
demo/run_defense.py; a Vietnamese walkthrough for the defense session is in
demo/HUONG_DAN_BAO_VE.md. The Defense App persists session changes locally, protects all mutations with a
presenter PIN printed at startup, and can reset to the verified P6 seed. Live PDF
extraction additionally requires LLM_API_KEY in backend/.env; without it the
extraction endpoint returns an explicit 503 and verification, locking, filtering,
reset, and CSV export continue to work offline.
To run the app for real (single host / VPS, prebuilt GHCR images, or a managed
host) see DEPLOY.md: docker-compose.prod.yml,
backend/.env.production.example, and a GHCR image-build workflow are provided.
The staged plan toward a commercial SaaS (PostgreSQL, auth, billing) is in
KE_HOACH_TRIEN_KHAI_APP_vi.md in the dissertation repository.
# Backend unit tests (effect-size conversions + confidence scheme)
cd backend
pip install -e ".[test]"
pytest -q
# Independent-validation analysis tests (synthetic fixtures only)
cd ..
python -m pytest -q validation/tests
# Frontend (Vite): dev server / production build
cd frontend
npm ci
npm run dev # http://localhost:3000
npm run build # outputs to build/
CI runs the backend test suite and the frontend Vite build on every change.
Set VITE_API_URL (see frontend/.env.example) to point the client at a
non-default backend URL.
The executable independent-validation package is in validation/,
with the preregister-before-running design in
VALIDATION_PROTOCOL.md. Its templates separate two
human coders, the adjudicated gold standard, untouched machine proposals, and
PI verification time. No product-accuracy claim is made until real frozen
inputs and generated results are archived; synthetic CI fixtures only verify
the metric calculations.
Execution status: the repository now includes a deterministic provisional
sampling frame of 40 PRIMARY studies plus 10 RESERVE studies in
validation/sampling/. Defense-demo studies and every
study flagged is_estimated in the P6 database are excluded. The frame is not
locked until full-text availability and non-use in M-AIDA development are
confirmed for every PRIMARY study; the freeze command enforces both gates.
| Method | Path | Description | Admin key? |
|---|---|---|---|
| POST | /api/extract |
Base64 PDF body to an extracted effect size | required |
| POST | /api/extract/upload |
Multipart PDF upload to an extracted effect size | required |
| GET | /api/studies |
List studies (filter: icrv, dpl, verified, locked) | - |
| GET | /api/studies/{id} |
Single study detail | - |
| PATCH | /api/studies/{id}/verify |
PI field overrides and approval | required |
| POST | /api/studies/{id}/lock |
Irreversible PI data lock | required |
| GET | /api/studies/export/csv |
Export locked studies as CSV | - |
| POST | /api/notion/sync |
Push locked studies to Notion | required |
| GET | /api/health |
Health check and service configuration flags | - |
“Admin key” means the request must carry X-MAIDA-Admin-Key: <MAIDA_ADMIN_KEY>
or the backend refuses it with 401, whatever the caller’s origin - see
Security below. In demo mode (demo/run_defense.py) this check stands
down in favour of that app’s own presenter-PIN middleware.
Interactive diagram of the extract → verify → lock path: assets/diagrams/maida-workflow.html (open locally in a browser) (source: assets/diagrams/maida-workflow.workflow.json, rendered with Archify, MIT).
PDF_TEXT_LIMIT); when a
paper is longer the record carries text_truncated = true, so an empty proposal
can be told apart from a paper that reports no statistic.metric_type, estimand_source, and source_controls, so beta-derived values
enter sensitivity analysis only, and a three-level confidence score is attached.evidence_page/evidence_quote,
n_evidence_page/n_evidence_quote). Missing evidence raises HTTP 422 and no
record is stored: the system has no default or fallback output path for any
input.PI_EDITABLE_FIELDS, 7.2.0); a change to any
primary statistic re-derives r, the variances (variance_r, variance_z),
metric_type and the provenance fields through the same function live
extraction uses. The machine’s proposal, its confidence score and the evidence
quotes are never editable; human edits are logged in pi_edited_fields.pi_locked
and locked_at cannot be set by any other route. Only locked records enter the
analysis export, which carries every field of the record.analysis/)The analysis/ package is the canonical, self-tested implementation
of the conversion layer (effect_size.py with hand-computed unit tests, plus an
R twin effect_size.R feeding the metafor pipeline). migrate_v8.py derives a
new lock generation from a released dataset without ever editing it: v7.1.1
(DOI-pinned) stays immutable, every derived record carries a derived_from
pointer, and excluded records keep a written reason (PRISMA-ready). Each run
emits figures.json: the single source every display surface reads its
headline numbers from. Policy details are in
analysis/README.md.
If you use M-AIDA, please cite it (GitHub renders a “Cite this repository” button
from CITATION.cff):
Do, T. H., and Phan, A. T. (2026). M-AIDA: Meta-Analysis Intelligent Data Assistant (Version 7.2.2) [Computer software]. Can Tho University. https://doi.org/10.5281/zenodo.21850575
Zenodo mints two kinds of identifier. The concept DOI
10.5281/zenodo.21850575 always resolves to the latest release; cite it for the
software in general. A version DOI pins one release, for an exact
reproducible build: 10.5281/zenodo.22920619 for v7.2.2 (tag v7.2.2, commit
8af4881, the current release), 10.5281/zenodo.22260059 for v7.2.1 (tag
v7.2.1, commit d2ea8e3), 10.5281/zenodo.22259090 for v7.2.0 (tag
v7.2.0, commit 3ff42c4, the first release after the 31 August 2026 code
review), 10.5281/zenodo.21926336 for v7.1.1 and 10.5281/zenodo.21850576 for
v7.1.2.
A separate Zenodo deposit of v7.1.1, made by hand on 9 July 2026
(concept 10.5281/zenodo.21282516, version 10.5281/zenodo.21282517), also
remains published. It is the record cited by the first author’s dissertation and
by the copyright-registration dossier, and it always resolves to v7.1.1. It is
not part of the GitHub-archived series above, so it never advances to a newer
release; new citations of the software as a whole should use
10.5281/zenodo.21850575.
Three Zenodo records minted on 3 September 2026 are superseded and must not be
cited, because the GitHub releases behind them carried tags pointing at
earlier commits than the release title claimed: 10.5281/zenodo.22258783 and
10.5281/zenodo.22258977 (from a release titled v.7.2.0, archiving the
unpatched commit 3c8de32, and carrying the metadata version 7.1.1) and
10.5281/zenodo.22259684 (from a release titled v7.2.1, archiving the 7.2.0
commit 3ff42c4). The authors have asked Zenodo to withdraw them.
A fourth record, 10.5281/zenodo.22920581 (23 September 2026), is a
duplicate of v7.2.2: the GitHub release was first published under the
mistyped tag V7.2.2 and then re-tagged v7.2.2, and Zenodo archived both.
It holds the same commit 8af4881, so its content is correct, but cite
10.5281/zenodo.22920619 so that every reference points at one record.
Authors and copyright holders: Do Thuy Huong and Phan Anh Tu, School of Economics, Can Tho University. Copyright subsists automatically under Vietnamese law and the Berne Convention from the moment of creation; a Copyright Office of Viet Nam registration is being prepared with Can Tho University as a co-owner under the university’s intellectual-property regulations.
Role of computational assistance: M-AIDA uses a configurable language-model provider only to propose candidate effect sizes and statistical conversions from study text. It is a human-in-the-loop tool: every proposed value must be independently verified, corrected if needed, and permanently locked by the principal investigator before it enters the analysis database. The provider does not select studies, decide eligibility, run the meta-analysis, write interpretive content, or hold authorship or ownership over the software. Scientific responsibility remains with the named human authors.
Security: copy backend/.env.example to backend/.env and supply your own keys;
never commit a real .env (it is git-ignored). In the recommended deployment
(DEPLOY.md), nginx is the only published service and proxies every /api/
request straight to the backend; without a check there, any site visitor
could call the same mutating routes the UI uses. Every extract/verify/lock/
Notion-sync request (7.2.2) is therefore gated on the X-MAIDA-Admin-Key
header, checked against MAIDA_ADMIN_KEY (backend/main.py:admin_key_guard).
Read-only routes (list/get studies, CSV export, health) stay public, since
they serve the published, locked dataset this project exists to make
transparent. Set MAIDA_ADMIN_KEY explicitly in production; left unset, the
backend still starts but generates and logs a new key on every restart. This
is single-shared-secret protection, appropriate for one PI’s own deployment -
see Production hardening still on the roadmap in DEPLOY.md for the
per-user auth planned before any multi-tenant or paid use.
M-AIDA is free/open-source software under the GNU Affero General Public License
v3.0 (AGPL-3.0-only), see LICENSE. The AGPL’s Section 13 covers
network use: running a modified version as a service requires publishing that
version’s source.
Using M-AIDA under the AGPL requires no contact and no fee.
Commercial licensing is not currently available. Granting terms other than
the AGPL requires holding, or being authorised by all co-holders to grant, the
economic rights in the work. Those rights are not yet formally settled (see the
next section), so no such grant can be made today. The position is stated in
full in COMMERCIAL-LICENSE.md.
AGPL-3.0-only supersedes the earlier “M-AIDA Academic Source-Available License
v1.0”, retired on 4 August 2026. Any document still carrying that name is out of
date; LICENSE in this repository is the operative text.
Economic rights in M-AIDA are held jointly by Can Tho University and the two authors, under Article 71 of the university’s science and technology management regulation (Decision 5152/QD-DHCT of 6 October 2023). The copyright registration is filed through the university and is still in process.
Because of that, the Zenodo deposits (the GitHub-archived series at 10.5281/zenodo.21850575 and the manual v7.1.1 deposit at 10.5281/zenodo.21282516) keep their files under restricted access while the records themselves, their metadata and their DOIs stay public and citable. This does not conflict with the AGPL: the AGPL governs what a recipient of the software may do with it, and obliges the authors to supply corresponding source to those recipients. It does not oblige anyone to publish files in any particular archive. The complete source is public in this repository, so the AGPL grant is fully effective today.
When the registration completes, opening the deposit is a decision for the joint owners, not for either author alone.