# Portal Configuration

This page describes how UDiTH Portal is configured and lists all available settings.

Portal uses the standard .NET configuration system. Throughout this page, settings are written using the .NET hierarchical notation, with a colon (`:`) separating each level of the hierarchy, for example `KeycloakAdmin:Name`. Array elements are addressed by their index, starting at `0`, for example `Serilog:WriteTo:0:Name`. Where a setting represents an array, the index is shown as `[]`.

## Loading Configuration

How a setting is provided depends on the platform.

### Linux (Docker)

On Linux, Portal is configured through environment variables, optionally backed by Docker secret files.

#### Environment variables

Each setting is provided as an environment variable. Because an environment variable name cannot contain a colon, replace every `:` in the setting name with a double underscore (`__`).

For example, the setting `KeycloakAdmin:Name` becomes:

```
KeycloakAdmin__Name=admin
```

And an array element such as `Serilog:WriteTo:0:Name` becomes:

```
Serilog__WriteTo__0__Name=Console
```

#### Docker secret files

Any variable can also be read from a file, similar to Docker secrets. To do this, append the `_file` suffix to the variable name and reference the file that contains the secret.

```
KeycloakAdmin__Password=<pw>
KeycloakAdmin__Password_file=/run/secrets/keycloak_password
```

#### Escaping `$` in Docker Compose

In Docker Compose, a value containing `$` is interpreted as a variable reference. A literal `$` must therefore be escaped as `$$`.

### Windows

On Windows, settings are stored in the `Settings/sharedsettings.json` file inside the Portal installation directory. The configuration uses standard JSON, with the hierarchy expressed as nested objects. For example, the setting `KeycloakAdmin:Name` is written as:

```json
{
  "KeycloakAdmin": {
    "Name": "admin"
  }
}
```

Array elements become JSON arrays:

```json
{
  "Serilog": {
    "WriteTo": [
      { "Name": "Console" }
    ]
  }
}
```

## Settings Reference

The following list contains all available settings, written in .NET (`:`) notation. Remember to translate each name to the form required by your platform, as described under [Loading Configuration](#loading-configuration).

```
###############################################################################
# Keycloak
###############################################################################

# URL used to connect to Keycloak. This is the public URL that both the server
# and browser clients use for authentication (e.g. https://keycloak.example.com).
KeycloakUrl=https://...
# Keycloak realm to use for authentication. This realm is created automatically
# during initial setup if it does not exist yet.
KeycloakRealm=portal
# Keycloak admin user name. Needs permission to manage the realm specified above.
KeycloakAdmin:Name=admin
# Keycloak admin user password.
KeycloakAdmin:Password=...

###############################################################################
# Server
###############################################################################

# MSSQL database connection string. Must point to an existing database with a
# user that has DB Owner permissions.
# Example: Server=mssql;Database=portal;User=portaluser;Password=secret;TrustServerCertificate=true
ConnectionStrings:AdminConnection=...
# The public URL under which Portal is reachable by clients
# (e.g. https://portal.example.com/Portal).
ServerUrl=https://...
# If Portal is served behind a reverse proxy that changes the base path,
# set this to the new relative path (e.g. /Portal).
RelativePath=/ (default)
# The TCP port on which the Kestrel web server listens.
# Only relevant when running as standalone (RunAsStandAlone=true).
ServerPort=5000 (default)
# UDiTH licence key for automatic activation on startup.
# This can also be configured later through the web interface.
LicenseKey=...
# DANGEROUS: Accept invalid TLS certificates for outgoing connections to
# Keycloak and licensing servers. Use only in test environments.
IgnoreCertificateErrors=false (default)
# When enabled, user names are included in server logs for HTTP requests and
# BBV sessions. Disable in environments where logging personal data is restricted.
ShowPII=false (default)
# Additional domains for which CORS Access-Control-Allow-Origin headers are
# returned. Use one entry per domain. Required when embedding Portal in an
# external website or calling the API from a different origin.
AccessControlAllowOrigin:[]=...
# Maximum size in bytes for any HTTP request body accepted by the server
# (Kestrel limit). If tus uploads are enabled, TusSettings:MaxRequestBodySizeClient
# must be smaller than or equal to this value, otherwise Portal will not start.
MaxRequestBodySizeServer=31457280 (default, 30 MiB)
# Periodically synchronise Keycloak user accounts with Portal (interval in
# milliseconds). Leave unset to disable periodic refresh.
AccountRefreshInterval=...

###############################################################################
# Proxy
###############################################################################

# If a forward proxy is required for outgoing connections to Keycloak or the
# licensing server, configure it here.
Proxy:Address=...
Proxy:UserName=...
Proxy:Password=...

###############################################################################
# Standalone HTTPS
###############################################################################

# When running without a reverse proxy, or when fully encrypted connections are
# required, you can terminate TLS directly in Kestrel. Provide either a PFX
# file (with password) or a PEM key and certificate pair. For PEM, a password
# is only required if the private key is encrypted.
StandaloneHttpsSettings:PfxFile=...
StandaloneHttpsSettings:PemKeyFile=...
StandaloneHttpsSettings:PemCertFile=...
StandaloneHttpsSettings:Password=...

###############################################################################
# Model Import (Central Model Repository)
###############################################################################

# Directory that is scanned for new model files to import.
ModelImport:ImportDirectory=/import (default)
# Directory where imported and processed model files are stored permanently.
ModelImport:ProviderStoragePath=/storage (default)
# Interval in milliseconds at which the import directory is scanned for new files.
ModelImport:IntervalInMilliseconds=5000 (default)

###############################################################################
# Model Processing
###############################################################################

# Globally disable processing (attribute extraction) of imported models.
# Models will still be imported, but no attributes will be written to the database.
ModelProcessing:ForcedSkipProcessing=false (default)
# Force reprocessing of previously failed model files (e.g. those marked as
# InvalidInput) after the given time in milliseconds. Leave unset to disable.
ModelProcessing:ForcedReprocessingTime=...

###############################################################################
# Model File Overwrites
###############################################################################

# Replace specific files inside every model during import. The key is the
# relative file path inside the model archive, the value is the path to the
# replacement file. Multiple entries can be added.
ModelFileOverwrites:Values:Data_default.upvf=/overwrittendefault.upvf

###############################################################################
# CMR Uploads
###############################################################################

# Enable the tus upload endpoint and the resumable upload client in the frontend.
# When enabled, large files are uploaded in chunks that can be resumed after
# interruptions.
TusSettings:TusEnabled=false (default)
# Directory where incomplete tus upload chunks are stored before processing.
TusSettings:StoreRootPath=... (default)
# Maximum size in bytes of a single upload chunk sent from client to server.
# Must be smaller than or equal to MaxRequestBodySizeServer, otherwise Portal
# will refuse to start.
TusSettings:MaxRequestBodySizeClient=20971520 (default, 20 MiB)
# Number of chunks uploaded in parallel from the client to the server.
# Values greater than 1 enable parallel chunk uploading, which can improve
# upload speed on high-bandwidth connections.
TusSettings:ParallelUploads=1 (default)
# Interval in milliseconds between cleanup runs that remove expired incomplete
# uploads from the tus storage directory.
TusSettings:CleanupInterval=900000 (default, 15 minutes)
# Time in milliseconds before an incomplete upload without activity is
# considered expired and eligible for cleanup.
TusSettings:SlidingExpiration=86400000 (default, 24 hours)

###############################################################################
# Frontend Customisation
###############################################################################

# Page title shown in the browser tab.
FrontendSettings:Title=UDiTH Portal (default)
# Show or hide the theme switcher in the user interface.
FrontendSettings:EnableThemeSelect=true (default)
# Theme applied when no user preference is set. Must be one of the values in
# AvailableThemes.
FrontendSettings:DefaultTheme=light (default)
# List of themes available for selection. Each entry is a theme name.
FrontendSettings:AvailableThemes:[]=light,dark
# Hide specific navigation menu items by key. Refer to the frontend source
# (nav-menu.definition.ts) for the list of available keys.
FrontendSettings:HiddenNavigation:[]=...
# URI scheme prefix used for the "Open locally" button. This is used to launch
# the local UDiTH application from the browser.
FrontendSettings:OpenLocallyPrefix=upvapi:// (default)
# When enabled, the external identifier and model version UID fields are
# read-only in the frontend and cannot be edited by users.
FrontendSettings:LockIdentifiers=false (default)

###############################################################################
# BBV / ICE Server
###############################################################################

# For BBV (Browser-Based Viewing), one or more ICE (STUN/TURN) servers must be
# configured so that WebRTC connections can be established between client and
# render server. Multiple ICE servers can be added by incrementing the array
# index.

# Authentication type for the ICE server. Currently only "password" is supported.
StreamingConfig:IceConfig:IceServers:[]:CredentialType=password (default)
# One or more STUN/TURN URLs. Most TURN servers require separate entries for
# UDP and TCP (e.g. turn:server:3478 and turn:server:3478?transport=tcp).
StreamingConfig:IceConfig:IceServers:[]:Urls:[]=turn:...
# Username for TURN server authentication.
StreamingConfig:IceConfig:IceServers:[]:Username=caxturn
# Password for TURN server authentication.
StreamingConfig:IceConfig:IceServers:[]:Credential=...

###############################################################################
# Logging (Serilog)
###############################################################################

# Serilog structured logging configuration. Logs can be written to console,
# files, and/or OpenTelemetry endpoints. Multiple sinks can be configured by
# incrementing the WriteTo array index.

# Enrich log entries with additional context (e.g. request IDs, user info).
Serilog:Enrich:0=FromLogContext
# Default minimum log level. Valid values: Verbose, Debug, Information, Warning,
# Error, Fatal.
Serilog:MinimumLevel:Default=Information
# Override log levels for specific namespaces to reduce noise.
Serilog:MinimumLevel:Override:Microsoft.AspNetCore.SignalR=Information
Serilog:MinimumLevel:Override:Microsoft=Warning
Serilog:MinimumLevel:Override:System=Warning
Serilog:MinimumLevel:Override:Windows=Warning
# Console sink — writes log output to stdout.
Serilog:WriteTo:0:Name=Console
# OpenTelemetry sink — forwards logs to an OTLP-compatible endpoint.
Serilog:WriteTo:1:Name=OpenTelemetry
Serilog:WriteTo:1:Args:Endpoint=https://...
Serilog:WriteTo:1:Args:IncludedData=157
Serilog:WriteTo:1:Args:Protocol=HttpProtobuf

###############################################################################
# OpenTelemetry (Metrics & Traces)
###############################################################################

# These are standard OpenTelemetry SDK environment variables. They are always
# provided as environment variables and have no hierarchical (`:`) form.

# OTLP endpoint for exporting metrics and traces.
OTEL_EXPORTER_OTLP_ENDPOINT=https://...
# Authorization header(s) for the OTLP endpoint.
OTEL_EXPORTER_OTLP_HEADERS=Authorization=...
# Protocol used for metric export.
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
# Interval in milliseconds at which metrics are exported.
OTEL_METRIC_EXPORT_INTERVAL=10000
# Additional resource attributes attached to all telemetry data
# (e.g. environment=production).
OTEL_RESOURCE_ATTRIBUTES=environment=...
# Service name reported in telemetry data.
OTEL_SERVICE_NAME=...

###############################################################################
# Advanced / Internal — Do not change these values unless instructed.
###############################################################################

# Duration in milliseconds after which a BBV watchdog session without heartbeat
# is considered gone and removed.
StreamingConfig:WatchdogSessionTimeOut=30000
# SignalR handshake timeout in milliseconds. Set to 0 to use the internal default.
StreamingConfig:ConnectionHandshakeTimeout=0
# Maximum SignalR hub message size in bytes. Set to 0 to use the internal
# default (32 KB). Increase only if you encounter message size errors.
StreamingConfig:MaximumReceiveMessageSize=0

# ZipArchive pool settings for model hosting. Controls how many ZipArchive
# instances are kept in memory for concurrent model file access.
# Minimum number of ZipArchive instances always kept in the pool.
ModelHosting:ZipArchivePoolMinSize=2
# Maximum number of ZipArchive instances allowed in the pool.
ModelHosting:ZipArchivePoolMaxSize=10
# Interval in milliseconds to check if the pool needs additional instances.
ModelHosting:ZipArchiveCreateDuration=1000
# Interval in milliseconds to check for and remove idle instances from the pool.
ModelHosting:ZipArchiveRemoveDuration=5000
# Run as standalone Kestrel web server (true) or behind IIS (false).
RunAsStandAlone=true (default)
# Automatically run database migrations on startup. When enabled, the database
# schema is created or updated to the current version.
RunMigrationsOnStartup=true (default)
```
