Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
94999b0
build: update CI/CD workflows and deployment scripts (#94)
NishaSharma14 Feb 16, 2026
21a59c4
feat: improve prediction (#93)
hamed-musallam Feb 17, 2026
ea9b602
fix: identation issue in dev-build.yml
NishaSharma14 Feb 17, 2026
d7a3489
Merge branch 'development' of https://github.com/NFDI4Chem/nmrkit int…
NishaSharma14 Feb 17, 2026
78277ee
chore: update nmr-cli package-lock.json (#97)
hamed-musallam Feb 17, 2026
90cf1bb
Fix playwright version in package.json
vcnainala Feb 17, 2026
93293a2
build: remove the cache from the build workflow
NishaSharma14 Feb 17, 2026
b1bec0a
Merge branch 'development' of https://github.com/NFDI4Chem/nmrkit int…
NishaSharma14 Feb 17, 2026
be5b6d4
feat: exposed publication string endpoint with swagger docs updates (…
vcnainala Feb 17, 2026
9aaa0c3
fix: dpeloy script error
NishaSharma14 Feb 18, 2026
e989ce5
Merge branch 'development' of https://github.com/NFDI4Chem/nmrkit int…
NishaSharma14 Feb 18, 2026
060a27e
feat: peaks to nmrium endpoint (#100)
vcnainala Feb 18, 2026
7fda5e7
fix: remove app volume mount and add the caching for docker build
NishaSharma14 Feb 18, 2026
5d89678
Merge branch 'development' of https://github.com/NFDI4Chem/nmrkit int…
NishaSharma14 Feb 18, 2026
c11c927
fix: stream serialization of large NMRium state objects (#101)
hamed-musallam Feb 18, 2026
ff93b1e
fix: improve error handling for spectra snapshot capture (#103)
hamed-musallam Feb 19, 2026
90af982
feat: update nmr-cli to replace 'chromium' with 'firefox' for spectr…
hamed-musallam Feb 19, 2026
2bff4aa
refactor(nmr-cli): capture errors using fiflogger (#106)
hamed-musallam Feb 23, 2026
324dd83
refactor: restructure parse spectra response and improve logging (#107)
hamed-musallam Feb 25, 2026
f3f21e6
feat: add from/to spectrum range options to peaks-to-nmrium endpoint
hamed-musallam Feb 26, 2026
9efef89
feat(nmr-cli): update NMRium core packages (#109)
hamed-musallam Mar 10, 2026
4c5881a
fix: numpy version to <2 to resolve compatibility issues (#117)
NishaSharma14 Jul 22, 2026
b46e3b8
Merge branch 'main' of https://github.com/NFDI4Chem/nmrkit into devel…
NishaSharma14 Jul 22, 2026
3d4ad3f
Merge branch 'development' of https://github.com/NFDI4Chem/nmrkit int…
NishaSharma14 Jul 22, 2026
34b2195
docs: migrate to Scalar and complete documentation update (#114)
vcnainala Jul 22, 2026
965abd7
fix: add scalar-fastapi to requirements.txt for scalar API support (#…
NishaSharma14 Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Key Features:
🔄 Format Conversion: Effortlessly convert NMR data between various file formats.

🔗 Explore the documentation and get started: https://nfdi4chem.github.io/nmrkit
Swagger Endpoint - https://dev.nmrkit.nmrxiv.org/latest/docs
API Reference (Scalar) - https://dev.nmrkit.nmrxiv.org/latest/docs
📢 Found a bug or have a feature request? We'd love to hear from you! Please open an issue: [https://github.com/NFDI4Chem/nmrkit/issues]

Happy NMR exploring! 🧪🌟"
Expand Down
57 changes: 57 additions & 0 deletions app/core/scalar_docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from fastapi import FastAPI
from fastapi.routing import APIRoute
from scalar_fastapi import get_scalar_api_reference
from starlette.routing import Mount


def _remove_doc_routes(fastapi_app: FastAPI) -> None:
fastapi_app.router.routes = [
route
for route in fastapi_app.router.routes
if not (
isinstance(route, APIRoute)
and route.path in ("/docs", "/redoc")
)
]
fastapi_app.docs_url = None
fastapi_app.redoc_url = None


def _remove_versioning_noop_routes(parent_app: FastAPI) -> None:
parent_app.router.routes = [
route
for route in parent_app.router.routes
if not (
isinstance(route, APIRoute)
and route.path.endswith(("/docs", "/openapi.json"))
and route.endpoint.__name__ == "noop"
)
]


def _add_scalar_docs(fastapi_app: FastAPI, openapi_url: str, title: str) -> None:
_remove_doc_routes(fastapi_app)

@fastapi_app.get("/docs", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
openapi_url=openapi_url,
title=title,
)


def configure_scalar_docs(parent_app: FastAPI) -> None:
"""Replace default Swagger UI with Scalar on all versioned API mounts."""
_remove_versioning_noop_routes(parent_app)

for route in parent_app.routes:
if not isinstance(route, Mount) or not isinstance(route.app, FastAPI):
continue

prefix = route.path.rstrip("/")
mounted_app = route.app
_add_scalar_docs(
mounted_app,
openapi_url=f"{prefix}/openapi.json",
title=mounted_app.title,
)
14 changes: 12 additions & 2 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from fastapi.middleware.cors import CORSMiddleware

from app.core import config, tasks
from app.core.scalar_docs import configure_scalar_docs

from prometheus_fastapi_instrumentator import Instrumentator
from app.schemas import HealthCheck
Expand All @@ -32,6 +33,7 @@
### Links

* [Documentation](https://nfdi4chem.github.io/nmrkit)
* [API Reference (Scalar)](https://dev.nmrkit.nmrxiv.org/latest/docs)
* [Source Code](https://github.com/NFDI4Chem/nmrkit)
"""

Expand Down Expand Up @@ -88,14 +90,21 @@
app.include_router(converter.router)
app.include_router(predict.router)

app.add_event_handler("startup", tasks.create_start_app_handler(app))
app.add_event_handler("shutdown", tasks.create_stop_app_handler(app))
if hasattr(app, "add_event_handler"):
app.add_event_handler("startup", tasks.create_start_app_handler(app))
app.add_event_handler("shutdown", tasks.create_stop_app_handler(app))
else:
# FastAPI versions that removed direct event registration still support router-level handlers.
app.router.add_event_handler("startup", tasks.create_start_app_handler(app))
app.router.add_event_handler("shutdown", tasks.create_stop_app_handler(app))

app = VersionedFastAPI(
app,
version_format="{major}",
prefix_format="/v{major}",
enable_latest=True,
docs_url=None,
redoc_url=None,
description=DESCRIPTION,
terms_of_service="https://nfdi4chem.github.io/nmrkit",
contact={
Expand All @@ -109,6 +118,7 @@
},
openapi_tags=tags_metadata,
)
configure_scalar_docs(app)

Instrumentator().instrument(app).expose(app)

Expand Down
8 changes: 4 additions & 4 deletions app/routers/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ def get_health() -> HealthCheck:
"| **nmrshift** | proton, carbon | ~5-10s |\n"
"| **nmrdb.org** | proton, carbon, cosy, hsqc, hmbc | ~30-60s |\n\n"
"> **Note:** nmrdb.org predictions can take 30-60 seconds. "
"Consider using curl or Postman instead of the Swagger UI for long-running requests."
"Consider using curl or Postman instead of the API docs for long-running requests."
),
response_description="Predicted spectra in NMRium-compatible JSON format",
status_code=status.HTTP_200_OK,
Expand All @@ -499,7 +499,7 @@ async def predict_from_structure(request: PredictRequest):
"""
## Predict NMR spectra from a MOL string

**Note:** nmrdb.org predictions take 30-60s. Use curl/Postman, not Swagger.
**Note:** nmrdb.org predictions take 30-60s. Use curl/Postman, not the API docs.

### Engines

Expand Down Expand Up @@ -564,7 +564,7 @@ async def predict_from_structure(request: PredictRequest):
"| **nmrshift** | proton, carbon | ~5-10s |\n"
"| **nmrdb.org** | proton, carbon, cosy, hsqc, hmbc | ~30-60s |\n\n"
"> **Note:** nmrdb.org predictions can take 30-60 seconds. "
"Consider using curl or Postman instead of the Swagger UI for long-running requests."
"Consider using curl or Postman instead of the API docs for long-running requests."
),
response_description="Predicted spectra in NMRium-compatible JSON format",
status_code=status.HTTP_200_OK,
Expand Down Expand Up @@ -597,7 +597,7 @@ async def predict_from_file(

Upload a MOL file and pass engine options as a JSON string in the `request` field.

> **Note:** nmrdb.org predictions take 30-60s. Use curl/Postman, not Swagger.
> **Note:** nmrdb.org predictions take 30-60s. Use curl/Postman, not the API docs.

### nmrshift example `request` field
```json
Expand Down
27 changes: 19 additions & 8 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,46 @@ export default defineConfigWithTheme<ThemeConfig>({
},
nav: [
{ text: 'Home', link: '/nmrkit/introduction' },
{ text: 'API', link: 'https://dev.nmrkit.nmrxiv.org/latest/docs' },
{ text: 'API Reference', link: '/getting-started/api-reference' },
{ text: 'Scalar (dev)', link: 'https://dev.nmrkit.nmrxiv.org/latest/docs' },
{ text: 'GitHub', link: 'https://github.com/NFDI4Chem/nmrkit' }
],
sidebar: [
{
text: 'Getting Started',
items: [
{ text: 'Introduction', link: '/introduction' },
{ text: 'Versions', link: '/getting-started/versions' },
{ text: 'API Reference', link: '/getting-started/api-reference' },
{ text: 'Architecture', link: '/getting-started/architecture' },
{ text: 'Versions', link: '/getting-started/versions' },
]
},
{
text: 'Deployment',
items: [
//{ text: 'Public API', link: '/public-api' },
{ text: 'Overview', link: '/deployment/overview' },
{ text: 'Docker', link: '/deployment/docker' },
{ text: 'Cluster Deployment (K8S)', link: '/deployment/cluster-deployment' }
]
},
{
text: 'Services',
items: [
{ text: 'nmr-cli', link: '/services/nmr-cli' },
{ text: 'nmr-respredict', link: '/services/nmr-respredict' },
]
},
{
text: 'Modules',
items: [
{ text: 'Registration', link: '/modules/registration' },
{ text: 'Search', link: '/modules/search' },
{ text: 'Prediction', link: '/modules/prediction' },
{ text: 'Chemistry', link: '/modules/chemistry' },
{ text: 'Spectra', link: '/modules/spectra' },
{ text: 'Training', link: '/modules/training' },
{ text: 'Validation', link: 'modules/validation' },
{ text: 'Converter', link: '/modules/converter' },
{ text: 'Prediction', link: '/modules/prediction' },
{ text: 'Registration', link: '/modules/registration' },
{ text: 'Search (planned)', link: '/modules/search' },
{ text: 'Training (planned)', link: '/modules/training' },
{ text: 'Validation (planned)', link: '/modules/validation' },
]
},
{
Expand Down
94 changes: 84 additions & 10 deletions docs/src/deployment/docker.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,99 @@
# Docker
NMRKit is containerized using Docker and is distributed publicly via the [Docker Hub](https://hub.docker.com/r/nfdi4chem/nmrkit), a cloud-based registry provided by Docker that allows developers to store, share, and distribute Docker images.

To use this image:
NMRKit is containerized using Docker and distributed via
[Docker Hub](https://hub.docker.com/r/nfdi4chem/nmrkit).

* Make sure you have [Docker](https://docs.docker.com/get-docker/) installed and configured on your target deployment environment.
* Pull the NMRKit image by providing the appropiate tag.
## Pull the image

```bash
docker pull nfdi4chem/nmrkit:[tag]
docker pull nfdi4chem/nmrkit:latest # production
docker pull nfdi4chem/nmrkit:dev-latest # development
```

## Docker Compose (recommended)

The root `docker-compose.yml` starts the full stack:

```bash
cp env.template .env
docker compose up -d
```
* NMRKit uses [rdkit-cartridge-debian](https://hub.docker.com/r/informaticsmatters/rdkit-cartridge-debian) Postgres. Run the below command to spin up the image.

| Service | Container | Port | Purpose |
|---------|-----------|------|---------|
| `web` | `nmrkit-api` | 8080→80 | FastAPI application |
| `nmr-load-save` | `nmr-converter` | — | nmr-cli spectra parsing & prediction |
| `nmr-respredict` | `nmr-respredict` | — | Residual NMR prediction (future) |
| `pgsql` | — | 5433→5432 | PostgreSQL + RDKit cartridge |
| `redis` | — | 6380→6379 | Cache |
| `minio` | — | 9002, 8901 | Object storage |
| `prometheus` | `nmrkit_prometheus` | 9090 | Metrics |
| `grafana` | `nmrkit_grafana` | 3000 | Dashboards |

Open http://localhost:8080/latest/docs for the Scalar API reference.

### Volumes

- `./app` is mounted into the API container for live code reload during development
- `/var/run/docker.sock` allows the API to `docker exec` into `nmr-converter`
- `shared-data` passes files between API, nmr-cli, and nmr-respredict containers

## Standalone container

For a minimal deployment with an external PostgreSQL instance:

```bash
docker run -d --name postgres -e POSTGRES_PASSWORD=password -e POSTGRES_USER=nmrkit -p 5432:5432 informaticsmatters/rdkit-cartridge-debian:latest
# Start PostgreSQL with RDKit cartridge
docker run -d --name postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_USER=nmrkit \
-p 5432:5432 \
informaticsmatters/rdkit-cartridge-debian:latest

# Start NMRKit API
docker run -d -p 8080:80 --name nmrkit \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_USER=nmrkit \
-e POSTGRES_SERVER=postgres \
-e POSTGRES_DB=nmr_predict \
--link postgres:postgres \
nfdi4chem/nmrkit:latest
```

* After the Postgres container is prepared to receive connections, initiate the NMRKit container by executing the following command and providing the Postgres credentials.
::: warning
Standalone mode does not include `nmr-converter`. Spectra parsing and prediction
endpoints require the nmr-cli container — use Docker Compose instead.
:::

## Server deployments (Traefik)

For hosted dev/prod environments, use the ops compose files:

```bash
docker run -d -p 8080:80 --name nmrkit -e POSTGRES_PASSWORD=password -e POSTGRES_USER=nmrkit -e POSTGRES_SERVER=postgres -e POSTGRES_DB=nmr_predict nfdi4chem/nmrkit:[tag]
# Development
docker compose -f ops/docker-compose-dev.yml up -d

# Production
docker compose -f ops/docker-compose-prod.yml up -d
```

These configurations use [Traefik](https://traefik.io/) as a reverse proxy:

| Environment | Host | Image tag |
|-------------|------|-----------|
| Development | `dev.nmrkit.nmrxiv.org` | `nfdi4chem/nmrkit:dev-latest` |
| Production | `nmrkit.nmrxiv.org` | `nfdi4chem/nmrkit:latest` |

## Health checks

Docker Compose health checks hit the registration module:

```
GET http://localhost:80/latest/registration/health
```

## See also

```
- [Deployment Overview](./overview) — all deployment options
- [nmr-cli service](../services/nmr-cli) — companion container details
- [Local Installation](../development/installation) — development setup
75 changes: 75 additions & 0 deletions docs/src/deployment/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Deployment Overview

NMRKit supports three deployment modes:

| Mode | Use case | Documentation |
|------|----------|---------------|
| **Docker Compose (local)** | Development and testing | [Local Installation](../development/installation#docker) |
| **Docker Compose (ops)** | Dev / prod servers with Traefik | [Docker](./docker) |
| **Kubernetes (Helm)** | Cluster deployments | [Cluster Deployment](./cluster-deployment) |

## Public instances

| Environment | API docs | Host |
|-------------|----------|------|
| Development | [dev.nmrkit.nmrxiv.org/latest/docs](https://dev.nmrkit.nmrxiv.org/latest/docs) | `dev.nmrkit.nmrxiv.org` |
| Production | [nmrkit.nmrxiv.org/latest/docs](https://nmrkit.nmrxiv.org/latest/docs) | `nmrkit.nmrxiv.org` |

## Compose files

| File | Purpose |
|------|---------|
| `docker-compose.yml` | Full local stack (API, nmr-cli, nmr-respredict, DB, Redis, MinIO, monitoring) |
| `ops/docker-compose-dev.yml` | Dev server with Traefik reverse proxy |
| `ops/docker-compose-prod.yml` | Production server with Traefik |

## Required services

At minimum, the following containers must be running for full API functionality:

| Service | Required for |
|---------|-------------|
| `nmrkit-api` | All API endpoints |
| `nmr-converter` | Spectra, converter, and predict modules |
| `pgsql` | Registration module |
| `nmr-respredict` | Future respredict integration (optional today) |

## Environment configuration

Copy `env.template` to `.env` and set database credentials:

```bash
cp env.template .env
```

| Variable | Description |
|----------|-------------|
| `POSTGRES_USER` | PostgreSQL username |
| `POSTGRES_PASSWORD` | PostgreSQL password |
| `POSTGRES_SERVER` | Database host (`pgsql` in Compose) |
| `POSTGRES_PORT` | Database port (default `5432`) |
| `POSTGRES_DB` | Database name (`nmr_predict`) |
| `MINIO_ROOT_USER` | MinIO access key |
| `MINIO_ROOT_PASSWORD` | MinIO secret key |

## CI/CD

Docker images are built and published via GitHub Actions:

- `dev-build.yml` — builds `nfdi4chem/nmrkit:dev-latest` on pushes to `development`
- `prod-build.yml` — builds `nfdi4chem/nmrkit:latest` on releases
- `doc-deploy.yml` — deploys this documentation site to GitHub Pages

See [#95 — Update CI/CD and deployment script](https://github.com/NFDI4Chem/nmrkit/issues/95)
for ongoing improvements to the deployment pipeline.

## Quick start (local)

```bash
git clone https://github.com/NFDI4Chem/nmrkit.git
cd nmrkit
cp env.template .env
docker compose up -d
```

API docs: http://localhost:8080/latest/docs
Loading
Loading