actaria is an open-source scholarly journal publishing platform: diamond open access, first-class open peer review, LaTeX-only submissions, and multi-tenant from day one.
See docs/superpowers/specs/ for design specs and docs/superpowers/plans/
for implementation plans.
See development status for the current release review, verification results, and remaining Phase 1 work. The release-readiness audit maps the original done criteria to current evidence and outstanding operator/provider acceptance.
Readers can use Search in a journal's navigation to find current articles,
preprints and published review reports by title, abstract or keyword. Quoted
phrases, OR and excluded terms (-term) are supported. Results use English
word stemming and relevance ranking, with title matches weighted most strongly.
Search follows the reader's publication/status rules and never searches private
manuscripts or review provenance. Apply migrations when upgrading: publications
migration 0012 adds the PostgreSQL full-text GIN index, maintained automatically
as publication metadata changes.
The quickstart below is for development. For the separate production images, private credentials, HTTPS proxy and deployment validation, see production deployment. The backup and recovery guide covers consistent snapshots, off-site transfer, empty-target restore and delivery reconciliation.
Everything runs under Docker Compose: Postgres, Redis, MinIO, Django web, the RQ worker, and lightweight compile, Crossref, account-email and journal-email recovery services.
# First time, or after Dockerfile / dependency changes.
docker compose build
# Start the application, storage, worker and recovery services.
docker compose up -d
# Idempotent dev seed: migrations, license fixture, MinIO bucket, superuser,
# JOAS journal, sections, and manager role.
./scripts/init-joas-test.sh
# Build the Inertia/React bundle served by Django.
npm install
npm run buildAfter dependency rebuilds, recreate the affected application services with
docker compose up -d --force-recreate --renew-anon-volumes <service> ... so their
anonymous /opt/venv volumes receive the rebuilt dependencies. Compose otherwise
preserves those volumes across image updates. Reinstall Playwright browsers and
system dependencies when replacing the web container's test runtime.
Log in at http://localhost:8760/auth/login/:
- Email:
root@actaria.local - Password:
actaria
Change the password before exposing the instance anywhere:
docker compose exec web uv run python manage.py changepassword root@actaria.localIf you are on a remote host over SSH, forward the port first:
ssh -L 8760:localhost:8760 <host>After running ./scripts/init-joas-test.sh:
| URL | Purpose |
|---|---|
/ |
Platform landing page listing configured journals |
/admin/ |
Django admin, superuser only |
/auth/login/ |
Email/password login |
/auth/signup/ |
Email-first signup and verification |
/auth/password-reset/ |
Request a password recovery email |
/j/joas/ |
JOAS journal home |
/j/joas/submit/ |
Author submission wizard |
/j/joas/my-submissions/ |
Author submission list |
/j/joas/office/ |
Editorial office dashboard |
/j/joas/preprints/ |
Public preprint archive |
/j/joas/preprint/<number>/ |
Public preprint detail |
/j/joas/articles/ |
Public article index |
/j/joas/article/<article-number>/ |
Public article detail |
/healthz |
Process liveness without dependency access |
/readyz |
Database, Redis and private storage readiness |
The /j/<slug>/ prefix is configurable with ACTARIA_JOURNAL_PATH_PREFIX.
# Logs and service state.
docker compose logs -f web
docker compose ps
# Stop services. Data persists under ./data/.
docker compose down
# Stop services and remove the /opt/venv named volume.
docker compose down -v
# Rebuild the frontend bundle after editing resources/js or resources/css.
npm run build
# Vite dev server with HMR at http://localhost:5173/.
npm run dev
# TypeScript check.
npm run typecheckManual wizard test zip:
uv run scripts/build-example-zip.pyThis writes example.zip containing main.tex, references, and a figure.
# Python unit/integration tests.
uv run pytest
# Browser UI tests.
uv run pytest tests/playwright/
# Docker integration tests, including real TeX Live compile cases.
uv run pytest -m dockerPlaywright requires Chromium in the runtime where tests run:
uv run playwright install chromiumWhen services are already running, container execution is closest to the web runtime:
docker compose exec web uv run --frozen pytest
docker compose exec web uv run --frozen pytest tests/playwright/
# Real Docker/TeX tests use the compile worker's socket and scratch mount.
docker compose exec worker uv run --frozen pytest -m dockerThe web service has no Docker socket. Run real compile integration tests in the worker, and run suites using the same test database sequentially.
CI measures application code, excluding tests and migrations, and requires 100% line coverage for permission modules and the workflow service/transition graph. Run the same coverage gate locally with:
docker compose exec web uv run --frozen pytest --cov=apps --cov-report=term-missing
docker compose exec web uv run --frozen coverage report --include='apps/*/permissions.py,apps/workflow/service.py,apps/workflow/stages.py' --fail-under=100The overall release target remains 95%; current measured results and outstanding release work are tracked in Development status.
Contributor roles and ROR affiliation lookup are documented in
Contributor metadata and ROR. Optional
ROR_CLIENT_ID identifies this installation to the organisation directory.
Manual affiliation entry remains available when directory lookup fails.
.envis gitignored. Copy.env.exampleon first setup if you need local overrides.- Key variables:
SECRET_KEY,DATABASE_URL,REDIS_URL,S3_ENDPOINT,S3_BUCKET,S3_ACCESS_KEY,S3_SECRET_KEY,ORCID_CLIENT_ID,ORCID_CLIENT_SECRET,ACTARIA_JOURNAL_PATH_PREFIX,ACTARIA_BASE_URL,CSRF_TRUSTED_ORIGINS, andACTARIA_DATA_DIR. docker-compose.ymloverrides database, Redis, and S3 endpoints inside the Compose network.
When DEBUG=false, actaria refuses to start unless SECRET_KEY is a
high-entropy value of at least 50 characters and ALLOWED_HOSTS contains
explicit hostnames without the unrestricted * wildcard. Generate a key with:
uv run python -c "import secrets; print(secrets.token_urlsafe(64))"Set that value and the production hostnames in the deployment environment before starting web, worker, or recovery processes.
Signup verification, contact verification and password recovery use durable
account-email requests and the email worker.
See account recovery operations for the trusted
link origin, rate limits, recovery scheduler and operator diagnostics. Personal
profiles verify contact addresses and manage ORCID connections at the configured
platform origin. Reviewer invitations and existing editorial notifications use
a tenant-scoped durable outbox with explicit resends for uncertain delivery.
Submission participants can use private shared discussions and separate editorial
notes, with attachment downloads and retained edit history. See
discussion operations for audiences, participant access,
reviewer identity handling and retention.
Authors and authorized editors can inspect private upload generations, compile logs and retained PDFs in Source history. See source-history operations for archive retention, released-source copies and the current-source backfill command for existing installs.
Public article, preprint and review-report pages offer version-specific BibTeX, RIS and EndNote downloads. See citation exports for metadata, privacy, custom domains and format behavior.
See journal email operations for recovery, permissions and legacy credential redaction. Managers choose initial submission-notification recipients under Office → Configurations → Email; none are selected automatically.
Configure SMTP_HOST, SMTP_PORT, SMTP_USER, and SMTP_PASSWORD for
reviewer invitations and editorial decisions. For port 587, set
SMTP_USE_TLS=true; for implicit TLS on port 465, use SMTP_USE_SSL=true
instead. Set DEFAULT_FROM_EMAIL to a sender accepted by your mail server;
a journal's configured From address overrides this fallback.
The equivalent Django variables (EMAIL_HOST, EMAIL_PORT,
EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_USE_TLS, EMAIL_USE_SSL)
take precedence over the SMTP_* aliases. EMAIL_TIMEOUT defaults to 30
seconds. Restart web and worker processes after changing configuration.
For local development, EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
prints messages to process logs. Use the SMTP backend for actual delivery.
| Service | Container port | Host port | Notes |
|---|---|---|---|
| web | 8760 | 8760 | Django |
| postgres | 5432 | 6432 | Localhost-only; avoids host Postgres collisions |
| redis | 6379 | 6379 | Localhost-only queue/cache |
| minio | 9000 / 9001 | 9000 / 9001 | Localhost-only API / console |
The host ports are configurable with POSTGRES_PORT, REDIS_PORT,
MINIO_PORT, and MINIO_CONSOLE_PORT. Development credentials can be
overridden with POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB,
S3_ACCESS_KEY, and S3_SECRET_KEY.
Stateful services bind-mount under ./data/ by default:
./data/postgres
./data/redis
./data/minio
Set ACTARIA_DATA_DIR to keep data elsewhere. To wipe local dev data:
docker compose down
rm -rf data/The worker uses Docker-out-of-Docker: actaria-worker mounts the host Docker
socket and starts sibling TeX Live containers for compile jobs. The scratch
directory must exist on the host and be writable by UID 1000:
mkdir -p /tmp/actaria-compileImportant compile knobs:
| Env var | Default | Notes |
|---|---|---|
ACTARIA_TEXLIVE_IMAGE |
texlive/texlive:latest |
TeX Live image |
ACTARIA_COMPILE_MEMORY |
2g |
Per-compile memory cap |
ACTARIA_COMPILE_CPUS |
1 |
Per-compile CPU cap |
ACTARIA_COMPILE_TIMEOUT |
60 |
latexmk wall-clock timeout in seconds |
ACTARIA_COMPILE_TMPFS_SIZE |
512m |
/tmp inside sandbox |
ACTARIA_COMPILE_USER |
1000:1000 |
UID/GID inside sandbox |
ACTARIA_COMPILE_LOG_CAP |
262144 |
Retained compile-log bytes |
ACTARIA_COMPILE_PDF_CAP |
104857600 |
Maximum generated PDF bytes |
ACTARIA_COMPILE_FILE_CAP |
209715200 |
Kernel-enforced maximum bytes per sandbox file |
ACTARIA_COMPILE_WORKDIR_CAP |
536870912 |
Hard /work tmpfs byte cap |
ACTARIA_COMPILE_STALE_SECONDS |
300 |
Age at which a running job is recoverable |
ACTARIA_COMPILE_RECOVERY_INTERVAL |
60 |
Seconds between automatic recovery passes |
Output collection closes its pipes and reaps the Docker client on both success and failure. Timeouts, output-limit errors, logging failures and worker cancellation also attempt to stop the named sibling container. That cleanup command is limited to ten seconds; Docker cleanup failure is logged without replacing the original compile error. The sandbox's own timeout and resource limits remain in force. Configured log caps also hold for very small values.
The compile-recovery Compose service runs stale-job recovery automatically.
For an immediate one-off pass:
docker compose exec compile-recovery python manage.py recover_compile_jobsSandbox invariants are pinned by tests/test_sandbox_invariants.py: no
network, read-only root filesystem and source bind, a size-capped tmpfs working
directory, per-file resource limits, non-root user, and
latexmk -no-shell-escape. The final PDF is size-checked inside the sandbox
and streamed to the worker; TeX receives no writable host bind.
- Manuscript zip: <= 20 MB compressed, <= 200 MB uncompressed, <= 500 entries.
- Supplementary files: 20 MB each, 100 MB total per submission.
- Output PDF: <= 100 MB.
- PDFs and source artifacts are served through Django proxy views, not public presigned object-storage URLs.
- Python dependencies are managed by
uv. - Frontend source lives under
resources/js/; Django serves the built bundle fromstatic/dist/. - Always run
npm run buildafter editing frontend source before relying on browser behavior through Django. - Pre-commit hooks run
ruff, formatting, large-file checks, and the journal isolation-test gate. Enable them withuv run pre-commit install.
After upgrading an existing installation, apply migrations and run
docker compose exec web uv run --frozen python manage.py snapshot_publications --apply
to preserve existing public files and author metadata before reopening editorial
access. New publications capture snapshots automatically. See
publication snapshots and corrections for
the dry run, recovery behavior, and version URLs.
Configure the journal's DOI prefix and versioning policy in Office →
Configurations → Identifiers. Production can reserve an identifier; publication
also allocates one when configured. Reservations preserve version associations
and remain distinct from confirmed registration. Crossref XML rendering, durable
deposit attempts, editorial preview/submission controls and provider confirmation
are implemented. Operators can enable automatic processing for future releases;
the crossref-recovery service recovers queued work and checks provider results.
Editors can explicitly associate imported DOIs with released versions while
preserving their values and registration evidence. Released contributor names
can be clarified with an immutable history to complete registration metadata.
Retraction and withdrawal notices have independent DOIs and validated Crossmark
updates; they wait for confirmation of the affected DOIs before submission.
A provisioned Crossref test-account exercise remains a release requirement.
See DOI operations
for policy behavior and handling of legacy identifiers.