Architecture overview (C4-style)¶
C4-inspired view of the SODa SCS Manager deployment: Compose app → Docker services → software modules → integration flows → configs and operational scripts.
Target container DNS (migration): {scope}--{service}--{function} — see Naming vocabulary. Ist→Soll and cutover: Naming migration plan.
Related detail pages: Service infrastructure, Naming vocabulary, Naming migration plan, Nextcloud mount sidecar, WissKI stack, Maintenance.
Diagrams below still use current names
Mermaid graphs in this page show today’s container names until the migration waves land.
1. System context (C4 L1)¶
Who uses the platform and which external systems it talks to.
flowchart TB
User[Platform user<br/>researcher / curator]
Admin[Operator<br/>DevOps / SCS admin]
subgraph SCS["SODa SCS Deployment"]
Platform[SCS Platform<br/>Compose multi-stack:<br/>Manager · Drive · Code · Auth · Ontologies · Triplestore · Health]
end
IdP[Upstream IdP / DIDMOS<br/>optional federation]
LE[Let's Encrypt]
Reg[Container registries<br/>ghcr.io / Docker Hub]
User -->|HTTPS apps| Platform
Admin -->|Ops · Portainer · Health · backups| Platform
Platform -.->|OIDC broker optional| IdP
Platform -->|ACME / TLS| LE
Platform -->|pull images| Reg
2. Containers — Compose app → Docker services (C4 L2)¶
Level: one Docker Compose project (root COMPOSE_FILE) plus per-project WissKI stacks created at runtime via Portainer.
flowchart TB
User[User / Browser]
subgraph Edge["Edge & shared infra"]
Traefik[scs--reverse-proxy<br/>Traefik TLS + routing]
DB[(scs--database<br/>MariaDB 11.5)]
Portainer[scs--portainer]
PMA[scs--phpmyadmin]
FwdAuth[scs--forward-auth]
Mounter[nextcloud-mounter<br/>rclone FUSE]
Health[scs--health]
end
subgraph Apps["Application stacks"]
KC[keycloak--keycloak]
Mgr[scs-manager--drupal]
MgrRedis[scs-manager--redis]
NC[nextcloud--nextcloud--app]
NCRP[nextcloud--nginx--edge]
OO[nextcloud--ods--app]
NCRedis[nextcloud--redis--cache]
JH[jupyterhub--jupyterhub--app]
WP[webprotege--webprotege--app]
WPMongo[(webprotege--mongodb--db)]
OpenGDB[OpenGDB<br/>nginx · AuthProxy · RDF4J]
end
subgraph WissKI["Per-project via Portainer"]
WVarnish["{svc}--varnish"]
WDrupal["{svc}--drupal"]
WRedis["{svc}--redis"]
end
User --> Traefik
Traefik --> KC
Traefik --> Mgr
Traefik --> NCRP
Traefik --> JH
Traefik --> WP
Traefik --> OpenGDB
Traefik --> Portainer
Traefik --> PMA
Traefik --> Health
Traefik --> WVarnish
KC --> DB
Mgr --> DB
NC --> DB
WDrupal --> DB
Mgr -.->|OIDC| KC
NC -.->|OIDC| KC
JH -.->|OIDC| KC
WP -.->|OIDC| KC
FwdAuth -.->|OIDC| KC
PMA --> FwdAuth
NCRP --> NC
NCRP --> OO
Mgr --> MgrRedis
NC --> NCRedis
WP --> WPMongo
WVarnish --> WDrupal
WDrupal --> WRedis
Mgr -->|rc API| Mounter
Mounter -->|WebDAV| NC
JH -.->|rslave project folders| Mounter
WDrupal -.->|rslave project folder| Mounter
Mgr -->|deploy stacks| Portainer
Portainer --> WissKI
WDrupal -->|SPARQL| OpenGDB
Compose wiring (how the “App” is assembled)¶
| Layer | Location | Role |
|---|---|---|
| Root compose | docker-compose.yml |
Traefik, MariaDB, Portainer, phpMyAdmin, forward-auth, nextcloud-mounter, shared volumes/networks |
| Stack compose | <stack>/docker-compose.yml |
Submodule base service definitions |
| Site overrides | 00_custom_configs/<stack>/docker/docker-compose.override.yml |
Domains, Traefik labels, volume mounts, networks (!override), ports (!reset) |
| Aggregation | .env → COMPOSE_FILE=… |
Single docker compose from repo root merges all files |
| Bootstrap | ./start.sh |
Network, override copy, DB start, all pre-install scripts |
Never pass -f manually for normal ops — see project stack-operations rules.
3. Components (software modules & extensions)¶
flowchart TB
subgraph Manager["scs-manager--drupal"]
SM[soda_scs_manager]
OIDC_D[openid_connect]
Theme[soda_scs_manager_theme]
SM --> PortAPI[Portainer API]
SM --> MountAPI[NextcloudMountManager]
SM --> WPAPI[WebProtégé REST]
SM --> KCAPI[Keycloak Admin]
SM --> NCAPI[Nextcloud OCS/WebDAV]
end
subgraph NextcloudApps["nextcloud--nextcloud--app apps"]
UOIDC[user_oidc]
Social[sociallogin]
OOApp[onlyoffice]
Draw[drawio]
TF[Group / Team Folders]
end
subgraph Jupyter["jupyterhub--jupyterhub--app"]
GA[GenericOAuthenticator]
Spawner[Spawner + group_map]
Tools[spawner_image: wisski_py, OpenRefine, …]
end
subgraph KeycloakComp["keycloak--keycloak"]
Realm[Realm from scs-realm.json.tpl]
Clients[OIDC clients: Manager, Drive, Code, DBMS, WebProtégé, DIDMOS, Health]
ThemeKC[SCS theme]
end
subgraph WissKIComp["WissKI instance"]
Wisski[WissKI / SALZ]
NCext[nextcloud_webdav_mount external]
RedisMod[Redis Drupal module]
end
OIDC_D -.-> Realm
UOIDC -.-> Realm
GA -.-> Realm
| Stack | Notable modules / apps | Configured by |
|---|---|---|
| SCS Manager | soda_scs_manager, OpenID Connect, custom theme |
Pre-install OIDC YAML; Drupal settings under 00_custom_configs/scs-manager-stack/drupal/ |
| Nextcloud | user_oidc, Social Login, OnlyOffice, Draw.io, Team Folders |
scs-nextcloud-stack/hooks/post-installation/* (first install only) |
| JupyterHub | OAuthenticator, Linux GIDs from Keycloak groups | jupyterhub/jupyterhub/jupyterhub_config.py + env |
| WebProtégé | OIDC SSO, project REST API patches | 00_custom_configs/webprotege/patches/ |
| WissKI (per project) | WissKI, Redis, external Nextcloud mount | Portainer env from Manager; wisski-base-image |
4. Integration flows¶
4.1 Identity (OIDC)¶
sequenceDiagram
participant U as Browser
participant T as Traefik
participant App as App (Manager / Drive / Code / …)
participant KC as Keycloak
U->>T: HTTPS Host(app)
T->>App: proxy
App->>U: redirect to Keycloak
U->>KC: login / consent
KC->>App: code / tokens (OIDC)
App->>KC: userinfo (groups, gids, …)
4.2 Nextcloud ↔ JupyterHub / WissKI (FUSE mount)¶
SCS Manager owns mount lifecycle; Jupyter and WissKI only bind project Team Folder paths (rslave). Details: Nextcloud mount sidecar.
flowchart LR
subgraph Host["Host FS"]
Root["NEXTCLOUD_MOUNTS_ROOT<br/>/var/lib/scs/nextcloud-mounts<br/>propagation: shared"]
end
NC[nextcloud--nextcloud--app<br/>WebDAV]
Mounter[nextcloud-mounter<br/>rclone FUSE]
Mgr[scs-manager--drupal<br/>rc API only]
JH[Jupyter notebook<br/>…/nextcloud/project-label]
WK[WissKI Drupal<br/>private://nextcloud]
Mgr -->|mount/unmount| Mounter
Mounter -->|WebDAV| NC
Mounter -->|FUSE under user/| Root
Root -->|rslave bind project folder| JH
Root -->|rslave bind project folder| WK
4.3 SCS Manager ↔ Portainer ↔ WissKI¶
flowchart LR
Mgr[SCS Manager] -->|Docker API via socket| Portainer
Portainer -->|deploy compose| WissKI[WissKI stack]
WissKI -->|SPARQL internal| AuthProxy[scs--authproxy]
AuthProxy --> RDF4J[scs--rdf4j]
WissKI --> MariaDB[(scs--database)]
5. Where configs live¶
flowchart TB
ENV[".env / example-env<br/>COMPOSE_FILE, domains, secrets"]
CC["00_custom_configs/<stack>/"]
Scripts["01_scripts/<stack>/pre-install.*"]
StackDir["<stack>/ (submodule + generated)"]
ENV --> Compose["docker compose up"]
CC -->|start.sh copies overrides| StackDir
Scripts -->|envsubst / DB create| StackDir
CC -->|Drupal PHP snippets, realm tpl,<br/>OIDC YAML tpl, nginx tpl, patches| StackDir
| Kind | Path | Notes |
|---|---|---|
| Env & compose list | .env (from example-env) |
COMPOSE_FILE, domains, DB/OIDC secrets |
| Compose overrides | 00_custom_configs/<stack>/docker/docker-compose.override.yml |
Copied by start.sh if dest missing |
| Drupal settings | 00_custom_configs/scs-manager-stack/drupal/*.php |
Reverse proxy, private files, OIDC, logging |
| OIDC client export | 00_custom_configs/scs-manager-stack/openid/*.yml.tpl |
→ scs-manager-stack/custom_configs/ |
| Keycloak realm | 00_custom_configs/keycloak/templates/realm/scs-realm.json.tpl |
→ keycloak/…/import/ |
| Nextcloud nginx | 00_custom_configs/scs-nextcloud-stack/… |
Proxy MIME / headers |
| phpMyAdmin | 00_custom_configs/phpmyadmin/configs/ |
Sign-on / SSO |
| WebProtégé patches | 00_custom_configs/webprotege/patches/ |
OIDC, project API, Docker build |
| Default landing page | 00_custom_configs/default-page/ |
Optional nginx static |
| Host systemd (FUSE) | 01_scripts/global/scs-nextcloud-mounts.service |
Keeps mounts root shared |
Overrides use ${SCS_ROOT_PATH}/… for host volume paths and volumes: !override / networks: !override where the base list must be replaced.
6. Bootstrap, scripts, backup & maintenance¶
Lifecycle¶
flowchart TD
A[Clone + submodule init] --> B[cp example-env → .env]
B --> C[setup-nextcloud-mounts.sh<br/>+ optional systemd unit]
C --> D[./start.sh]
D --> D1[reverse-proxy network]
D --> D2[Copy compose overrides]
D --> D3[Start scs--database]
D --> D4[Run all pre-install scripts]
D4 --> E[docker compose up -d]
E --> F[Post-config checklist<br/>Keycloak clients, occ hooks if needed]
F --> G[Ops: backups, updates, repair]
Script map (01_scripts/)¶
| Area | Scripts | Responsibility |
|---|---|---|
| Global bootstrap | global/pre-install.sh, setup-nextcloud-mounts.sh |
Snapshot dirs, FUSE host bind |
| Per-stack pre-install | */pre-install.sh |
DB users, realm/OIDC/VCL/nginx generation |
| Backup orchestrator | global/backup-all-services.bash |
Calls all service backups → /srv/backups/ |
| Per-service backup | *-backup.bash / backup-*.bash |
Keycloak, Manager, Nextcloud, JupyterHub, OpenGDB, WebProtégé, project website |
| Nextcloud maintain | run-nextcloud-repair.bash, apply-nextcloud-proxy-and-region.bash, configure-nextcloud-email.bash, fix-*.bash |
Post-update / warning fixes |
| DB | database/db-snapshot.bash |
MariaDB snapshots |
| WissKI | wisski/apply-performance-tuning.bash |
Tune running Portainer stacks |
| WebProtégé | configure-oidc.bash |
OIDC post-setup |
| Logs | global/truncate-runtime-logs.bash |
Disk hygiene |
| Stack helpers | scs-nextcloud-stack/start-services.bash, stop-services.bash |
Start/stop Nextcloud stack alone |
Entry point for first-time setup: ./start.sh at repo root. Day-2 backup: 01_scripts/global/backup-all-services.bash. Updates: Maintenance / Updates.
Docker service inventory (quick)¶
| Stack / compose | Containers (typical) |
|---|---|
| Root | core--traefik--edge (alias scs--reverse-proxy), core--mariadb--db (alias scs--database), core--portainer--app (alias scs--portainer), dbms--phpmyadmin--app (alias scs--phpmyadmin), dbms--forwardauth--proxy (alias scs--forward-auth), core--echo--app (alias scs--echo), core--rclone--sidecar (alias nextcloud-mounter) |
| Keycloak | keycloak--keycloak--app (alias keycloak--keycloak) |
| SCS Manager | manager--drupal--app (alias scs-manager--drupal), manager--redis--cache (alias scs-manager--redis) (DB/Varnish often disabled via override) |
| Nextcloud | nextcloud--nextcloud--app (alias nextcloud--nextcloud), nextcloud--nginx--edge (alias nextcloud--nextcloud-reverse-proxy), nextcloud--ods--app (alias nextcloud--onlyoffice-document-server), nextcloud--ods--edge (alias nextcloud--onlyoffice-reverse-proxy), nextcloud--redis--cache (alias nextcloud--redis) |
| JupyterHub | jupyterhub--jupyterhub--app (alias jupyterhub--jupyterhub), jupyterhub--spawner--builder (build only; alias jupyterhub--image-builder) |
| OpenGDB | opengdb--rdf4j--db (alias scs--rdf4j), opengdb--nginx--edge (alias scs--opengdb-proxy), opengdb--authproxy--proxy (alias scs--authproxy), opengdb--outproxy--proxy (alias scs--outproxy) |
| WebProtégé | webprotege--webprotege--app (alias webprotege), webprotege--mongodb--db (aliases wpmongo, webprotege-mongodb) |
| SCS Health | health--health--app (alias scs--health) |
| Project website (optional) | scs-project-website--* (not in live COMPOSE_FILE here; Wave H6 skipped) |
| WissKI (runtime) | {SERVICE_NAME}--varnish / --drupal / --redis via Portainer — naming Wave Z deferred (needs wisski-base-stack release; prefer wisski--{id}--* over proj-{id}) |
7. Networks & shared volumes¶
| Resource | Purpose |
|---|---|
Network reverse-proxy |
Traefik ↔ all public HTTP services (IPv6 enabled) |
Network nextcloud-mounter-net |
Internal: Manager ↔ mounter rc API only |
Volume scs--database-data |
Shared MariaDB |
Volume scs--shared-data / JUPYTERHUB_SHARE |
Shared Hub data |
Host path NEXTCLOUD_MOUNTS_ROOT |
FUSE tree for Jupyter / WissKI binds |
Volume scs--reverse-proxy-certificates |
Traefik / ACME storage |
See also¶
- Service infrastructure overview — narrative wiring per stack
- Pre-start steps — what
start.shruns - Post-configuration checklist
- SCS Manager user lifecycle
- Troubleshooting: Drive ↔ Jupyter