# Data Model: Nextflow Module System Client **Date**: 2026-01-19 **Feature**: 251117-module-system **Last Updated**: 2026-02-27 (reflects final implementation) ## Overview This document defines the data entities, their attributes, relationships, and state transitions for the Nextflow module system client implementation. --- ## Entity Definitions ### 1. ModuleReference Represents a reference to a module in DSL `include` statements. ```groovy @CompileStatic class ModuleReference { String scope // e.g., "nf-core" String name // e.g., "fastqc" String fullName // e.g., "@nf-core/fastqc" static ModuleReference parse(String source) { // Parses "@scope/name" format } boolean isRegistryModule() { return fullName.startsWith('@') } } ``` **Validation Rules**: - `scope`: lowercase alphanumeric with hyphens, pattern `[a-z0-9][a-z0-9-]*` - `name`: lowercase alphanumeric with underscores/hyphens, pattern `[a-z][a-z0-9_-]*` - `fullName`: must match `^@[a-z0-9][a-z0-9-]*/[a-z][a-z0-9_-]*$` --- ### 2. ModuleSpec Parsed representation of `meta.yaml` file. Class: `nextflow.module.ModuleSpec`. ```groovy @CompileStatic class ModuleSpec { String name // e.g., "nf-core/fastqc" (without @) String version // e.g., "1.0.0" String description // Module description List keywords // Discovery keywords List authors // GitHub handles String license // SPDX identifier Map requires // dependency -> version constraint static ModuleSpec load(Path metaYamlPath) { ... } List validate() { ... } // Returns list of validation errors boolean isValid() { ... } } ``` **Validation Rules**: - `name`: Must match `scope/name` or `scope/path/to/name` pattern - `version`: Must be valid SemVer (`MAJOR.MINOR.PATCH[-prerelease]`) - `description`, `license`: Required fields (validate() reports missing) **Note**: Tool/argument definitions were removed from the ADR and are not part of `ModuleSpec`. --- ### 3. InstalledModule Represents a module in the local `modules/` directory. ```groovy @CompileStatic class InstalledModule { ModuleReference reference Path directory // e.g., /project/modules/@nf-core/fastqc Path mainFile // e.g., /project/modules/@nf-core/fastqc/main.nf Path manifestFile // e.g., /project/modules/@nf-core/fastqc/meta.yaml Path checksumFile // e.g., /project/modules/@nf-core/fastqc/.checksum String installedVersion String expectedChecksum ModuleIntegrity getIntegrity() { // Compute and compare checksum } } enum ModuleIntegrity { VALID, // Checksum matches MODIFIED, // Checksum mismatch (local changes) MISSING_CHECKSUM, // No .checksum file CORRUPTED // Missing required files } ``` **State Transitions**: ``` [NOT_INSTALLED] --install--> [VALID] [VALID] --user edits--> [MODIFIED] [MODIFIED] --install -force--> [VALID] [VALID] --version change in config--> [VALID] (replaced) [MODIFIED] --version change in config--> [MODIFIED] (blocked, warn) ``` --- ### 4. ModulesConfig and RegistryConfig Modules configuration loaded from `nextflow_spec.json` ( or the `modules {}` block in `nextflow.config` as alternative). Registry settings from the `registry {}` block in `nextflow.config`. ```groovy @ScopeName("modules") @CompileStatic class ModulesConfig implements ConfigScope { Map modules = [:] // module fullName -> version String getVersion(String moduleName) { ... } boolean hasVersion(String moduleName) { ... } } @ScopeName("registry") @CompileStatic class RegistryConfig implements ConfigScope { static final String DEFAULT_REGISTRY_URL = 'https://registry.nextflow.io/api' Collection url // Registry URL(s) in priority order String apiKey // API key (falls back to NXF_REGISTRY_TOKEN env var) String getUrl() // Returns primary (first) URL Collection getAllUrls() String getApiKey() // Returns apiKey or NXF_REGISTRY_TOKEN } ``` **Config Syntax**: ```nextflow // nextflow_spec.json (current approach) { "modules": { "@nf-core/fastqc": "1.0.0", "@nf-core/bwa-align": "1.2.0" } } // nextflow.config (alternative not currently used) modules { '@nf-core/fastqc' = '1.0.0' '@nf-core/bwa-align' = '1.2.0' } registry { url = [ 'https://private.registry.myorg.com', 'https://registry.nextflow.io/api' ] apiKey = '${MYORG_TOKEN}' // Only applied to the primary registry } ``` --- ### 5. DefaultRemoteModuleResolver (SPI) Bridges the DSL parser to the module resolution runtime. Class: `nextflow.module.DefaultRemoteModuleResolver`. ```groovy // Implements: nextflow.module.spi.RemoteModuleResolver (nf-lang) class DefaultRemoteModuleResolver implements RemoteModuleResolver { int getPriority() { return 0 } // Can be overridden by plugins with higher priority Path resolve(String moduleName, Path baseDir) { // 1. Parse ModuleReference from "@scope/name" // 2. Read version constraints from nextflow_spec.json / ModulesConfig // 3. Call ModuleResolver.installModule(reference, version, autoInstall=true) // 4. Return path to modules/@scope/name/main.nf } } ``` The SPI is loaded via Java `ServiceLoader` by `RemoteModuleResolverProvider` (in `nf-lang`), which selects the highest-priority implementation available. --- ### 6. PipelineSpec Reads and writes `nextflow_spec.json` in the project root. Class: `nextflow.pipeline.PipelineSpec`. ```groovy class PipelineSpec { PipelineSpec(Path baseDir) Map getModules() void addModuleEntry(String name, String version) boolean removeModuleEntry(String name) } ``` --- ### 6. ModuleResolutionResult Result of module resolution process. ```groovy @CompileStatic class ModuleResolutionResult { ModuleReference reference Path resolvedPath // Absolute path to main.nf ResolutionAction action String message // Warning/info message if any } enum ResolutionAction { USE_LOCAL, // Used existing local module DOWNLOADED, // Downloaded from registry REPLACED, // Replaced local with different version BLOCKED_MODIFIED, // Local modified, not replaced (warning issued) FAILED // Resolution failed (error) } ``` --- ## Relationships ``` PipelineSpec (1) -----> (*) ModuleReference (nextflow_spec.json) ModulesConfig (1) -----> (*) ModuleReference (nextflow.config alternative) RegistryConfig (1) -----> (*) Registry URLs ModuleReference (1) -----> (0..1) InstalledModule | v (via registry) ModuleSpec (1) <----- InstalledModule (from meta.yaml) ``` --- ## Storage Layout ``` project-root/ ├── nextflow.config # registry{} block; optional modules{} block ├── nextflow_spec.json # auto-managed module version pins ├── main.nf # include { X } from '@scope/name' └── modules/ └── @scope/ └── name/ ├── .checksum # SHA-256 from registry (download integrity) ├── main.nf # Entry point (required) ├── meta.yaml # Manifest (required for publishing) ├── README.md # Documentation (required for publishing) └── [other files] # Supporting files ``` --- ## Validation Summary | Entity | Field | Validation | |--------|-------|------------| | ModuleReference | fullName | Pattern: `^@[a-z0-9][a-z0-9-]*/[a-z][a-z0-9_-]*$` | | ModuleSpec | name | Pattern: `scope/name` or `scope/path/to/name` | | ModuleSpec | version | SemVer: `MAJOR.MINOR.PATCH[-prerelease]` | | ModuleSpec | description, license | Required (non-empty) | | InstalledModule | directory | Must contain main.nf | | ModulesConfig | modules keys | Must be valid module fullName | | RegistryConfig | url | Valid HTTPS URL |