Skip to content

fwanderlingh/prismatica

Repository files navigation

Prismatica logo

PRISMATICA

An open source review platform,following the PRISMA (Preferred Reporting Items for Systematic reviews and Meta-Analyses) protocol, built with Next.js, React, and TypeScript.

Full information about the PRISMA guidelines can be found at https://www.prisma-statement.org/.

Dashboard

Why Prismatica

Prismatica is designed for teams running evidence reviews that need both speed and auditability:

  • Structured PRISMA workflow from import to export
  • Multi-user collaboration with role-aware controls
  • Server-side state and signed HTTP-only sessions
  • Full-text PDF handling with validation and provenance
  • Configurable review thresholds and conflict handling
  • Audit trail and project-level traceability

Quick Start

1) Install dependencies

npm install

2) Run locally (HTTP)

npm run dev -- --hostname 127.0.0.1 --port 3000

Open http://127.0.0.1:3000.

3) Run locally (HTTPS)

npm run dev:https -- --hostname 127.0.0.1 --port 3000

This uses Next.js experimental local HTTPS support.

Features

  • Dashboard with PRISMA counts, audit trail, and progress indicators
  • Sign-in, optional captcha-protected registration, and server-managed sessions
  • Admin controls for password reset, account deletion, registration policy, and checkout windows
  • Multi-project workspace with per-project navigation
  • Team membership management with owner safeguards
  • RIS and BibTeX import with provenance and review flow
  • Dedup candidate review with side-by-side comparisons
  • Title/abstract screening with append-only decisions, undo route support, and temporary checkout-based queue control
  • Full-text review with PDF upload, validation, streaming, DOI linking, and temporary checkout-based queue control
  • Conflict handling in full-text and extraction phases
  • Extraction templates (text, single-choice, multi-choice)
  • Extraction submissions with temporary checkout-based queue control, consensus routes, and configurable extraction voting
  • Export and report validation endpoints
  • Theme preferences (light, dark, system)
  • Path-based routing and refined UI components

Workflow Overview

  1. Create an account, sign in, and create a review project.
  2. Import records from RIS or BibTeX with batch provenance.
  3. Review deduplication candidates (when present).
  4. Screen title/abstract decisions (include/maybe/exclude).
  5. Advance studies to full-text, upload/validate PDFs, and review outcomes.
  6. Resolve conflicts and advance eligible studies to extraction.
  7. Define extraction templates and collect reviewer submissions.
  8. Build extraction consensus and validate/export reporting output.

Architecture Snapshot

  • Frontend: Next.js App Router + React UI
  • Backend: Next API routes under app/api
  • State: Server-side JSON store with atomic writes
  • Auth: Signed HTTP-only cookies and session checks in server routes
  • Files: Uploaded PDFs stored on disk by default, or in MinIO/S3-compatible object storage

Core modules:

  • lib/serverStore.ts: persistence, business logic, and workflow mutations
  • lib/serverAuth.ts: session and cookie handling
  • lib/serverRoute.ts: route helpers (auth, JSON, file responses)
  • lib/workflow.ts: stage and decision-state progression logic
  • components/prisma-review-app.tsx: main application shell and view orchestration
  • components/prisma-review-ui.tsx: reusable UI presentation components

System Requirements

  • Node.js 20.9 or newer
  • npm

Ubuntu/Debian install example:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

Verify:

node --version
npm --version

Scripts

npm run dev          # Next.js development server
npm run dev:https    # Dev server with experimental HTTPS
npm run build        # Production build
npm run start        # Production server (defaults)
npm run start:prod   # Production server bound to 127.0.0.1:3000
npm run check        # TypeScript type-check

Accounts and Access

No demo reviewer accounts are pre-created.

  • Register the first reviewer from the sign-in page.
  • Create projects and invite members from project settings.

A separate administrator account is seeded on startup by default:

  • Email: admin@prismatica.local
  • Password: change-me-admin

For non-local environments, set PRISMATICA_ADMIN_PASSWORD explicitly.

Server Storage and Sessions

For production, set a stable session secret and move data outside the repo:

Default behavior when PRISMATICA_DATA_FILE is not set:

  • State file: ./data/prismatica-state.json (relative to the project root)
  • PDF folder: ./data/pdfs/

Production example:

export PRISMATICA_SESSION_SECRET="replace-with-a-long-random-string"
export PRISMATICA_DATA_FILE="/var/lib/prismatica/prismatica-state.json"
npm run build
npm run start -- --hostname 0.0.0.0 --port 3000

Optional environment variables:

export PRISMATICA_INVITE_PASSWORD="temporary-password-for-invited-users"
export PRISMATICA_ADMIN_EMAIL="admin@example.com"
export PRISMATICA_ADMIN_PASSWORD="replace-this-default-admin-password"
export PRISMATICA_REGISTRATION_ENABLED="false"
export PRISMATICA_CAPTCHA_SECRET="replace-with-a-long-random-string"
export PRISMATICA_SECURE_COOKIES="true"
export PRISMATICA_USERS_SYNC_POSTGRES="true"
export PRISMATICA_STORAGE_MODE="postgres"
export PRISMATICA_OBJECT_STORAGE_PROVIDER="minio"
export PRISMATICA_S3_ENDPOINT="http://127.0.0.1:9000"
export PRISMATICA_S3_REGION="us-east-1"
export PRISMATICA_S3_BUCKET="prismatica-pdfs"
export PRISMATICA_S3_ACCESS_KEY="minio-access-key"
export PRISMATICA_S3_SECRET_KEY="minio-secret-key"
export PRISMATICA_S3_FORCE_PATH_STYLE="true"

Session Secret Management

  • PRISMATICA_SESSION_SECRET signs session cookies; keep it private and high-entropy.
  • Use a long random value (at least 32 bytes of entropy).
  • Store it in environment variables or a secrets manager, not in git.
  • Use a different secret per environment (development, staging, production).
  • Rotating the secret invalidates all active sessions and requires users to sign in again.

Generate a strong secret:

openssl rand -base64 48

or

node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"

Notes:

  • Use PRISMATICA_SECURE_COOKIES=true only when serving over HTTPS.
  • PRISMATICA_REGISTRATION_ENABLED=false disables public registration for new data files.
  • Uploaded PDFs are stored under a sibling pdfs/ folder near PRISMATICA_DATA_FILE unless PRISMATICA_OBJECT_STORAGE_PROVIDER=minio is enabled.

PDF Object Storage: MinIO

Set PRISMATICA_OBJECT_STORAGE_PROVIDER=minio with the PRISMATICA_S3_* variables above to store new PDF uploads in MinIO or another S3-compatible service. Object keys use:

reports/<project-id>/<report-id>-<sha256>.<extension>

During migration, MinIO mode still reads from the local PDF folder when an object is missing. Disable that fallback after backfill and verification:

export PRISMATICA_PDF_LOCAL_FALLBACK="false"

Backfill existing local PDFs into MinIO:

npm run backfill:pdfs:minio -- --dry-run
npm run backfill:pdfs:minio

The backfill verifies each PDF checksum before upload and updates report storagePath values to the MinIO object key. It works with either JSON state or PRISMATICA_STORAGE_MODE=postgres.

Users And Preferences: PostgreSQL Migration (Incremental)

If you are rebuilding review data from scratch, you can migrate only accounts and auth preferences first.

What this migrates:

  • authSettings.registrationEnabled
  • authSettings.screeningCheckoutWindowMinutes
  • authSettings.extractionCheckoutWindowMinutes
  • users (profile fields, password hash/salt, admin flag, theme)

What this does not migrate:

  • projects, studies, reports, decisions, extraction, events, dedup candidates

Run:

export DATABASE_URL="postgresql://user:password@127.0.0.1:5432/prismatica"
export PRISMATICA_SOURCE_STATE_FILE="./data/prismatica-state.json" # optional
npm run migrate:users:postgres

To keep PostgreSQL users/auth settings updated while the app still uses JSON for review workflows, enable runtime sync:

export PRISMATICA_USERS_SYNC_POSTGRES="true"

When enabled (and DATABASE_URL is set), these mutations sync to PostgreSQL automatically:

  • registration
  • profile updates (including password changes)
  • admin auth-settings updates
  • invited user creation
  • admin users management

Note: when PRISMATICA_STORAGE_MODE=postgres is enabled, full review state is persisted in PostgreSQL relational tables; PRISMATICA_USERS_SYNC_POSTGRES is only needed for the legacy JSON-primary transition mode.

Schema file:

  • db/users_preferences.sql

PostgreSQL As Primary Review State Store

To make PostgreSQL the primary store for review workflow state (projects, studies, reports, decisions, extraction, events), set:

export PRISMATICA_STORAGE_MODE="postgres"
export DATABASE_URL="postgresql://user:password@127.0.0.1:5432/prismatica"

Behavior:

  • Prismatica persists users, auth settings, projects, imports, studies, reports, decisions, extraction state, events, and dedup candidates in PostgreSQL relational tables.
  • If the relational tables are empty on first start, Prismatica can bootstrap from PRISMATICA_DATA_FILE (or default ./data/prismatica-state.json) when available.
  • Legacy app_state_store is read only as a compatibility fallback during transition; new writes target relational tables.
  • After cutover, keep JSON only as backup/export fallback.

Optional: Migrate To Prisma ORM

If desired, PostgreSQL access can later move from custom SQL/state-IO helpers to Prisma ORM.

Possible benefits:

  • Typed schema and generated client
  • Migration history tracking
  • Easier per-entity evolution as the data model grows

Suggested staged approach:

  1. Add Prisma schema and model users, auth_settings, then validate parity.
  2. Expand to review entities (projects, studies, reports, decisions, extraction tables).
  3. Replace app_state_store blob persistence with normalized Prisma-backed tables.
  4. Keep existing API contracts stable during the swap.

This is optional and can be scheduled after the current PostgreSQL + MinIO stabilization.

Network Access Patterns

Local subnet development

npm run dev -- --hostname 0.0.0.0 --port 3000

Then open http://<server-lan-ip>:3000.

If the LAN IP changes, add it in next.config.mjs under allowedDevOrigins and restart the dev server.

Public HTTP access (not recommended for production)

npm run build
npm run start -- --hostname 0.0.0.0 --port 3000

Then open http://<server-hostname-or-ip>:3000.

Recommended Production TLS: Caddy Reverse Proxy

Prismatica is intended to run behind Caddy with Next.js bound to localhost (127.0.0.1:3000).

Deployment assets:

  • deploy/caddy/Caddyfile: IP mode with tls internal
  • deploy/caddy/Caddyfile.letsencrypt: domain mode with public certificates
  • deploy/caddy/prismatica.service: systemd service for the Next.js app

Mode A: IP-only HTTPS (Caddy Internal CA)

Use this when no domain is available.

  1. Edit deploy/caddy/Caddyfile and replace 203.0.113.10 with your server IP.
  2. Activate config:
sudo cp deploy/caddy/Caddyfile /etc/caddy/Caddyfile
sudo systemctl reload caddy
  1. Install and start app service:
sudo cp deploy/caddy/prismatica.service /etc/systemd/system/prismatica.service
sudo systemctl daemon-reload
sudo systemctl enable --now prismatica
  1. Trust Caddy local root certificate on each client:
# On server
sudo cp /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt /tmp/caddy-local-root.crt

Debian/Ubuntu client trust:

sudo cp caddy-local-root.crt /usr/local/share/ca-certificates/caddy-local-root.crt
sudo update-ca-certificates

Fedora/RHEL client trust:

sudo cp caddy-local-root.crt /etc/pki/ca-trust/source/anchors/caddy-local-root.crt
sudo update-ca-trust

Mode B: Domain HTTPS (Let's Encrypt)

Use this for browser-trusted public certificates.

  1. Point DNS A/AAAA records to your server.
  2. Edit deploy/caddy/Caddyfile.letsencrypt and set your domain.
  3. Activate config:
sudo cp deploy/caddy/Caddyfile.letsencrypt /etc/caddy/Caddyfile
sudo systemctl reload caddy

Caddy will automatically request and renew certificates.

Switching TLS modes

# IP-only mode (internal CA)
sudo cp deploy/caddy/Caddyfile /etc/caddy/Caddyfile

# Domain mode (Let's Encrypt)
sudo cp deploy/caddy/Caddyfile.letsencrypt /etc/caddy/Caddyfile

sudo systemctl reload caddy

Production Hardening Checklist

  • Set a strong PRISMATICA_SESSION_SECRET
  • Set a strong PRISMATICA_ADMIN_PASSWORD
  • Enable PRISMATICA_SECURE_COOKIES=true when using HTTPS
  • Keep Next.js behind localhost and reverse proxy through Caddy
  • Restrict filesystem permissions on data and PDF storage
  • Open only required firewall ports (443; optionally 80 for ACME HTTP challenge)
  • Keep Caddy internal CA materials restricted to trusted admins (if using internal CA mode)

Validation and Quality

Run type checks:

npm run check

Create production build:

npm run build

Start production server directly (without reverse proxy):

npm run start -- --hostname 0.0.0.0 --port 3000

For production deployments, prefer the Caddy reverse-proxy pattern above.

About

Open source PRISMA review platform website, supporting the full process from BibTex/RIS import, to deduplication, abstract and full-text screening, conflict arbitration and data extraction.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors