Skip to Content

Modules

Settings → Modules (/admin/modules) is the coarsest configuration control in SeqDesk. A module is a named bundle of behaviour — usually a set of form field types, sometimes a whole subsystem — that is either on or off for the entire instance. Turning one off removes its fields from every form builder and from every form a researcher sees, no matter what each individual field’s Visible setting says.

Only a facility admin can reach the page. The whole /admin area redirects RESEARCHER accounts to /orders, and PUT /api/admin/modules — the write path — rejects anything but FACILITY_ADMIN.

Reading module state is deliberately unrestricted. The browser loads it from GET /api/modules, which requires no session at all, because a form cannot be rendered without knowing which modules are on. Treat the list of enabled modules as public information about your instance — it is.

The three-part relationship

This is the part that trips people up, so it is worth stating plainly.

A module owns a set of field types

The mapping is hard-coded in src/lib/modules/form-integration.ts, not configurable. Each module claims one or more FieldType values, plus a few well-known field names, plus a moduleSource marker written onto fields the app inserts itself.

The form builders offer those field types

A field type whose owning module is enabled can be added in the relevant builder. A field type whose module is disabled is filtered out before the builder ever renders it.

Enabling a module does not add the field

This is the step everyone misses. A module turns a field type on; it does not place a field on your form. Until you add a field of that type — by hand in the builder, or with the Form actions buttons on the module card — the module is active but invisible. The card shows an amber Missing field badge in exactly that state, and an emerald Field added badge once a matching field exists.

Two fields are the exception: a Sequencing Technology field on the order form and a MIxS field on the study form are seeded automatically while the stored configuration is still older than the shipped defaults version. funding, billing and the ENA sample fields are never seeded for you.

Field ownership is resolved in a fixed order: the field’s moduleSource first, then its type, then its name. A field that matches none of them belongs to no module and is always shown — which is why your own custom text and select fields never disappear when you toggle modules.

The modules

The page is split into four tabs, one per category.

Form Modules

Module IDNameDefaultField typesTarget form
mixs-metadataMIxS MetadataOnmixs (_mixs)Study
funding-infoExternal Funding & GrantsOfffunding (_funding, study_funding)Study
billing-infoCost Center & PSPOffbillingSequencing Order
ena-sample-fieldsENA Sample FieldsOnorganism (_organism, sample_title, sample_alias)Sequencing Order
sequencing-techSequencing TechnologyAlways onsequencing-tech, barcode (_sequencing_tech, _barcode)Sequencing Order
dynamic-studiesDynamic Study DefinitionsOff— (no field types)Study

Validation

Module IDNameDefaultEffect
ai-validationAI Field ValidationOnEnables the per-field AI validation prompt and strictness setting in the order builder, and gates POST /api/ai/validate. Contributes no field type of its own.

Access Control

Module IDNameDefaultEffect
account-validationAccount ValidationOffRestricts self-registration to a list of email domains.

Communication

Module IDNameDefaultEffect
notificationsEmail NotificationsOffMaster gate for the hosted email relay. See Email Notifications.

sequencing-tech is in ALWAYS_ENABLED_MODULE_IDS; its switch is permanently disabled and isModuleEnabled returns true for it even when the global kill switch is on. Instrument and kit registration for it lives on Sequencing Technologies.

Reading a module card

BadgeMeaning
ActiveEnabled and effective right now
InactiveSwitched off
Always activesequencing-tech; cannot be switched off
Paused (Global Off)The module’s own switch is on, but the installation-level kill switch is suppressing it
Coming SoonListed but not yet available; the switch is disabled
Settings availableThe card expands with its own settings panel when enabled
Field added / Missing fieldWhether a field owned by this module currently exists on the target form
Hidden from users when disabledShown on a disabled module that owns field types, as a reminder of the blast radius

Each card also carries a Form integration block naming the target form and the exact field types, links to the builders that can place them, and — for sequencing-tech — an Open module settings link to /admin/sequencing-tech.

Form actions

These buttons do in one click what you would otherwise do by hand in a builder. They are disabled while the module is off, and they never duplicate a field that already exists.

ModuleActionWrites to
mixs-metadataAdd MIxS to Study FormStudy form config
funding-infoAdd Funding to Study FormStudy form config
ena-sample-fieldsAdd ENA Fields to Sequencing Order FormOrder form config (per-sample)
sequencing-techAdd Sequencing Tech to Sequencing Order FormOrder form config
sequencing-techAdd Barcode to Sequencing Order FormOrder form config (per-sample)
sequencing-techApply ONT Run Plan PresetOrder form and the sequencing run questionnaire

Add Barcode stays disabled until a Sequencing Technology field exists on the order form, and pressing it early answers Add Sequencing Technology first. The barcode field is populated from the kit chosen in the technology selector, so it is meaningless without one.

Modules with their own settings

Account Validation

Expanding the enabled card gives you Allowed Email Domains. Domains are lower-cased and must contain a dot; anything else is dropped on save. The list is stored as accountValidationSettings inside SiteSettings.extraSettings.

Two switches’ worth of behaviour, from /api/register:

StateResult for a non-matching domain
Empty domain listEveryone may register — the list, not the module, is what enforces anything
Domains listed, enforcement onRegistration is refused
Domains listed, enforcement offRegistration proceeds with a warning that the domain is not approved

Matching is exact, not suffix-based. Listing example.org does not admit lab.example.org — add every subdomain you actually use, or you will lock out half your institute.

Cost Center & PSP

Configures how a billing field validates input: whether the PSP element is collected at all, its prefix range, the number of digits in the main part, its suffix range, and the example string shown to researchers — the shipped default describes 1-1234567-99. Cost centre collection has its own switch, an optional regular expression, and its own example.

Where the setting lives, and who reads it

State is one JSON string in the singleton settings row, SiteSettings.modulesConfig:

{ "modules": { "mixs-metadata": true, "ena-sample-fields": true, "dynamic-studies": false }, "globalDisabled": false }

Unknown keys are ignored and missing keys fall back to the shipped defaults, so a partial object is safe. A bare { "module-id": true } object without the modules wrapper is still accepted for backwards compatibility. If the column contains invalid JSON, every module silently reverts to its default state rather than erroring — worth remembering if you edit the database by hand.

Enforcement is not in one place. Each of these reads the same column independently:

ConsumerWhat it decides
GET /api/admin/form-configWhich fields the order builder may show
GET /api/orders/[id]/samplesWhich per-sample columns a researcher sees
src/lib/studies/schema.tsWhich study fields resolve, and whether per-study questionnaires apply
POST /api/ai/validateWhether assisted validation answers at all
POST /api/registerWhether domain restrictions apply
src/lib/notifications/settings.tsWhether hosted email is considered enabled
The sidebarStudy Forms versus Define Studies

The browser copy is loaded once per page load through a React context. A module change therefore reaches other people’s open tabs only on their next navigation, not instantly.

The global kill switch

globalDisabled forces every optional module off at once. While it is set, the page shows “Modules are globally disabled at installation level”, individual switches are frozen, and each module that was on reports Paused (Global Off) — its own stored state is preserved, so clearing the kill switch restores exactly what you had.

What breaks if you get this wrong

ChangeConsequence
Disabling ena-sample-fields after orders existOrganism, Sample Title and Sample Alias stop rendering. The values already stored on samples are untouched, but ENA submission loses the fields it needs to build a sample XML
Disabling mixs-metadata on a facility that submits to ENAStudy and sample MIxS blocks vanish from the questionnaire; existing checklist answers stay in the database, unreachable through the UI
Enabling dynamic-studies mid-flightStudies that already have their own StudyFormConfig switch to it; studies that do not keep using the global study form. Both states coexist, which is intended but surprising
Disabling dynamic-studies againPer-study questionnaires are ignored and everyone falls back to the global study form. The per-study definitions are not deleted
Enabling account-validation with an empty listNothing changes. The module is on, but with no domains it admits everyone
Enabling notifications without a relay tokenEmail stays off. The module is only one of three conditions the dispatcher checks
Setting globalDisabled on a live instanceEvery optional field type disappears from researchers’ forms at once, including required ones. Forms remain submittable, so you may silently stop collecting data you rely on

Disabling a module never deletes data. Field values already written to customFields stay exactly where they are and reappear the moment the module is re-enabled. The risk of a module toggle is what stops being collected, not what is lost.

Setting modules at install time

Module flags can be shipped in settings.json and merged over whatever is in the database by Infrastructure → Import settings.json (/admin/data-compute). The import merges rather than replaces, so a file naming three modules leaves the rest alone:

{ "modules": { "mixs-metadata": true, "ena-sample-fields": true, "billing-info": true } }

Troubleshooting

SymptomCauseFix
Module is Active but researchers see nothing newNo field of that type exists on the form yetUse the card’s Form actions button, or add the field in the builder
Card shows Missing field after you added the fieldThe field was added to the other form — module targets are fixedCheck the Used in line on the card and add it to the named form
A field is invisible even though Visible is onIts owning module is off; the module filter runs before the visibility checkRe-enable the module
Every switch is greyed outThe global kill switch is setClear globalDisabled on this page
The sequencing-tech switch will not moveIt is in ALWAYS_ENABLED_MODULE_IDSIt cannot be disabled; hide its fields in the builder instead
A colleague still sees the old stateModule state is fetched once per page loadAsk them to reload
Add Barcode is disabledNo Sequencing Technology field on the order formAdd that first
Registrations refused after enabling Account ValidationExact-match domains, subdomains excludedAdd each subdomain, or turn enforcement off to warn instead of block

See also