(migration)=
# Migration Guide

This guide is for system administrators, and will help you migrate your NexusLIMS installation from v1.4.3 to v2.5.0.

## What Changed

The major changes you need to know about:

1. **Package Manager**: Poetry → `uv` (faster, simpler installation)
2. **Environment Variables**: All variables now use `NX_` prefix
3. **Metadata System**: New Pydantic schemas with EM Glossary integration and validation
4. **Configuration**: Better validation with helpful error messages

## Transition to uv

The project has transitioned from Poetry to `uv` for Python package and environment management. `uv` is a fast, modern package installer and resolver written in Rust that provides:

- Significantly faster dependency resolution and installation
- Better reproducibility with lock files
- Simpler workflow for both development and deployment
- Direct Python version management (no need for separate tools like pyenv)

### Installing uv

Install `uv` using the official installation script:

```bash
# Unix/macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```

For alternative installation methods, see the [uv documentation](https://docs.astral.sh/uv/).

## Environment Variable Changes

Environment variable naming has been standardized for better consistency. **You must update your `.env` file** to use the new variable names.

### Renamed Variables

The following variables have been renamed:

| **Old Name (v1.x)** | **New Name (v2.0+)** | **Required** |
|---------------------|----------------------|--------------|
| `mmfnexus_path` | `NX_INSTRUMENT_DATA_PATH` | Yes |
| `nexusLIMS_path` | `NX_DATA_PATH` | Yes |
| `nexusLIMS_db_path` | `NX_DB_PATH` | Yes |
| `nexusLIMS_user` | `NX_CDCS_TOKEN` | Yes |
| `nexusLIMS_pass` | `NX_CDCS_TOKEN` | Yes |
| `cdcs_url` | `NX_CDCS_URL` | Yes |
| `NexusLIMS_cert_bundle_file` | `NX_CERT_BUNDLE_FILE` | No |
| `NexusLIMS_cert_bundle` | `NX_CERT_BUNDLE` | No |
| `NexusLIMS_file_strategy` | `NX_FILE_STRATEGY` | No |
| `NexusLIMS_ignore_patterns` | `NX_IGNORE_PATTERNS` | No |
| `nexusLIMS_file_delay_days` | `NX_FILE_DELAY_DAYS` | No |
| `NEMO_address_*` | `NX_NEMO_ADDRESS_*` | If using NEMO |
| `NEMO_token_*` | `NX_NEMO_TOKEN_*` | If using NEMO |
| `NEMO_strftime_fmt_*` | `NX_NEMO_STRFTIME_FMT_*` | No |
| `NEMO_strptime_fmt_*` | `NX_NEMO_STRPTIME_FMT_*` | No |
| `NEMO_tz_*` | `NX_NEMO_TZ_*` | No |

```{note}
**v2.3.0+ Authentication Change**: CDCS authentication has changed from username/password (`NX_CDCS_USER` and `NX_CDCS_PASS`) to token-based authentication (`NX_CDCS_TOKEN`). Replace your username and password with an API token obtained from the CDCS admin panel. See {ref}`config-cdcs-token` for details.
```

### New Variables

The following variables are new in v2.0:

| **Variable** | **Purpose** | **Required** |
|--------------|-------------|--------------|
| `NX_LOG_PATH` | Custom directory for application logs | No |
| `NX_RECORDS_PATH` | Custom directory for generated XML records | No |
| `NX_LOCAL_PROFILES_PATH` | Directory for site-specific instrument profiles | No |
| `NX_EMAIL_SMTP_HOST` | SMTP server hostname | If using email |
| `NX_EMAIL_SMTP_PORT` | SMTP server port (default: 587) | No |
| `NX_EMAIL_SMTP_USERNAME` | SMTP username for authentication | No |
| `NX_EMAIL_SMTP_PASSWORD` | SMTP password for authentication | No |
| `NX_EMAIL_USE_TLS` | Use TLS encryption (default: true) | No |
| `NX_EMAIL_SENDER` | Email address to send from | If using email |
| `NX_EMAIL_RECIPIENTS` | Comma-separated recipient addresses | If using email |

### Removed Variables

The following variables from v1.x are no longer used:

| **Variable** | **Reason for Removal** |
|--------------|------------------------|
| `test_cdcs_url` | Tests now run as independent unit tests and integration tests against a Docker-deployed instance created on demand |
| `sharepoint_root_url` | SharePoint harvester has been removed |
| `email_sender` | Replaced by enhanced email configuration (`NX_EMAIL_*`) |
| `email_recipients` | Replaced by enhanced email configuration (`NX_EMAIL_*`) |

## Complete Environment Variable Reference

### General Configuration

| **Variable** | **Description** | **Example** |
|--------------|-----------------|-------------|
| `NX_FILE_STRATEGY` | File inclusion strategy: `exclusive` (only files with extractors) or `inclusive` (all files) | `exclusive` |
| `NX_IGNORE_PATTERNS` | JSON array of glob patterns to ignore | `["*.mib","*.db","*.emi"]` |
| `NX_INSTRUMENT_DATA_PATH` | Root path to centralized instrument data (read-only mount) | `/mnt/microscopy/data` |
| `NX_DATA_PATH` | Writable parallel path for metadata and previews | `/var/nexuslims/data` |
| `NX_DB_PATH` | Path to NexusLIMS SQLite database | `/var/nexuslims/nexuslims.db` |
| `NX_FILE_DELAY_DAYS` | Maximum days to wait for files (can be fractional) | `2` |
| `NX_LOG_PATH` | Optional: Directory for logs (defaults to `NX_DATA_PATH/logs/`) | `/var/log/nexuslims` |
| `NX_RECORDS_PATH` | Optional: Directory for records (defaults to `NX_DATA_PATH/records/`) | `/var/nexuslims/records` |
| `NX_LOCAL_PROFILES_PATH` | Optional: Directory for site-specific instrument profiles | `/var/nexuslims/profiles` |

### CDCS Authentication

| **Variable** | **Description** | **Example** |
|--------------|-----------------|-------------|
| `NX_CDCS_TOKEN` | API token for CDCS authentication | `your-api-token-here` |
| `NX_CDCS_URL` | Root URL of NexusLIMS CDCS instance (with trailing slash) | `https://nexuslims.example.com/` |
| `NX_CERT_BUNDLE_FILE` | Optional: Path to SSL certificate bundle | `/etc/ssl/certs/custom-ca.pem` |
| `NX_CERT_BUNDLE` | Optional: SSL certificate bundle as string | `-----BEGIN CERTIFICATE-----\n...` |

### NEMO Harvester Configuration

Multiple NEMO harvesters can be configured using numbered suffixes (`_1`, `_2`, etc.):

| **Variable** | **Description** | **Example** |
|--------------|-----------------|-------------|
| `NX_NEMO_ADDRESS_N` | Full path to NEMO API root (with trailing slash) | `https://nemo.example.com/api/` |
| `NX_NEMO_TOKEN_N` | Authentication token for NEMO server | `abc123def456...` |
| `NX_NEMO_STRFTIME_FMT_N` | Optional: Format for sending datetimes to API | `%Y-%m-%dT%H:%M:%S%z` |
| `NX_NEMO_STRPTIME_FMT_N` | Optional: Format for parsing datetimes from API | `%Y-%m-%dT%H:%M:%S%z` |
| `NX_NEMO_TZ_N` | Optional: IANA timezone for API datetimes | `America/Denver` |

### Email Notification Configuration

Email notifications are sent by `nexuslims build-records` when errors are detected:

| **Variable** | **Description** | **Example** |
|--------------|-----------------|-------------|
| `NX_EMAIL_SMTP_HOST` | SMTP server hostname | `smtp.gmail.com` |
| `NX_EMAIL_SMTP_PORT` | Optional: SMTP port (default: 587) | `587` |
| `NX_EMAIL_SMTP_USERNAME` | Optional: SMTP username for authentication | `user@example.com` |
| `NX_EMAIL_SMTP_PASSWORD` | Optional: SMTP password for authentication | `your-app-password` |
| `NX_EMAIL_USE_TLS` | Optional: Use TLS encryption (default: true) | `true` |
| `NX_EMAIL_SENDER` | Email address to send from | `nexuslims@example.com` |
| `NX_EMAIL_RECIPIENTS` | Comma-separated list of recipient addresses | `admin@example.com,team@example.com` |

## Centralized Configuration Module

To improve maintainability and type safety, all environment variable access is centralized in the `nexusLIMS.config` module using [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).

For complete configuration documentation, see {ref}`configuration`.

### What This Means for Users

- **No file structure changes required**: Continue defining variables in your `.env` file or system environment
- **Automatic validation**: The application validates configuration at startup and provides clear error messages
- **Type safety**: Configuration values are automatically converted to appropriate Python types
- **Default values**: Sensible defaults are provided where applicable
- **Mocking for tests**: The design of the system allows for a fully mocked setup
for use in the test suite, ensuring more reliable code quality testing.

### What This Means for Developers

Instead of accessing environment variables directly:

```python
# Old approach (v1.x) - Don't use
import os
path = os.environ.get("nexusLIMS_path")
```

Use the centralized config module:

```python
# New approach (v2.0+)
from nexusLIMS.config import settings
path = settings.NX_DATA_PATH
```

This provides:

- Type hints and autocomplete in IDEs
- Validation at import time
- Consistent defaults throughout the application
- Easier testing with `refresh_settings()`

## Step-by-Step Migration Instructions

Follow these steps to migrate your NexusLIMS installation from v1.x to v2.5.0:

### 1. Backup Your Current Installation

```{important}
**Database migrations required**: The database schema has changed since v1.4.3. You will need to run migrations to:
- Add the `upload_log` table (for tracking record exports)
- Update `session_log` CHECK constraints (to support new record statuses)

**Note:** Database migrations automatically create timestamped backups before making changes. However, it's still good practice to create your own backups of critical files before major upgrades.
```

```bash
# Backup your .env file (always recommended)
cp .env .env.v1.backup

# Optional: Create manual database backup (migrations create automatic backups)
cp /path/to/nexuslims_db.sqlite /path/to/nexuslims_db.sqlite.backup
```

### 2. Install uv

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh

# Verify installation
uv --version
```

### 3. Update Your .env File

Create a new `.env` file based on `.env.example`:

```bash
# Copy the example file
cp .env.example .env

# Edit with your settings
nano .env  # or your preferred editor
```

**Map your old variables to new names** using the table in the "Renamed Variables" section above.

**Key changes to make**:

- Rename `mmfnexus_path` → `NX_INSTRUMENT_DATA_PATH`
- Rename `nexusLIMS_path` → `NX_DATA_PATH`
- Rename `nexusLIMS_db_path` → `NX_DB_PATH`
- Replace `nexusLIMS_user` and `nexusLIMS_pass` → `NX_CDCS_TOKEN` (obtain token from CDCS admin panel)
- Rename `cdcs_url` → `NX_CDCS_URL`
- Rename `NexusLIMS_cert_bundle_file` → `NX_CERT_BUNDLE_FILE` (if used)
- Rename `NexusLIMS_cert_bundle` → `NX_CERT_BUNDLE` (if used)
- Rename `NexusLIMS_file_strategy` → `NX_FILE_STRATEGY` (if customized)
- Rename `NexusLIMS_ignore_patterns` → `NX_IGNORE_PATTERNS` (if customized)
- Rename `nexusLIMS_file_delay_days` → `NX_FILE_DELAY_DAYS` (if customized)
- Rename `NEMO_address_*` → `NX_NEMO_ADDRESS_*` (if using NEMO)
- Rename `NEMO_token_*` → `NX_NEMO_TOKEN_*` (if using NEMO)
- Remove `test_cdcs_url`, `sharepoint_root_url`, `email_sender`, `email_recipients`
- Add new email configuration variables (`NX_EMAIL_*`) if you want email notifications

### 4. Remove Old Virtual Environment

```bash
# If you have an old Poetry or pyenv environment
rm -rf .venv

# Remove Poetry lock file
rm poetry.lock  # if it exists
```

### 5. Create New Environment with uv

```bash
# Install NexusLIMS with dependencies (this will create the virtualenvironment as necessary)
uv sync
```

### 6. Mark Database as Migrated and Apply Updates

```{versionadded} 2.2.0
NexusLIMS now uses Alembic for database schema version control. You need to mark your existing database as migrated to the baseline schema, then apply updates.
```

```bash
# Mark database as at the baseline schema version (v1.4.3 schema)
nexuslims db alembic stamp v1_4_3

# Apply pending migrations (adds upload_log table and updated CHECK constraints)
nexuslims db upgrade
```

**What this does:**

1. `stamp v1_4_3` - Marks your v1.4.3 database as having the baseline schema (`instruments` + `session_log` tables)
2. `upgrade` - Applies migration (database update) commands that have updated the schema since v1.4.3:
   - Migration `v2_4_0a`: Adds the `upload_log` table for tracking record exports
   - Migration `v2_4_0b`: Updates `session_log` CHECK constraints to include new statuses (`NO_CONSENT`, `NO_RESERVATION`, `BUILT_NOT_EXPORTED`)

````{note}
If you're running from a source checkout (not an installed package), prefix commands with `uv run`:
```bash
uv run nexuslims db alembic stamp v1_4_3
uv run nexuslims db upgrade
```
````

````{note}
**Automatic backups:** The migration system automatically creates timestamped backups before making changes to your database (e.g., `database_backup_20260207_143216.sqlite`). These are created in the same directory as your database file.

If you prefer to create your own backup first, you can:
```bash
cp /path/to/nexuslims_db.sqlite /path/to/nexuslims_db.sqlite.backup
```
````

### 7. Verify Installation

```bash
# Test configuration loading
uv run python -c "from nexusLIMS.config import settings; print(settings.NX_DATA_PATH)"

# Run unit tests (not necessary, but will provide confidence things are working)
uv run pytest tests/unit

# Check database connection and list instruments
uv run python -c "from nexusLIMS.instruments import instrument_db; print(f'{len(instrument_db)} instruments found:'); [print(f'  - {pid}') for pid in instrument_db.keys()]"
```

### 8. Update Deployment Scripts

If you have cron jobs or systemd services running NexusLIMS:

**Old command style (v1.x)**:

```bash
# Using Poetry
cd /path/to/NexusLIMS
poetry run python -m nexusLIMS.builder.record_builder
```

**New command style (v2.0+)**:

```bash
# Using uv
cd /path/to/NexusLIMS
uv run nexuslims build-records
```

### 9. Test Record Building

Run a test record build to verify everything works:

```bash
# Dry run mode (find files but don't build records)
uv run nexuslims build-records -n

# Verbose mode (with detailed logging)
uv run nexuslims build-records -vv -n
```

## Common Migration Issues

### Database Path Not Found

**Error**: `ValidationError: NX_DB_PATH ... does not exist`

**Solution**: Ensure your database file exists at the path specified in `NX_DB_PATH`. If you migrated the path, update it in your `.env` file.

### Directory Does Not Exist

**Error**: `ValidationError: NX_INSTRUMENT_DATA_PATH ... does not exist`

**Solution**: Pydantic validates that paths exist. Ensure all directory paths in your `.env` file point to existing directories:

```bash
mkdir -p /path/to/nexuslims/data
mkdir -p /path/to/nexuslims/logs
```

### SSL Certificate Errors

**Error**: `SSLError: certificate verify failed`

**Solution**: If your CDCS or NEMO servers use custom SSL certificates, configure `NX_CERT_BUNDLE_FILE`:

```bash
NX_CERT_BUNDLE_FILE=/etc/ssl/certs/custom-ca-bundle.pem
```

### NEMO Harvester Not Found

**Error**: No NEMO reservations being harvested

**Solution**: Verify your NEMO configuration uses the new `NX_` prefix:

```bash
NX_NEMO_ADDRESS_1=https://nemo.example.com/api/
NX_NEMO_TOKEN_1=your-token-here
```

## Getting Help

If you encounter issues during migration:

1. **Review the error message carefully** - Pydantic provides detailed validation errors
2. **Check the example file**: Compare your `.env` with `.env.example`
3. **Consult the logs**: Check `NX_LOG_PATH` (or `NX_DATA_PATH/logs/`) for details
4. **Open an issue**: [https://github.com/datasophos/NexusLIMS/issues](https://github.com/datasophos/NexusLIMS/issues)

For professional migration support, deployment assistance, or custom development:

- **Contact Datasophos**: https://datasophos.co/#contact

## Further Reading

- {ref}`getting_started` - Fresh installation guide for v2.0
- {ref}`record-building` - Understanding the record building workflow
- {py:mod}`nexusLIMS.config` - Configuration module API documentation
- [uv documentation](https://docs.astral.sh/uv/) - Learn more about uv
