Configuration Examples and Reference

This document provides minimal, working configuration examples for all SYNDI components. These examples serve as starting points for new deployments.

Quick Reference

Lambda Configuration Files (Backend)

Base Configuration File

Location: infra/.config/lambda/{env}.json

This is the base configuration shared by all organizations in an environment.

{
  "lambda": {
    "auth": {
      "provider": "cognito",
      "required": true,
      "cognito": {
        "region": "us-east-1"
      }
    },
    "file_uploads": {
      "max_file_size_mb": 25,
      "max_total_upload_size_mb": 100,
      "max_files_per_upload": 10,
      "allowed_extensions": [
        ".pdf", ".doc", ".docx", ".txt", 
        ".xls", ".xlsx", ".csv", 
        ".png", ".jpg", ".jpeg"
      ],
      "forbidden_extensions": [
        ".exe", ".bat", ".sh", ".php", ".js"
      ],
      "temp_storage_retention_days": 7
    },
    "retry": {
      "max_retries": 3,
      "backoff_multiplier": 2
    },
    "cors": {
      "allowedOrigins": [
        "http://localhost:3000",
        "http://localhost:5173"
      ]
    },
    "server": {
      "host": "0.0.0.0",
      "port": 8000
    }
  }
}

Organization-Specific Override File

Location: infra/.config/lambda/{env}-{org}.json

Organization-specific settings that override the base configuration.

{
  "lambda": {
    "email_settings": {
      "from_email": "noreply@yourorg.edu",
      "support_email": "support@yourorg.edu",
      "invitation_subject": "Welcome to SYNDI Laboratory System"
    },
    "file_uploads": {
      "max_file_size_mb": 50
    },
    "cors": {
      "allowedOrigins": [
        "https://syndi.yourorg.edu",
        "http://localhost:3000"
      ]
    },
    "private_webapp": {
      "auth": {
        "service": {
          "accounts": [
            {
              "service_id": "ci_pipeline",
              "service_name": "CI/CD Pipeline",
              "api_key": "REPLACE-WITH-SECURE-KEY",
              "groups": ["service"],
              "permissions": ["submit:*", "view:*"],
              "is_admin": false
            }
          ]
        }
      }
    }
  }
}

Generate secure API key:

openssl rand -hex 32

Webapp Configuration Files (Frontend)

Base Webapp Config

Location: infra/.config/webapp/{env}.json

{
  "webapp": {
    "apiEndpoint": "TO_BE_FILLED_BY_SYNC_CONFIGS",
    "auth": {
      "required": true,
      "provider": "cognito",
      "cognito": {
        "region": "us-east-1",
        "userPoolId": "TO_BE_FILLED_BY_SYNC_CONFIGS",
        "clientId": "TO_BE_FILLED_BY_SYNC_CONFIGS"
      },
      "session": {
        "timeout": 3600000,
        "refreshBuffer": 300000
      }
    },
    "autosave": {
      "enabled": true,
      "storage": {
        "type": "localStorage",
        "keyPrefix": "claire-autosave",
        "maxItems": 50,
        "ttl": 86400000
      },
      "timerDelayMs": 15000,
      "ui": {
        "showStatus": true,
        "toastOnSave": false,
        "toastOnError": true
      }
    }
  }
}

Note: Infrastructure values (apiEndpoint, userPoolId, clientId) are filled by sync-configs.

Organization Frontend Config

Location: infra/.config/webapp/{env}-{org}.json

{
  "webapp": {
    "branding": {
      "title": "SYNDI Laboratory System",
      "org_name": "Your Organization"
    },
    "ui": {
      "theme": "light",
      "logo": "/assets/logo.png"
    }
  }
}

Minimal SOP Example

Location: Upload to S3 bucket rawscribe-forms-{env}-{org}-{accountid}/sops/

'@context': https://schema.org
'@type': SoftwareApplication
id: TEST_001
name: "Test SOP"
title: "Test Standard Operating Procedure"
version: "1.0.0"
author: "Lab Manager"
date-published: "2024-01-01"

taskgroups:
  - id: main_group
    name: "Main"
    ordinal: 1
    children:
      - id: task_1
        '@type': Task
        name: "Sample Collection"
        ordinal: 1
        children:
          - id: sample_id
            '@type': Field
            name: "Sample ID"
            type: "string"
            required: true
            ui_config:
              placeholder: "Enter sample ID"
              help_text: "Unique identifier for this sample"
          - id: collection_date
            '@type': Field
            name: "Collection Date"
            type: "date"
            required: true
            ui_config:
              help_text: "Date sample was collected"
          - id: sample_notes
            '@type': Field
            name: "Notes"
            type: "text"
            required: false
            ui_config:
              multiline: true
              rows: 4

Upload to S3:

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws s3 cp test-sop.yaml \
  s3://rawscribe-forms-stage-myorg-${ACCOUNT_ID}/sops/

Important Configuration Principles

What Goes in JSON Config Files

Application behavior settings:

  • File upload limits (max_file_size_mb)

  • Retry policies (max_retries, backoff_multiplier)

  • Email settings (from_email, support_email)

  • UI preferences (theme, showStatus)

  • Feature flags (autosave.enabled)

  • CORS allowed origins

  • Service account configurations

  • Timeout values

  • Session durations

What Does NOT Go in JSON Config Files

Infrastructure values (these come from CloudFormation outputs → environment variables):

  • S3 bucket names

  • Cognito User Pool IDs

  • Cognito Client IDs

  • API Gateway endpoints

  • Lambda function names

  • CloudFront distribution IDs

  • Any CloudFormation outputs

Why: Infrastructure values are deployment-specific and managed by CloudFormation. They’re automatically set as Lambda environment variables and synced to configs via sync-configs.

Configuration Hierarchy

Configuration is resolved in this order (highest to lowest priority):

  1. CloudFormation Outputs → Lambda environment variables

  2. Org-specific config ({env}-{org}.json) - Organization overrides

  3. Base config ({env}.json) - Environment defaults

  4. Application defaults - Hardcoded in code

Example resolution for API endpoint:

1. Check Lambda env var: API_ENDPOINT
2. Check org config: webapp.apiEndpoint (from stage-myorg.json)
3. Check base config: webapp.apiEndpoint (from stage.json)
4. Use default: http://localhost:8000 (development fallback)

Configuration Merge Process

Step 1: Base + org-specific merge (via config-merger.py)

infra/.config/lambda/stage.json (base)
  + infra/.config/lambda/stage-myorg.json (override)
  = backend/rawscribe/.config/config.json (merged)

Step 2: CloudFormation sync (via sync-configs)

CloudFormation outputs
  → infra/.config/webapp/stage-myorg.json (updated)
  → infra/.config/lambda/stage-myorg.json (updated)

Step 3: Runtime loading

Lambda: Reads env vars first, falls back to config.json
Frontend: Reads merged config.json from public/

Complete Configuration Examples

Development Environment

Base Lambda Config (infra/.config/lambda/dev.json):

{
  "lambda": {
    "auth": {
      "provider": "mock",
      "required": true,
      "users": [
        {
          "id": "dev_user",
          "email": "dev_user@local.dev",
          "username": "dev_user",
          "password": "dev123",
          "name": "Development User",
          "groups": ["admin"],
          "permissions": ["*"],
          "isAdmin": true
        }
      ]
    },
    "storage": {
      "type": "local",
      "local_path": "../.local/s3",
      "draft_bucket_name": "eln-drafts",
      "eln_bucket_name": "eln",
      "forms_bucket_name": "forms"
    },
    "server": {
      "host": "0.0.0.0",
      "port": 8000
    }
  }
}

Base Webapp Config (infra/.config/webapp/dev.json):

{
  "webapp": {
    "apiEndpoint": "http://localhost:8000",
    "authRequired": true,
    "auth": {
      "provider": "mock"
    },
    "storage": {
      "type": "local"
    }
  }
}

Staging Environment

Base Lambda Config (infra/.config/lambda/stage.json):

{
  "lambda": {
    "auth": {
      "provider": "cognito",
      "required": true,
      "cognito": {
        "region": "us-east-1"
      }
    },
    "file_uploads": {
      "max_file_size_mb": 25,
      "allowed_extensions": [".pdf", ".doc", ".txt", ".xls", ".xlsx"]
    },
    "storage": {
      "type": "s3",
      "region": "us-east-1"
    }
  }
}

Org-Specific Override (infra/.config/lambda/stage-myorg.json):

{
  "lambda": {
    "email_settings": {
      "from_email": "noreply@myorg.edu",
      "support_email": "support@myorg.edu"
    },
    "file_uploads": {
      "max_file_size_mb": 50
    },
    "auth": {
      "cognito": {
        "userPoolId": "us-east-1_ABC123",
        "clientId": "abc123def456"
      }
    }
  }
}

Note: Cognito IDs automatically filled by sync-configs.

Production Environment

Base Lambda Config (infra/.config/lambda/prod.json):

{
  "lambda": {
    "auth": {
      "provider": "cognito",
      "required": true,
      "cognito": {
        "region": "us-east-1"
      }
    },
    "file_uploads": {
      "max_file_size_mb": 25,
      "allowed_extensions": [".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".csv"],
      "forbidden_extensions": [".exe", ".bat", ".sh"],
      "temp_storage_retention_days": 30
    },
    "retry": {
      "max_retries": 5,
      "backoff_multiplier": 2
    },
    "cors": {
      "allowedOrigins": [
        "https://syndi.production-domain.com"
      ]
    }
  }
}

Field Descriptions

Lambda Config Fields

file_uploads:

  • max_file_size_mb - Maximum size per file (MB)

  • max_total_upload_size_mb - Maximum total upload size (MB)

  • max_files_per_upload - Maximum number of files per request

  • allowed_extensions - List of permitted file extensions

  • forbidden_extensions - List of blocked file extensions

  • temp_storage_retention_days - Days to keep temporary files

retry:

  • max_retries - Maximum retry attempts for failed operations

  • backoff_multiplier - Exponential backoff multiplier

  • initialDelay - Initial delay before first retry (ms)

cors:

  • allowedOrigins - Array of permitted CORS origins

auth.cognito:

  • region - AWS region (e.g., “us-east-1”)

  • userPoolId - Cognito User Pool ID (auto-filled by sync-configs)

  • clientId - Cognito App Client ID (auto-filled by sync-configs)

email_settings:

  • from_email - Email sender address

  • support_email - Support/reply-to address

  • invitation_subject - Subject for user invitation emails

  • use_ses - Use AWS SES for emails (true/false)

private_webapp.auth.service.accounts:

  • service_id - Unique service identifier

  • service_name - Human-readable service name

  • api_key - Secure API key (generate with openssl rand -hex 32)

  • groups - Array of group memberships

  • permissions - Array of permission strings

  • is_admin - Boolean admin flag

Webapp Config Fields

branding:

  • title - Application title (browser tab)

  • org_name - Organization display name

ui:

  • theme - UI theme (“light” or “dark”)

  • logo - Path to logo image

auth.session:

  • timeout - Session timeout (milliseconds)

  • refreshBuffer - Time before expiry to refresh token (ms)

autosave:

  • enabled - Enable autosave (true/false)

  • storage.type - Storage type (“localStorage”, “sessionStorage”, “api”)

  • storage.keyPrefix - Prefix for storage keys

  • storage.maxItems - Maximum autosave items

  • storage.ttl - Time to live (milliseconds)

  • timerDelayMs - Delay before autosave triggers (ms)

  • ui.showStatus - Show autosave status indicator

  • ui.toastOnSave - Show toast notification on save

  • ui.toastOnError - Show toast on error

Minimal SOP Example

Location: Upload to S3 bucket rawscribe-forms-{env}-{org}-{accountid}/sops/

'@context': https://schema.org
'@type': SoftwareApplication
id: TEST_001
name: "Test SOP"
title: "Test Standard Operating Procedure"
version: "1.0.0"
author: "Lab Manager"
date-published: "2024-01-01"

taskgroups:
  - id: main_group
    name: "Main"
    ordinal: 1
    children:
      - id: task_1
        '@type': Task
        name: "Sample Collection"
        ordinal: 1
        children:
          - id: sample_id
            '@type': Field
            name: "Sample ID"
            type: "string"
            required: true
            ui_config:
              placeholder: "Enter sample ID"
              help_text: "Unique identifier for this sample"
          - id: collection_date
            '@type': Field
            name: "Collection Date"
            type: "date"
            required: true
            ui_config:
              help_text: "Date sample was collected"
          - id: sample_type
            '@type': Field
            name: "Sample Type"
            type: "select"
            required: true
            ui_config:
              options:
                - value: "blood"
                  label: "Blood"
                - value: "tissue"
                  label: "Tissue"
                - value: "cell_culture"
                  label: "Cell Culture"
          - id: sample_notes
            '@type': Field
            name: "Notes"
            type: "text"
            required: false
            ui_config:
              multiline: true
              rows: 4
              placeholder: "Additional notes about the sample"

Upload to S3:

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws s3 cp test-sop.yaml \
  s3://rawscribe-forms-stage-myorg-${ACCOUNT_ID}/sops/

# Verify upload
aws s3 ls s3://rawscribe-forms-stage-myorg-${ACCOUNT_ID}/sops/

Important Configuration Principles

What Goes in JSON Config Files

Application behavior settings:

  • File upload limits

  • Retry policies

  • Email settings

  • UI preferences

  • Feature flags

  • CORS origins

  • Service accounts

  • Timeout values

  • Autosave settings

What Does NOT Go in JSON Config Files

Infrastructure values (these come from CloudFormation):

  • S3 bucket names

  • Cognito User Pool IDs

  • Cognito Client IDs

  • API Gateway endpoints

  • Lambda function names

  • CloudFront distribution IDs

  • Any CloudFormation outputs

Why: Infrastructure values vary by deployment and are managed by CloudFormation. They’re:

  1. Output by CloudFormation stack

  2. Set as Lambda environment variables

  3. Synced to config files via sync-configs

Configuration Hierarchy

  1. Base config ({env}.json) - Shared settings for all organizations

  2. Org override ({env}-{org}.json) - Organization-specific overrides

  3. Environment variables - Infrastructure values from CloudFormation

  4. Runtime merge - ConfigLoader.py merges all sources

Deep Merge Example

Base (stage.json):

{
  "lambda": {
    "file_uploads": {
      "max_file_size_mb": 25,
      "allowed_extensions": [".pdf", ".doc"]
    }
  }
}

Override (stage-myorg.json):

{
  "lambda": {
    "file_uploads": {
      "max_file_size_mb": 50
    },
    "email_settings": {
      "from_email": "noreply@myorg.com"
    }
  }
}

Merged Result:

{
  "lambda": {
    "file_uploads": {
      "max_file_size_mb": 50,
      "allowed_extensions": [".pdf", ".doc"]
    },
    "email_settings": {
      "from_email": "noreply@myorg.com"
    }
  }
}

Key points:

  • max_file_size_mb overridden (50 not 25)

  • allowed_extensions preserved from base

  • email_settings added from override