Configuration
The SCF Controls Platform runs in two ways, and configuration differs between them:
- Managed SaaS — a fully-managed application. Configuration is handled through the platform’s web interface; there are no environment files or server settings to manage. Most of this page covers these in-app settings.
- Self-hosted (open source) — you run the Docker Compose stack and configure it through a
.envfile thatscripts/install.shwrites for you. See Self-hosted environment variables below, and Deployment for the full install.
Self-hosted environment variables
Section titled “Self-hosted environment variables”Self-hosted deployments are configured through a .env file in the checkout. On first run
scripts/install.sh writes it for you, and it holds non-secret settings only. Every credential
the stack needs is generated by the installer into the secrets directory (SCF_SECRETS_DIR, one
0600 file per credential) and reaches each service as a file. You type no credential into .env
on the bundled path. See Credentials and secrets for what lands where, and
never commit .env.
Every credential also accepts a NAME_FILE variant (for example DB_PASSWORD_FILE) naming a file
that holds the value. The platform resolves each credential in the order database tier, then
NAME_FILE, then the plain environment variable. The plain variable in .env is the legacy
fallback: it keeps installs that predate the installer working, but it is not the first-run path.
Required
Section titled “Required”These are the credentials the stack cannot boot without. On a fresh install the installer
generates every one of them into SCF_SECRETS_DIR; you never choose, see or type a value.
| Variable | Written by the installer | Purpose |
|---|---|---|
DB_PASSWORD | Yes — generated for the bundled Postgres, or collected once for an external database | Postgres password; the backend builds its connection string from the DB_* settings plus this value. Legacy path: set it in .env |
API_KEY | Yes | Master backend API key. Legacy path: openssl rand -hex 32 into .env |
SCF_SECRET_KEY | Yes | Encrypts the integration credentials stored in the database. scripts/upgrade.sh generates it if absent and never overwrites it. Back it up |
DOWNLOAD_TOKEN_SECRET | Yes | Signs evidence download links; falls back to API_KEY when unset |
VITE_API_KEY | No | Copy of the API key baked into the frontend bundle at build time, so the browser can call the backend on the API-key sign-in path. Anyone who loads the page can read it, so it is not a secret. Installer-provisioned installs do not need it: the secrets overlay exposes $SCF_SECRETS_DIR to the frontend build, which reads API_KEY from it for the build step only (ignored when VITE_OIDC_ENABLED or VITE_GOOGLE_AUTH_ENABLED is true); rotating the key and running docker compose up -d --build frontend picks up the new value. Plain .env installs set it to the same value as API_KEY and rebuild the frontend after changing it (docker compose up -d --build frontend) |
| Variable | Default | Purpose |
|---|---|---|
SCF_SECRETS_DIR | (written by the installer) | Absolute host path of the credentials directory. docker-compose.secrets.yml, scripts/backup.sh and scripts/upgrade.sh all read it. Absent on a legacy .env install |
SCF_APP_GID | 1001 (written by the installer) | Linux only. The gid the containers reach host files through: the installer group-owns SCF_SECRETS_DIR (group read) and webclient/public/data (group write) to it, and the compose files hand it to group_add for the services that run as container root with cap_drop: ALL. 1001 is the gid of the backend image’s apiuser. Changing it means re-running scripts/install.sh — editing this line alone leaves SCF_SECRETS_DIR on the old gid. The next scripts/upgrade.sh run does pick the new value up for webclient/public/data, which it re-checks and re-groups on every upgrade, but it never touches the secrets directory. Ignored on macOS, where Docker Desktop remaps bind-mount ownership |
COMPOSE_FILE | docker-compose.yml:docker-compose.secrets.yml (written by the installer) | Compose file set. The secrets overlay is opt-in: on a legacy install the variable is absent and the base file runs alone. Setting it disables auto-discovery of docker-compose.override.yml, so add that file to the list if you use one |
ENVIRONMENT | production | development | staging | production. Only use development on a trusted local machine. Outside development and test the backend refuses to start on a missing or placeholder credential |
OSS_SINGLE_TENANT | 1 | Lets the master key admin a single org; fail-closed — disabled at startup if >1 org/member exists |
LOG_LEVEL | info | debug | info | warning | error |
CATALOG_VERSION | 2025.4 | SCF catalogue version surfaced on /version; match your imported workbook |
PLATFORM_VERSION | 0.40.0 | Fallback application version label; .env.example ships it aligned with webclient/package.json. Normally unused — the backend reads the real version from the mounted package.json, falling back to this only if that mount is missing (and to 0.0.0 if unset) |
MAX_UPLOAD_SIZE | 64m | Largest request body the frontend nginx proxies to the backend (client_max_body_size). Clears the backend’s own 50 MB cap on the SCF catalogue workbook. You should not need to change it — but see the note below if you run your own reverse proxy |
Database connection
Section titled “Database connection”The installer asks whether you want the bundled Postgres container or an external database
(scripts/install.sh, or the web installer’s Database step). It probes an external database
before it writes anything — DNS, TCP connect, authentication, TLS negotiation, server version,
database existence, and a real CREATE TABLE / DROP TABLE privilege check — and refuses to
continue if any of those fail. The values it accepts, whether entered as discrete fields or as a
connection string, are written to .env as the variables below; the wizard’s screens are shown on
First-run setup.
| Variable | Default | Purpose |
|---|---|---|
DB_HOST | postgres | Database host. postgres is the bundled container; set it to your own host for an external database |
DB_PORT | 5432 | Database port |
DB_NAME | cg_scf | Database name. It must already exist — the platform does not create it |
DB_USER | cg | Database role. It needs CREATE/DROP on the database: Alembic migrations run DDL on every upgrade |
DB_SSLMODE | (unset) | disable | allow | prefer | require | verify-ca | verify-full. Use require or stronger for any database reached over a network you do not control |
DB_PASSWORD | (generated / collected by the installer) | The role’s password. File-backed — see Required above |
DATABASE_URL | (unset) | A complete SQLAlchemy DSN, used verbatim when set and non-empty, overriding every DB_* variable above. The installer leaves it empty |
The backend composes its connection string from the DB_* variables whenever DATABASE_URL is
empty, URL-escaping the user and password for you. Prefer the components: they are what the
installer writes, what the credential file protects, and what keeps the password out of
docker inspect.
Authentication (Google OAuth — optional)
Section titled “Authentication (Google OAuth — optional)”Leave GOOGLE_AUTH_ENABLED=false to run with API-key auth only.
| Variable | Purpose |
|---|---|
GOOGLE_AUTH_ENABLED / VITE_GOOGLE_AUTH_ENABLED | Enable Google sign-in (backend + frontend must match) |
GOOGLE_CLIENT_ID / VITE_GOOGLE_CLIENT_ID | OAuth client ID (build-time copy baked into the frontend bundle) |
Identity provider (OIDC / bundled Keycloak — optional)
Section titled “Identity provider (OIDC / bundled Keycloak — optional)”Leave VITE_OIDC_ENABLED=false to keep Google / API-key auth. Set it to true to authenticate via
OIDC single sign-on — either the bundled Keycloak (docker compose --profile idp up -d) or your own
provider. The KC_* variables apply only when the bundled idp profile is running. See
Identity Provider for the full setup, the ISSUER-vs-DISCOVERY
footgun, and troubleshooting. The localhost defaults below only work when your browser runs on
the Docker host itself — on a remote host, set OIDC_ISSUER, OIDC_REDIRECT_URI, and
KC_HOSTNAME to the host’s reachable address (see
Deploying on a remote host).
| Variable | Default | Purpose |
|---|---|---|
VITE_OIDC_ENABLED | false | Frontend: use redirect-based OIDC sign-in instead of Google. Build-time (baked into the frontend image) |
OIDC_ISSUER | http://localhost:8081/realms/scf | PUBLIC issuer; must byte-match the token iss claim and be browser-reachable |
OIDC_DISCOVERY_URL | http://keycloak:8080/realms/scf | INTERNAL realm base the backend fetches (bare base, no /.well-known suffix) |
OIDC_CLIENT_ID | scf-platform | OIDC client ID |
OIDC_CLIENT_SECRET | (generated for bundled Keycloak, or collected for an external provider, by the installer into a 0600 file) | Confidential client secret; idp-init writes it into Keycloak at boot. Legacy path: replace the changeme-generate-a-real-oidc-secret placeholder in .env |
OIDC_REDIRECT_URI | http://localhost:5173/api/auth/callback | OAuth callback URI (must be registered on the client) |
OIDC_SCOPES | openid email profile | Requested scopes |
KC_ADMIN_USER | admin | Keycloak admin user — REQUIRED with --profile idp. Also read by the backend service to provision invited users; see Provisioning invited users |
KC_ADMIN_PASSWORD | (generated by the installer into a 0600 file; never shown) | Keycloak admin password — REQUIRED with --profile idp, and read by the backend service for the same reason. Legacy path: replace the changeme-keycloak-admin placeholder in .env |
KC_ADMIN_PASSWORD_FILE | (set by the secrets overlay to /run/secrets/KC_ADMIN_PASSWORD) | Path to a file holding the password. Takes precedence over KC_ADMIN_PASSWORD; you do not set this by hand |
KC_HOSTNAME | http://localhost:<KEYCLOAK_PORT> | Public base URL Keycloak advertises; default follows a remapped KEYCLOAK_PORT. Set explicitly for remote hosts or a reverse proxy |
BOOTSTRAP_ADMIN_EMAIL | (blank) | If set, idp-init seeds this platform admin with a one-time random temp password printed to the idp-init logs |
Provisioning invited users
Section titled “Provisioning invited users”KC_ADMIN_USER and KC_ADMIN_PASSWORD were only ever read by idp-init, which uses them once to
build the realm. The backend service now reads them too. When both resolve and an OIDC realm is
configured (OIDC_DISCOVERY_URL or OIDC_ISSUER), inviting a user also creates that user in the
bundled Keycloak with a one-time temporary password, which is returned in the invite API response
and included in the invitation email when Resend is enabled. Keycloak requires the invitee to
replace it at first sign-in.
The backend resolves the password the same way it resolves every other credential: the path in
KC_ADMIN_PASSWORD_FILE first, then the environment variable. It is never read from the
database — KC_ADMIN_PASSWORD is closed to the integration-secrets table by construction, so a row
stored under that name cannot become the credential that controls your realm. It is not exposed in
any API response other than the temporary password itself, and never written to the frontend bundle.
Email notifications (Resend — optional)
Section titled “Email notifications (Resend — optional)”Outbound email is off until a Resend API key is present. The key is a tier-3 integration
credential: add it under Settings, Integrations (see Integrations).
Setting RESEND_API_KEY in .env is the legacy fallback and still works.
| Variable | Purpose |
|---|---|
RESEND_API_KEY | Resend API key for outbound notification email — legacy .env fallback; prefer Settings, Integrations |
RESEND_FROM_EMAIL | From address on notification emails |
APP_URL | Public frontend URL used in email links |
Scheduled GRC automation (optional)
Section titled “Scheduled GRC automation (optional)”The backend runs daily Celery beat jobs that generate evidence collection tasks, send due/overdue task notifications, and refresh stale evidence windows. Both flags default to on; set to false (or 0) to opt out.
| Variable | Default | Purpose |
|---|---|---|
TASK_AUTOMATION_ENABLED | true | Daily evidence-task generation plus due and overdue notification jobs |
WINDOW_ASSESSMENT_NIGHTLY_ENABLED | true | Nightly sweep that refreshes stale evidence window assessments. Uploads and webhook deliveries also trigger an assessment directly; see WINDOW_ASSESSMENT_ON_INGEST below |
Evidence window assessment
Section titled “Evidence window assessment”The window assessor scores every file collected inside a frequency-derived window as one portfolio. These knobs shape what it sends to the model and when it runs.
| Variable | Default | Purpose |
|---|---|---|
ARTIFACT_TYPE_LAZY_EXTRACTION | true | A fresh install ships the catalog with no required artifact types per control. When this is on, the first window assessment that needs a control’s artifact types extracts them once (one ARTIFACT_TYPE_AI_MODEL call per control) and caches the result on the catalog row. Controls that were attempted are not re-tried, and an extraction failure never blocks the assessment. Set to false to use only what the backfill CLI (backend/scripts/extract_artifact_types.py) has populated |
WINDOW_ASSESSMENT_TEXT_BUDGET | 150000 | Character budget for the evidence text in one window prompt. Identical collector payloads are deduplicated before the budget is applied, and anything dropped is disclosed in the assessment’s coverage findings |
WINDOW_ASSESSMENT_ON_INGEST | true | A browser upload or webhook delivery schedules the window assessment for that evidence item instead of waiting for the nightly sweep. Only tracked evidence items (those with a collection frequency) are scheduled. Set to false to rely on the sweep alone |
WINDOW_ASSESSMENT_INGEST_DEBOUNCE_SECONDS | 120 | How long the assessor waits after an ingest before running, so deliveries arriving inside the interval collapse into one assessment that sees all of them. The debounce is held in Redis; if Redis is unavailable the assessment is still scheduled |
Assurance and KSI feature flags
Section titled “Assurance and KSI feature flags”Four flags decide which assessment layer the platform treats as primary. All default on: the
windowed, record-level AI assessment is the primary assessment surface and the per-file assessor is
the diagnostic layer beneath it (see the AI evidence assessment
guide). Set the backend flags on both the backend and celery-worker services; the two answer
the same questions and a flag set on only one produces two different scores for the same
organisation.
| Variable | Default | Purpose |
|---|---|---|
ENABLE_PER_WINDOW_REVIEW | true | Per-window review: window verdicts fill the Awaiting confirmation queue, the window review panel appears on the evidence page and the Frequency Health tile on the dashboard. With it on, the per-file document review endpoint answers 410 Gone (with a Sunset header and a pointer to the window review endpoint) for any evidence item that already has a window assessment; evidence with no window assessment yet still accepts per-file review |
VITE_ENABLE_PER_WINDOW_REVIEW | true | The frontend’s build-time twin of the flag above. It is baked into the bundle: change it with docker compose up -d --build frontend, never with a restart. The app compares it against GET /api/features at startup and logs a mismatch to the browser console; a bundle built with it off against a backend with it on leaves reviewers with no working review path |
ENABLE_WINDOW_ASSESSMENT_KSI | true | The Evidence Quality axis reads window verdicts in preference to per-file verdicts for evidence that has a window assessment |
ENABLE_COMPOSITE_KSI | true | The Evidence Quality axis reads the per-control composite (the roll-up of window verdicts across a control’s evidence) in preference to both. Independent of the window flag: composite on and window off falls back to per-file for controls with no composite |
Only the literal value true (any case) turns a backend flag on, and an unset or empty value takes
the default. Turning any of them off is an opt-out for a deployment that wants to stay on per-file
review; it does not remove the window assessments already stored.
Evidence storage
Section titled “Evidence storage”Start here: most installations should not use these variables at all. Evidence storage is configured in the application, under Settings, Evidence storage, where a platform administrator sets a store for the whole installation and an organisation administrator can point their own organisation at a store of its own. Those configurations live in the database, hold their credentials encrypted, and can be changed without restarting anything.
The variables below are the fallback beneath that. When an organisation has no store of its own and the installation has no platform store either, the backend synthesises one from this environment so that installations predating the settings screen keep working untouched. Anything configured in the application wins over anything set here.
The normal path for an installation holding real evidence is a bucket of your own: install with
./scripts/install.sh --no-minio so no object store is bundled at all — the minio and minio-init
services never start and the stack runs without them — then configure the store from the application,
or set the S3 variables below. See
Deployment → Evidence storage.
Left alone, the stack falls back to the bundled MinIO container so a first run needs no cloud account. That store is an evaluation and pilot path only: MinIO archived its community edition in April 2026 and the shipped image carries unpatched advisories with no community fix — see the troubleshooting guide.
| Variable | Default | Purpose |
|---|---|---|
COMPOSE_PROFILES | (written by the installer) | Contains storage when the bundled MinIO is part of this stack. Without it minio and minio-init never start. May also contain idp, as idp,storage |
EVIDENCE_STORAGE_BOOTSTRAP | (empty) | bundled_minio or none, written by the installer. COMPOSE_PROFILES is read on the host and never reaches a container, so this is how the backend learns which object store it has. bundled_minio makes it seed the platform storage configuration on first boot |
AWS_ENDPOINT_URL | http://minio:9000 | Internal S3 endpoint; blank = use real AWS S3. A --no-minio install is written blank |
EVIDENCE_PUBLIC_ENDPOINT | http://localhost:9000 | Browser-facing endpoint for presigned URLs |
EVIDENCE_BUCKET | evidence | Bucket name. Blank on a --no-minio install, which is what makes the platform report itself as having no evidence storage rather than pointing at an address where nothing is listening |
MINIO_ROOT_USER / MINIO_ROOT_PASSWORD | (generated by the installer into 0600 files) | Bundled MinIO credentials. Legacy path: replace the minioadmin / changeme-… placeholders in .env; the backend refuses to start on them |
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | (generated by the installer — a pair of its own, not the MinIO root credentials) | S3 credentials the backend uses. On the bundled path minio-init creates a MinIO user for this pair whose policy names the evidence bucket and nothing else, so a leaked application credential is not the object store’s root account. For real AWS S3, put your own values in the two files (or in .env on the legacy path) |
AWS_DEFAULT_REGION | eu-west-1 | S3 region |
AWS_SESSION_TOKEN | (unset) | Optional third credential, for temporary credentials issued by AWS STS. Read the same file-first way as the key pair. Leave unset for long-lived keys |
AZURE_STORAGE_ACCOUNT_NAME / AZURE_STORAGE_ACCOUNT_KEY | — | Retired and ignored. Azure Blob is no longer a storage backend. Setting these selects nothing; the backend logs a warning and carries on with the store it would otherwise have used. See the note below |
EVIDENCE_CONTAINER | evidence | Retired and ignored, with AZURE_STORAGE_* |
Optional integrations
Section titled “Optional integrations”The API keys in this table are tier-3 integration credentials, managed encrypted in the database from
Settings, Integrations (see Integrations). The .env variable is the
legacy fallback, read only when nothing is stored in the database or in a NAME_FILE file.
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY | Enables AI-assisted evidence / window assessment and AI vendor assessments. Must be set on the Celery worker for vendor assessments; without it the vendor assessment engine runs in mock mode and returns a clearly marked sample report |
VENDOR_AI_MODEL | Claude model for vendor assessments — see AI model selection |
VENDOR_AI_MOCK | Set to 1 to force mock vendor assessments even when an API key is configured |
HIBP_API_KEY, NVD_API_KEY | Third-party breach / vulnerability lookups for vendor research |
APPLICATIONINSIGHTS_CONNECTION_STRING | Telemetry export |
SCF_XLSX | Path to your SCF workbook for the catalogue importer (default ./catalog-source/scf.xlsx) |
AI model selection
Section titled “AI model selection”Every AI feature resolves its model through a single registry
(backend/services/model_registry.py). No model id is hard-coded at a call
site, so repointing a model is an environment change, not a deploy.
One variable moves the platform. Set SCF_AI_MODEL and every compliance
role follows it: evidence assessment, artifact-type extraction, vendor
assessment, system recipe generation and AI-augmented document generation.
Per-role overrides beat the global. Each role also has its own variable,
for holding one service back or pushing one forward (“everything on the new
model except doc-gen, which regressed”). Precedence: per-role variable, then
SCF_AI_MODEL, then the built-in default.
| Variable | What the feature does | Default |
|---|---|---|
EVIDENCE_AI_MODEL | AI evidence assessment: reads an uploaded evidence file and answers each SCF assessment objective of its mapped controls with an advisory designation and rationale; also drives per-window portfolio assessments. A human reviewer confirms or overrides every suggestion | claude-opus-5 |
ARTIFACT_TYPE_AI_MODEL | Artifact-type extraction: derives the artifact types (policy, screenshot, export, report) a control expects. Runs lazily from the window assessor on first use (see ARTIFACT_TYPE_LAZY_EXTRACTION) and from the backfill CLI | claude-sonnet-4-6 |
VENDOR_AI_MODEL | Vendor assessment: the vendor assessment engine researches a third-party vendor with web search and drafts the security / data-protection assessment report | claude-sonnet-4-6 |
SYSTEMS_AI_MODEL | System recipe generation: produces the L1–L4 evidence-collection recipes for a system, grounded in the vendor’s real admin console and APIs | claude-sonnet-4-6 |
DOC_GEN_AI_MODEL | AI-augmented document generation: writes Tier-2 ISMS documents (domain policies, procedures, standards) from scoped control data. Tier-1 documents are template-rendered and never call a model | claude-sonnet-4-6 |
Notes:
- Defaults are not uniform. Evidence assessment defaults to a stronger
(and more expensive) model than the other roles, so setting
SCF_AI_MODELflattens every role onto one id — use a per-role override to keep a role apart. - Unregistered ids are honoured, with a warning. An id not declared in the registry is still sent to the provider — production must be able to escape a bad default without a deploy — but its per-assessment cost is recorded as NULL rather than guessed, and the weekly model-liveness check cannot vouch for it.
- Cost-tracked roles need a priced model. Evidence assessment and artifact-type extraction write a cost figure per run; their registry defaults must declare a price (enforced in CI).
- Recreate, don’t restart. A model change takes effect on container
recreation (
docker compose up -d --force-recreate backend celery-worker);docker compose restartreuses the old environment and will not pick it up.
Platform Settings
Section titled “Platform Settings”Organisation Settings
Section titled “Organisation Settings”Organisation administrators can configure:
| Setting | Description | Access |
|---|---|---|
| Organisation Name | Display name for your organisation | Admin only |
| Primary Framework | Default compliance framework for dashboard metrics | Admin only |
| User Roles | Assign roles to team members | Admin only |
User Preferences
Section titled “User Preferences”Individual users can configure:
| Setting | Description |
|---|---|
| Notification Preferences | Email notification settings |
| Display Preferences | UI preferences (if available) |
Authentication
Section titled “Authentication”By default a self-hosted install authenticates with the master API_KEY, which the installer
generates into the secrets directory (it lives in .env only on a legacy install) — no external
identity provider is required. Optional OIDC single sign-on and Google Sign-In can be
enabled on top. See Authentication for the full setup of each
method.
Google Sign-In flow (when enabled)
Section titled “Google Sign-In flow (when enabled)”- User clicks “Sign in with Google”
- Google authenticates the user
- Platform receives user identity (email, name, profile picture)
- User is granted access based on their organisation membership
Any Google account type works: Google Workspace, personal Gmail, or Google Cloud Identity.
Email Notifications
Section titled “Email Notifications”The platform sends email notifications for:
| Notification Type | Trigger |
|---|---|
| User Invitations | When invited to join an organisation |
| Task Assignment | When assigned to a control or task |
| Due Reminders | Before task due dates |
| Overdue Alerts | When tasks pass their due date |
| @Mentions | When mentioned in comments |
Data Storage
Section titled “Data Storage”Where Your Data Lives
Section titled “Where Your Data Lives”On a self-hosted install, all data lives in your own infrastructure:
- PostgreSQL (bundled container or your own instance) — the system of record
- Object storage — evidence files in an S3-compatible store of your own, or the bundled MinIO while you evaluate
- Backups are your responsibility — see Backup & Restore
The bundled combination is the only one the shipped scripts back up in full.
scripts/upgrade.sh (and scripts/backup.sh) dump the bundled Postgres container and tar the
bundled MinIO volume. Choose an external database or external object storage and that store
falls outside what they capture — silently, and without an error. Back it up yourself before you
rely on either script. That is a reason to configure your provider’s own protection when you move
off the bundled stores, not a reason to stay on them. See
what the scripts do not cover.
Data Retention
Section titled “Data Retention”You control retention entirely: data persists in your database and object store until you delete it, and you can export or back up at any time.
Security Configuration
Section titled “Security Configuration”Access Control
Section titled “Access Control”| Feature | Description |
|---|---|
| API key / OIDC / Google OAuth | Authentication methods — see Authentication |
| Role-Based Access | Admin, Editor, Viewer roles (enforcement coming soon) |
| Organisation Isolation | Each organisation’s data is completely separate |
Security Features
Section titled “Security Features”- HTTPS Only — All connections are encrypted
- OAuth 2.0 — Industry-standard authentication
- Session Management — Automatic session timeout for security
- Audit Logging — All actions are logged for compliance
Integration Settings
Section titled “Integration Settings”Current Integrations
Section titled “Current Integrations”The platform currently supports:
| Integration | Purpose |
|---|---|
| Google Sign-In | User authentication |
| Email (Resend) | Notification delivery |
Future Integrations
Section titled “Future Integrations”Single Sign-On (SSO) via OIDC has shipped — see Identity Provider for bundled Keycloak or bring-your-own-provider setup.
Additional integrations are planned for future releases:
- SIEM/SOAR integration
- Ticketing system integration (Jira, ServiceNow)
- API access for automation
Backup Configuration
Section titled “Backup Configuration”Backup Features
Section titled “Backup Features”Access under Settings, Backups in the web interface (the Tenant Export / Import card):
| Feature | Description |
|---|---|
| Download Tenant Export | Export one organisation’s working data as a JSON file |
| Import Tenant Data | Upload a previous export, review the preview, then confirm |
Backup Contents
Section titled “Backup Contents”Backups include:
- All scoped controls and their status
- Evidence tracking configurations
- Users and organisation settings
- Assignments, comments, and tasks
- Notification history
What’s Not Included
Section titled “What’s Not Included”This list describes the in-app JSON export, which is a partial tenant export, not a disaster-recovery backup. It omits:
- SCF catalog data (this is reference data provided by the platform)
- System configuration (managed by the platform)
- Evidence files, the audit log, audit engagements, evidence assessments, generated documents, vendors, teams, custom risk definitions — and 26 other organisation-scoped tables
- The credentials directory (
SCF_SECRETS_DIR) andSCF_SECRET_KEY, without which a restored database cannot decrypt its stored integration credentials
For a backup that covers the whole database, the evidence volume and the credentials together, use
scripts/backup.sh — see Backup & Restore.
Version Information
Section titled “Version Information”Checking Your Version
Section titled “Checking Your Version”The platform version is displayed:
- In the footer of each page
- From
GET /api/version
Version Components
Section titled “Version Components”| Component | Description |
|---|---|
| Platform Version | Application version number |
| API Version | Backend API version |
| Catalog Version | SCF Controls Catalog version |
Support Configuration
Section titled “Support Configuration”Getting Help
Section titled “Getting Help”| Resource | Purpose |
|---|---|
| This Documentation | Self-service help and guides |
| In-App Support | Contact support from within the platform |
| Email Support | support@scfcontrolsplatform.com |
Reporting Issues
Section titled “Reporting Issues”When reporting issues, include:
- Browser type and version
- Steps to reproduce the problem
- Any error messages shown
- Screenshots if applicable
Related Guides
Section titled “Related Guides”- Authentication — Sign-in and account management
- User Management — Managing users and roles
- Backup & Restore — Data backup procedures

