Onboarding a New Integration
This guide walks you through adding a new Signals ELN integration to the monorepo, configuring infrastructure, and deploying it to Minerva.
Prerequisites
Before you begin, make sure you have:
- Access to the xred-eln-integrations repo
- Access to Vault under
minerva-prod/xred-eln - Access to ArgoCD for the target environment
- uv and Node.js 20+ installed locally
If you don’t have access yet, follow the steps in Getting Started to request the
ROLE-PRED-MINERVA-XRED-ELN-DEV role via CIDM.
Repository structure
All integrations live in the apps/ directory of the monorepo. Each app has a backend (FastAPI)
and frontend (React):
- Dockerfile
- pyproject.toml
- uv.lock
- Dockerfile
- package.json
Step-by-step guide
Create the app directory
Pick a short, lowercase name for your integration. This name is used in directory paths, Docker image tags, and Kubernetes resource names.
APP_NAME="my-integration"
mkdir -p apps/$APP_NAME/backend/app apps/$APP_NAME/backend/tests apps/$APP_NAME/frontend/srcSet up the backend
Copy the structure from apps/demo/backend/ and modify:
pyproject.toml— update the project name and add your dependenciesapp/main.py— implement your FastAPI endpoints (keep the/healthendpoint)tests/— add your tests
cp apps/demo/backend/pyproject.toml apps/$APP_NAME/backend/
cp apps/demo/backend/app/main.py apps/$APP_NAME/backend/app/
cp apps/demo/backend/tests/test_health.py apps/$APP_NAME/backend/tests/Generate the lock file:
cd apps/$APP_NAME/backend
uv lockSet up the Dockerfile (backend)
Create apps/$APP_NAME/backend/Dockerfile. The build context is the repo root, so paths
must be fully qualified:
FROM python:3.12-slim
COPY certs/ /usr/local/share/ca-certificates/roche/
RUN update-ca-certificates
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY apps/my-integration/backend/pyproject.toml apps/my-integration/backend/uv.lock ./
RUN uv sync --frozen --no-install-project
COPY apps/my-integration/backend/app/ ./app/
EXPOSE 8000
CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]Replace my-integration with your actual app name in all COPY paths.
Set up the frontend (optional)
If your integration includes a frontend, copy the structure from apps/demo/frontend/ and modify:
package.json— update the project namesrc/— implement your React componentsDockerfile— update theCOPYpaths to match your app name
cp -r apps/demo/frontend/* apps/$APP_NAME/frontend/Skip this step if your integration is backend-only.
Push to develop and verify CI
Create a feature branch and push:
git checkout -b feat/$APP_NAME/initial-setup
git add apps/$APP_NAME
git commit -m "feat($APP_NAME): initial integration scaffold"
git push -u origin feat/$APP_NAME/initial-setupOpen a PR to develop. The CI pipeline will detect your new app automatically and run
lint, test, and security stages. Once merged to develop, Docker images are built and
pushed to GHCR.
Deploy to Minerva
There are two ways to deploy: the Deploy workflow (recommended) or manually creating K8s manifests.
Option A: Deploy workflow (recommended)
The Deploy workflow automatically creates Kubernetes manifests if they don’t exist yet, or updates the image tag if they do.
- Go to Actions → Deploy
- Click Run workflow
- Select the branch that matches your target environment (
develop→ DEV,uat→ UAT,main→ PROD) - Fill in the inputs:
| Input | Description |
|---|---|
| App | Your app name (e.g. my-integration) |
| Components | backend, frontend, or both |
The environment and image tag are determined automatically from the branch. The workflow will:
- Run preflight checks (CI status, image availability, Dockerfiles)
- Scaffold the K8s manifests (deployment, service, ingress) if this is the first deploy
- Update the image tag if manifests already exist
- Push to the infrastructure repo on the correct branch
- ArgoCD picks up the change and deploys automatically
Option B: Manual K8s manifests
If you need more control, you can create the manifests yourself in the
infrastructure repo on the target
environment branch (e.g. dev):
k8s/
├── secretstore.yaml # Shared (already exists)
├── externalsecret-registry.yaml # Shared (already exists)
├── kustomization.yaml # Add your app here
└── my-integration/
├── deployment-backend.yaml
├── service-backend.yaml
├── ingress-backend.yaml
└── kustomization.yamlEach manifest must follow Minerva conventions:
securityContext.allowPrivilegeEscalation: falseon all containers- Minerva labels:
minerva.roche.com/project: xred-eln,minerva.roche.com/service: <app> imagePullSecretsreferencingghcr-registry-secret- Ingress with
cert-manager.io/cluster-issuer: roche-acme-prodand the correct hostname for the environment
The hostname depends on the environment:
| Environment | Domain |
|---|---|
| DEV | minerva.sandbox.pcloud.roche.com |
| UAT | apps.uat.minerva.roche.com |
| PROD | apps.minerva.roche.com |
Add your app to the top-level k8s/kustomization.yaml:
resources:
- secretstore.yaml
- externalsecret-registry.yaml
- my-integration/ # Add this linePush to the target branch and sync in ArgoCD.
Verify
Once ArgoCD shows Healthy and Synced, your backend should be reachable at:
https://xred-eln-my-integration-api.<domain>/health| Environment | Domain |
|---|---|
| DEV | minerva.sandbox.pcloud.roche.com |
| UAT | apps.uat.minerva.roche.com |
| PROD | apps.minerva.roche.com |
Environment promotion
To promote your integration to a higher environment:
- Merge your code in the integrations repo:
develop→uat→main - Wait for CI to build the images on the target branch
- Run the Deploy workflow from the target branch
| Branch | Deploys to | Image tag |
|---|---|---|
develop | DEV | :develop |
uat | UAT | :uat |
main | PROD | :main |
Deployments to UAT and PROD can only be triggered from the uat or main branch
respectively — the workflow will fail on any other branch. This ensures only merged and
reviewed code gets deployed. On DEV, the 4-eye principle is not enforced but recommended.
See Secret Management for how to add secrets in Vault and reference them in your deployments.
Environment mappings
The full mapping of xRED ELN environments across Signals, MuleSoft (Proxify), Gravitee, and ArgoCD:
| Environment | Signals | Signals Proxy | Proxify1 | Gravitee (Minerva) | Argo |
|---|---|---|---|---|---|
| PRE-DEV (SBX) | xRED | xRED DEV Proxy | Development | DEV | DEV |
| DEV | DEV | xRED DEV Proxy | Development | DEV | DEV |
| UAT | TEST | xRED UAT Proxy | Test | UAT | UAT |
| TRAINING | TRAINING | xRED UAT Proxy | Stage | UAT | UAT |
| PROD | PROD | xRED PROD Proxy | Production | PROD | PROD |
Footnotes
-
Proxify — this layer typically exposes endpoints for Signals Data Sources. ↩