(configuration)=
# Configuration

This guide provides comprehensive information about configuring NexusLIMS through environment variables. All configuration is managed through the centralized `nexusLIMS.config` module, which uses [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) for validation and type safety.

## Configuration Files

NexusLIMS loads configuration from environment variables and optionally from a `.env` file in the same folder from which you run any NexusLIMS commands.

(configuration-management)=
## Configuration Management

NexusLIMS provides both CLI tools and an interactive terminal UI to help you manage, debug, and migrate your configurations between environments.

### Interactive Configuration Editor (TUI)

The **NexusLIMS Configuration Editor** provides a user-friendly terminal interface for editing your `.env` file:

```bash
# Launch the interactive configurator
nexuslims config edit

# Edit a specific .env file
nexuslims config edit --env-path /path/to/.env
```

The configurator features:

- **Tabbed Interface**: Organized into logical sections (Core Paths, CDCS, File Processing, etc.)
- **Pre-populated Fields**: Loads existing `.env` values automatically
- **Real-time Validation**: Catches errors before saving
- **Context-sensitive Help**: Press **F1** on any field for detailed documentation
- **Dynamic NEMO Management**: Add/remove multiple NEMO harvester instances
- **Toggle Sections**: Enable/disable optional features like eLabFTW and Email alerts

```{figure} ../images/tui/screenshots/config_main_screen.svg
:name: config-tui-main-screen

Main Screen of the configuration TUI
```

**Navigation:**
- **`Tab` / `Shift+Tab`**: Move between fields
- **`<` / `>`**: Navigate between tabs
- **`F1`**: Show field-specific help
- **`Ctrl+S`**: Save configuration
- **`Escape`**: Cancel/Exit
- **`?`**: Show the overall help screen

```{figure} ../images/tui/screenshots/config_help_screen.svg
:name: config-tui-help-screen

Configuration app general help screen (shown with `?` key)
```

**Field Help:** Press **F1** while focused on any field to see extended documentation:

```{figure} ../images/tui/screenshots/config_field_detail.svg
:name: config-tui-field-detail

Showing the detailed help for a particular field (by pressing `F1`)
```

#### Video Demonstrations

This demo shows opening the configuration tool, browsing around the "tabs" that separate
the logical grouping of config values, showing the help screen, and then exiting:

```{raw} html
<figure>
  <video src="../_images/config_main.mp4" width="100%" controls autoplay muted loop aria-label="Configuration tool demonstration video">
  </video>
  <figcaption>Demonstration of the main screens in the interactive configuration tool</figcaption>
</figure>
```
<!-- this hidden span is so Sphinx will properly copy the video to the right location -->
<span style="display: none;">![main config screen](../images/tui/recordings/config_main.mp4)</span>

This video demonstrates using the `F1` key to show detailed help for various configuration variables.
This capability can help you learn more about what each setting does and how to properly set the values:


```{raw} html
<figure>
  <video src="../_images/config_field_help.mp4" width="100%" controls autoplay muted loop></video>
  <figcaption>Using the <code>F1</code> key to view detailed help for different fields</figcaption>
</figure>
```
<!-- this hidden span is so Sphinx will properly copy the video to the right location -->
<span style="display: none;">![main config screen](../images/tui/recordings/config_field_help.mp4)</span>

This video demonstrates adding a NEMO harvester configuration to the application. Since NexusLIMS supports
multiple NEMO instances in one installation, the configuration tool allows you to add/delete harvesters
and fill out each harvester's configuration in a logical grouping:

```{raw} html
<figure>
  <video src="../_images/config_nemo_management.mp4" width="100%" controls autoplay muted loop></video>
  <figcaption>Adding a NEMO harvester configuration, then adding a second one, and finally deleting it</figcaption>
</figure>
```
<!-- this hidden span is so Sphinx will properly copy the video to the right location -->
<span style="display: none;">![main config screen](../images/tui/recordings/config_nemo_management.mp4)</span>

### Dumping Configuration

Use `nexuslims config dump` to export your current configuration to a JSON file:

```bash
# Dump to default file (nexuslims_config.json)
nexuslims config dump

# Dump to specific file
nexuslims config dump --output /path/to/my-config.json
```

The dumped configuration includes:

- All environment variables (from both environment and `.env` file)
- Parsed NEMO harvester configurations
- Email configuration (if configured)
- Computed defaults for optional settings

```{danger}
**Security Warning**: The dumped JSON file contains **live credentials** (API tokens, passwords, certificates). Handle it with the same care as your `.env` file. Never commit it to version control or share it publicly.
```

Example output:
```json
{
  "NX_DATA_PATH": "/var/nexuslims/data",
  "NX_INSTRUMENT_DATA_PATH": "/mnt/nexus_instruments",
  "NX_DB_PATH": "/var/nexuslims/data/nexuslims.db",
  "NX_CDCS_URL": "https://nexuslims.example.com",
  "NX_CDCS_TOKEN": "live-secret-token-here",
  "nemo_harvesters": {
    "1": {
      "address": "https://nemo.example.com/api/",
      "token": "live-secret-token-here",
      "tz": null
    }
  },
  "email_config": {
    "smtp_host": "smtp.gmail.com",
    "smtp_port": 587,
    "smtp_password": "live-password-here",
    "sender": "nexuslims@example.com",
    "recipients": ["admin@example.com"]
  }
}
```

**Use cases for config dumps:**

- **Backup**: Create a complete snapshot of a working configuration
- **Migration**: Transfer configuration to a new server (see Loading Configuration below)
- **Comparison**: Diff configs between environments to identify differences
- **Disaster recovery**: Quick restoration of configuration after system failure

### Loading Configuration

Use `nexuslims config load` to convert a dumped JSON config back into a `.env` file:

```bash
# Load config (creates/overwrites .env in current directory)
nexuslims config load nexuslims_config.json

# Load to specific .env file
nexuslims config load nexuslims_config.json --env-path /path/to/.env

# Skip confirmation prompt (useful for automation)
nexuslims config load nexuslims_config.json --force
```

**Safety features:**

- **Backup**: If `.env` exists, it's automatically backed up to `.env.bak.YYYYMMDD-HHMMSS` before overwriting
- **Confirmation**: Prompts for confirmation before overwriting (unless `--force` is used)
- **Flattening**: Structured config (nested harvesters, email config) is converted back to flat environment variables

**Migration workflow example:**

```bash
# On source server
nexuslims config dump --output production-config.json

# Securely transfer the file to new server (contains live credentials!)
scp production-config.json user@newserver:/path/to/

# On destination server
nexuslims config load production-config.json

# Clean up the dump file (it contains secrets)
rm production-config.json
```

### Configuration in Logs

When `nexuslims build-records` starts with a verbosity of `-v` or higher,
it logs a sanitized view of the loaded configuration to help with debugging.
The log output is sanitized, ensuring no sensitive environment variables
are exposed in logs.

Example log output:
```
INFO - Loaded configuration:
INFO - {
INFO -   "NX_DATA_PATH": "/var/nexuslims/data",
INFO -   "NX_CDCS_TOKEN": "***",
INFO -   "nemo_harvesters": {
INFO -     "1": {"address": "https://nemo.example.com/api/", "token": "***"}
INFO -   }
INFO - }
```

This is particularly useful when:

- Troubleshooting why a specific setting isn't taking effect
- Verifying that `.env` changes were picked up
- Confirming which NEMO instances are configured
- Checking computed defaults for optional settings

## Required Configuration

These variables **must** be configured for NexusLIMS to function.

### File System Paths

(config-instrument-data-path)=
#### `NX_INSTRUMENT_DATA_PATH`

```{config-detail} NX_INSTRUMENT_DATA_PATH
```

**Example:**
```bash
NX_INSTRUMENT_DATA_PATH=/mnt/nexus_instruments
```

(config-data-path)=
#### `NX_DATA_PATH`

```{config-detail} NX_DATA_PATH
```

**Example:**
```bash
NX_DATA_PATH=/var/nexuslims/data
```

(config-db-path)=
#### `NX_DB_PATH`

```{config-detail} NX_DB_PATH
```

**Example:**
```bash
NX_DB_PATH=/var/nexuslims/data/nexuslims.db
```

### CDCS Integration

(config-cdcs-url)=
#### `NX_CDCS_URL`

```{config-detail} NX_CDCS_URL
```

**Example:**
```bash
NX_CDCS_URL=https://nexuslims.example.com
```

(config-cdcs-token)=
#### `NX_CDCS_TOKEN`

```{config-detail} NX_CDCS_TOKEN
```

**Example:**
```bash
NX_CDCS_TOKEN=your-api-token-here
```

(config-cdcs-user-owned-records)=
#### `NX_CDCS_USER_OWNED_RECORDS`

```{config-detail} NX_CDCS_USER_OWNED_RECORDS
```

**Example:**
```bash
NX_CDCS_USER_OWNED_RECORDS=true
```

(config-cdcs-assign-workspace)=
#### `NX_CDCS_ASSIGN_TO_PUBLIC_WORKSPACE`

```{config-detail} NX_CDCS_ASSIGN_TO_PUBLIC_WORKSPACE
```

**Example:**
```bash
NX_CDCS_ASSIGN_TO_PUBLIC_WORKSPACE=true
```

```{warning}
Store API tokens securely. Use environment variables or a secure secrets management system rather than committing tokens to version control.
```

### NEMO Integration

NexusLIMS supports multiple NEMO instances by using numbered environment variable pairs. Each NEMO instance requires an address and token.

(config-nemo-address)=
#### `NX_NEMO_ADDRESS_N`

```{config-detail} nemo.address
```

**Example:**
```bash
NX_NEMO_ADDRESS_1=https://nemo1.example.com/api/
NX_NEMO_ADDRESS_2=https://nemo2.example.com/api/
```

(config-nemo-token)=
#### `NX_NEMO_TOKEN_N`

```{config-detail} nemo.token
```

**Example:**
```bash
NX_NEMO_TOKEN_1=abc123def456...
NX_NEMO_TOKEN_2=xyz789uvw012...
```

## Optional Configuration


### eLabFTW Integration

(config-elabftw)=

NexusLIMS can optionally export records to [eLabFTW](https://www.elabftw.net/), an open-source electronic lab notebook. Each NexusLIMS session creates one eLabFTW experiment with a structured summary and the full XML record attached.

(config-elabftw-url)=
#### `NX_ELABFTW_URL`

```{config-detail} NX_ELABFTW_URL
```

**Example:**
```bash
NX_ELABFTW_URL=https://elabftw.example.com
```

(config-elabftw-api-key)=
#### `NX_ELABFTW_API_KEY`

```{config-detail} NX_ELABFTW_API_KEY
```

**Example:**
```bash
NX_ELABFTW_API_KEY=1-abcdef0123456789...
```

```{note}
eLabFTW API keys have the format `{id}-{key}` where the key portion is 84 hexadecimal characters.
```

(config-elabftw-experiment-category)=
#### `NX_ELABFTW_EXPERIMENT_CATEGORY`

```{config-detail} NX_ELABFTW_EXPERIMENT_CATEGORY
```

**Example:**
```bash
NX_ELABFTW_EXPERIMENT_CATEGORY=1
```

(config-elabftw-experiment-status)=
#### `NX_ELABFTW_EXPERIMENT_STATUS`

```{config-detail} NX_ELABFTW_EXPERIMENT_STATUS
```

**Example:**
```bash
NX_ELABFTW_EXPERIMENT_STATUS=2
```

```{tip}
When eLabFTW export is enabled, experiments are created with:
- **Title:** "NexusLIMS Experiment - {session_id}"
- **Body:** HTML summary with session details and link to CDCS record (if available)
- **Tags:** NexusLIMS, instrument name, username
- **Metadata:** Structured extra_fields including session times, instrument, user, and CDCS cross-link
- **Attachment:** Full XML record file
```

(config-labarchives)=
### LabArchives Integration

NexusLIMS can optionally export records to [LabArchives](https://www.labarchives.com/), a
commercial electronic lab notebook system. Each NexusLIMS session creates one notebook page
with an HTML session summary and the full XML record attached as a file.

LabArchives authentication uses HMAC-SHA-512 signed requests. You need four credentials:
an Access Key ID (provided by LabArchives), an Access Password (provided by LabArchives),
a User ID (uid), and the instance URL (most likely can stay as the default unless you are
in a different region).

(config-labarchives-url)=
#### `NX_LABARCHIVES_URL`

```{config-detail} NX_LABARCHIVES_URL
```

**Example:**
```bash
NX_LABARCHIVES_URL=https://api.labarchives.com/api
```

(config-labarchives-access-key-id)=
#### `NX_LABARCHIVES_ACCESS_KEY_ID`

```{config-detail} NX_LABARCHIVES_ACCESS_KEY_ID
```

**Example:**
```bash
NX_LABARCHIVES_ACCESS_KEY_ID=your-access-key-id-here
```

(config-labarchives-access-password)=
#### `NX_LABARCHIVES_ACCESS_PASSWORD`

```{config-detail} NX_LABARCHIVES_ACCESS_PASSWORD
```

**Example:**
```bash
NX_LABARCHIVES_ACCESS_PASSWORD=your-access-password-here
```

(config-labarchives-user-id)=
#### `NX_LABARCHIVES_USER_ID`

```{config-detail} NX_LABARCHIVES_USER_ID
```

**Example:**
```bash
NX_LABARCHIVES_USER_ID=your-uid-here
```

```{note}
To obtain your UID, use the `nexuslims config labarchives-get-uid` command, or use
the button on the LabArchives page of the `nexuslims config edit` application. You will need to sign in
manually via the LabArchives web interface and generate a fresh **Password Token for
External Applications** (valid for 1 hour only), which will be exchanged for your
stable UID. This only has to be done once, as the
returned `uid` value is stable and does not change over time.
```

(config-labarchives-notebook-id)=
#### `NX_LABARCHIVES_NOTEBOOK_ID`

```{config-detail} NX_LABARCHIVES_NOTEBOOK_ID
```

**Example:**
```bash
NX_LABARCHIVES_NOTEBOOK_ID=12345  # optional
```

```{tip}
When LabArchives export is enabled, the following structure is created automatically:
- **Notebook:** The notebook specified by `NX_LABARCHIVES_NOTEBOOK_ID` (or Inbox if unset)
- **Folder hierarchy:** `NexusLIMS Records/{instrument_pid}/` (created automatically if missing)
- **Page:** `{YYYY-MM-DD} — {session_id}` (one page per session)
- **Entry:** HTML session summary with optional CDCS cross-link
- **Attachment:** Full XML record file
```

### Export Configuration

(config-export-strategy)=
#### `NX_EXPORT_STRATEGY`

```{config-detail} NX_EXPORT_STRATEGY
```

**Example:**
```bash
NX_EXPORT_STRATEGY=best_effort
```

```{note}
See the {ref}`exporters` page for a full description of how strategies interact with destination priorities and inter-destination dependencies (e.g. eLabFTW cross-linking to a CDCS record).
```


### File Handling

(config-file-strategy)=
#### `NX_FILE_STRATEGY`

```{config-detail} NX_FILE_STRATEGY
```

**Example:**
```bash
NX_FILE_STRATEGY=inclusive
```

(config-ignore-patterns)=
#### `NX_IGNORE_PATTERNS`

```{config-detail} NX_IGNORE_PATTERNS
```

**Example:**
```bash
NX_IGNORE_PATTERNS=["*.mib", "*.db", "*.emi", "*.tmp", "*~"]
```

(config-file-delay-days)=
#### `NX_FILE_DELAY_DAYS`

```{config-detail} NX_FILE_DELAY_DAYS
```

```bash
NX_FILE_DELAY_DAYS=2.5
```

(config-clustering-sensitivity)=
#### `NX_CLUSTERING_SENSITIVITY`

```{config-detail} NX_CLUSTERING_SENSITIVITY
```

**Examples:**
```bash
# More sensitive - detects smaller time gaps as activity boundaries
NX_CLUSTERING_SENSITIVITY=2.0

# Less sensitive - only large time gaps create new activities
NX_CLUSTERING_SENSITIVITY=0.5

# Disable clustering - all files in one activity
NX_CLUSTERING_SENSITIVITY=0
```

### Directory Paths

(config-log-path)=
#### `NX_LOG_PATH`

```{config-detail} NX_LOG_PATH
```

**Example:**
```bash
NX_LOG_PATH=/var/log/nexuslims
```

(config-records-path)=
#### `NX_RECORDS_PATH`

```{config-detail} NX_RECORDS_PATH
```

**Example:**
```bash
NX_RECORDS_PATH=/var/nexuslims/records
```

(config-local-profiles-path)=
#### `NX_LOCAL_PROFILES_PATH`

```{config-detail} NX_LOCAL_PROFILES_PATH
```

See {ref}`instrument-profiles` for details on writing profile modules.

**Example:**
```bash
NX_LOCAL_PROFILES_PATH=/etc/nexuslims/profiles
```

### NEMO Advanced Options

(config-nemo-strftime-fmt)=
#### `NX_NEMO_STRFTIME_FMT_N`

```{config-detail} nemo.strftime_fmt
```

**Example:**
```bash
NX_NEMO_STRFTIME_FMT_1=%Y-%m-%d %H:%M:%S
```

(config-nemo-strptime-fmt)=
#### `NX_NEMO_STRPTIME_FMT_N`

```{config-detail} nemo.strptime_fmt
```

**Example:**
```bash
NX_NEMO_STRPTIME_FMT_1=%Y-%m-%d %H:%M:%S
```

(config-nemo-tz)=
#### `NX_NEMO_TZ_N`

```{config-detail} nemo.tz
```

**Example:**
```bash
NX_NEMO_TZ_1=America/Denver
NX_NEMO_TZ_2=America/New_York
```

### SSL/TLS Configuration

(config-cert-bundle-file)=
#### `NX_CERT_BUNDLE_FILE`

```{config-detail} NX_CERT_BUNDLE_FILE
```

**Example:**
```bash
NX_CERT_BUNDLE_FILE=/etc/ssl/certs/custom-ca-bundle.crt
```

(config-cert-bundle)=
#### `NX_CERT_BUNDLE`

```{config-detail} NX_CERT_BUNDLE
```

**Example:**
```bash
NX_CERT_BUNDLE="-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"
```

(config-disable-ssl-verify)=
#### `NX_DISABLE_SSL_VERIFY`

```{config-detail} NX_DISABLE_SSL_VERIFY
```

**Example:**
```bash
NX_DISABLE_SSL_VERIFY=true
```

### Email Notifications

Email notifications are optional but recommended for production deployments. They alert administrators when record building fails.

(config-email-smtp-host)=
#### `NX_EMAIL_SMTP_HOST`

**Required for email:** Yes

```{config-detail} email.smtp_host
```

**Example:**
```bash
NX_EMAIL_SMTP_HOST=smtp.gmail.com
```

(config-email-smtp-port)=
#### `NX_EMAIL_SMTP_PORT`

```{config-detail} email.smtp_port
```

**Example:**
```bash
NX_EMAIL_SMTP_PORT=587
```

(config-email-smtp-username)=
#### `NX_EMAIL_SMTP_USERNAME`

```{config-detail} email.smtp_username
```

**Example:**
```bash
NX_EMAIL_SMTP_USERNAME=nexuslims@example.com
```

(config-email-smtp-password)=
#### `NX_EMAIL_SMTP_PASSWORD`

```{config-detail} email.smtp_password
```

**Example:**
```bash
NX_EMAIL_SMTP_PASSWORD=app_specific_password
```

(config-email-use-tls)=
#### `NX_EMAIL_USE_TLS`

```{config-detail} email.use_tls
```

**Example:**
```bash
NX_EMAIL_USE_TLS=true
```

(config-email-sender)=
#### `NX_EMAIL_SENDER`

**Required for email:** Yes

```{config-detail} email.sender
```

**Example:**
```bash
NX_EMAIL_SENDER=nexuslims@example.com
```

(config-email-recipients)=
#### `NX_EMAIL_RECIPIENTS`

**Required for email:** Yes

```{config-detail} email.recipients
```

**Example:**
```bash
NX_EMAIL_RECIPIENTS=admin@example.com,team@example.com
```

## Configuration in Code (for developers)

### Accessing Configuration

Always access configuration through the `settings` object from the `nexusLIMS.config` module:

```python
from nexusLIMS.config import settings

# Access configuration values
data_path = settings.NX_DATA_PATH
file_strategy = settings.NX_FILE_STRATEGY
db_path = settings.NX_DB_PATH

# Access NEMO harvesters (returns dict of configurations)
nemo_harvesters = settings.nemo_harvesters()

# Access email configuration (returns EmailConfig or None)
email_config = settings.email_config()
```

```{danger}
**Never use `os.getenv()` or `os.environ` directly for NexusLIMS configuration.**

Always access configuration through the `settings` object from `nexusLIMS.config`. This ensures:
- Type safety and validation
- Consistent behavior across the codebase
- Proper defaults and error handling
- Easier testing (can mock the settings object)
```

### Testing with Configuration

In tests, use `refresh_settings()` after modifying environment variables:

```python
import os
from nexusLIMS.config import settings, refresh_settings

def test_with_custom_config():
    # Modify environment
    os.environ["NX_FILE_STRATEGY"] = "inclusive"

    # Refresh to pick up changes
    refresh_settings()

    # Now settings reflects the new value
    assert settings.NX_FILE_STRATEGY == "inclusive"
```

## Configuration Validation

Pydantic validates all configuration on startup. If validation fails, NexusLIMS will raise a `ValidationError` with details about what's wrong.

Common validation errors:
- **Missing required fields**: Set all required environment variables
- **Invalid paths**: Ensure directories/files exist and are accessible
- **Invalid URLs**: Check URL format and trailing slashes
- **Invalid types**: Check value types (numbers, booleans, etc.)

## Example Configurations

### Minimal Production Configuration

```bash
# File paths
NX_INSTRUMENT_DATA_PATH=/mnt/nexus_instruments
NX_DATA_PATH=/var/nexuslims/data
NX_DB_PATH=/var/nexuslims/data/nexuslims.db

# CDCS
NX_CDCS_URL=https://nexuslims.example.com
NX_CDCS_TOKEN=your-api-token-here

# NEMO
NX_NEMO_ADDRESS_1=https://nemo.example.com/api/
NX_NEMO_TOKEN_1=token_here
```

### Full Example Production Configuration

```bash
# ============================================================================
# File paths
# ============================================================================
NX_INSTRUMENT_DATA_PATH=/mnt/nexus_instruments
NX_DATA_PATH=/var/nexuslims/data
NX_DB_PATH=/var/nexuslims/data/nexuslims.db
NX_LOG_PATH=/var/log/nexuslims
NX_RECORDS_PATH=/var/nexuslims/records

# Local profiles
NX_LOCAL_PROFILES_PATH=/etc/nexuslims/profiles

# ============================================================================
# CDCS Integration
# ============================================================================
NX_CDCS_URL=https://nexuslims.example.com
NX_CDCS_TOKEN=your-api-token-here

# ============================================================================
# Export Configuration
# ============================================================================
# Strategy for exporting to multiple destinations ('all', 'first_success', 'best_effort')
NX_EXPORT_STRATEGY=all

# ============================================================================
# eLabFTW Integration (optional)
# ============================================================================
NX_ELABFTW_URL=https://elabftw.example.com
NX_ELABFTW_API_KEY=your-elabftw-api-key
NX_ELABFTW_EXPERIMENT_CATEGORY=1
NX_ELABFTW_EXPERIMENT_STATUS=1

# ============================================================================
# File Handling
# ============================================================================
NX_FILE_STRATEGY=inclusive
NX_FILE_DELAY_DAYS=2.5
NX_CLUSTERING_SENSITIVITY=1.0
NX_IGNORE_PATTERNS='["*.mib","*.db","*.emi","*.hdr"]'

# ============================================================================
# NEMO Harvesters
# ============================================================================
# First NEMO instance
NX_NEMO_ADDRESS_1=https://nemo1.example.com/api/
NX_NEMO_TOKEN_1=token1_here
NX_NEMO_TZ_1=America/Denver
NX_NEMO_STRFTIME_FMT_1=%Y-%m-%dT%H:%M:%S%z
NX_NEMO_STRPTIME_FMT_1=%Y-%m-%dT%H:%M:%S%z

# Second NEMO instance (optional)
NX_NEMO_ADDRESS_2=https://nemo2.example.com/api/
NX_NEMO_TOKEN_2=token2_here
NX_NEMO_TZ_2=America/New_York

# ============================================================================
# Email Notifications (optional)
# ============================================================================
NX_EMAIL_SMTP_HOST=smtp.gmail.com
NX_EMAIL_SMTP_PORT=587
NX_EMAIL_SMTP_USERNAME=nexuslims@example.com
NX_EMAIL_SMTP_PASSWORD=app_password
NX_EMAIL_USE_TLS=true
NX_EMAIL_SENDER=nexuslims@example.com
NX_EMAIL_RECIPIENTS=admin@example.com,team@example.com

# ============================================================================
# SSL Certificate Configuration (optional)
# ============================================================================
# Option 1: Path to certificate bundle file
NX_CERT_BUNDLE_FILE=/etc/ssl/certs/custom-ca.crt

# Option 2: Certificate bundle as string (alternative to NX_CERT_BUNDLE_FILE)
# NX_CERT_BUNDLE="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"

# Option 3: Disable SSL verification (NEVER use in production!)
# NX_DISABLE_SSL_VERIFY=false
```

## Troubleshooting

### Configuration Not Loading

If configuration changes aren't taking effect:

1. **Check .env file location**: Must be in project root
2. **Check environment variables**: `os.environ` takes precedence over `.env`
3. **Restart application**: Configuration is loaded on startup
4. **Check for typos**: Variable names are case-sensitive

### Path Validation Errors

If you get path validation errors:

1. **Ensure directories exist**: Create them before starting NexusLIMS
2. **Check permissions**: Ensure the user running NexusLIMS has read/write access
3. **Use absolute paths**: Avoid relative paths
4. **Check for typos**: Verify path spelling

### NEMO Configuration Issues

If NEMO harvesters aren't working:

1. **Check trailing slash**: `NX_NEMO_ADDRESS_N` must end with `/`
2. **Match suffixes**: `NX_NEMO_ADDRESS_1` must pair with `NX_NEMO_TOKEN_1`
3. **Verify tokens**: Test tokens in the NEMO admin interface
4. **Check timezone format**: Use IANA timezone names (e.g., `America/Denver`)

### Email Not Working

If email notifications aren't sending:

1. **Check required fields**: `NX_EMAIL_SMTP_HOST`, `NX_EMAIL_SENDER`, and `NX_EMAIL_RECIPIENTS` are required
2. **Verify SMTP credentials**: Test SMTP access independently
3. **Check firewall**: Ensure SMTP port (usually 587) isn't blocked
4. **Use app passwords**: Some providers (Gmail) require app-specific passwords

### Instrument Profile Issues

If instrument profiles aren't loading or working:

1. **Verify `NX_LOCAL_PROFILES_PATH`**: Ensure the environment variable points to a valid directory
2. **Check profile structure**: Profiles must create an `InstrumentProfile` instance and register it via `get_profile_registry().register()`
3. **Match `instrument_id` to database**: The `instrument_id` parameter in `InstrumentProfile()` must match the instrument's `name` field in the database (filename doesn't matter)
4. **Import errors**: Check that all dependencies are available in the environment

## See Also

- {ref}`getting_started` - Initial setup guide
- {ref}`instrument-profiles` - Customizing metadata extraction
- {ref}`record-building` - Understanding the record building process
- [Pydantic Settings Documentation](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
