Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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,
)
5 changes: 5 additions & 0 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 @@ -101,6 +103,8 @@
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 @@ -114,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