Dataset Lifecycle¶
Datasets are git/git-annex repositories managed by datalad-service. This document describes the states a dataset, its snapshots, and their DOIs pass through, and the mutations that drive transitions between them.
Dataset states¶
A dataset’s state is determined by two fields: whether it has any snapshots and whether it is public.
stateDiagram-v2
[*] --> Draft
Draft --> Embargoed : createSnapshot()
Embargoed --> Public : publishDataset()
Public --> Embargoed : updatePublic(false) [admin]
Draft --> Deleted : deleteDataset()
Embargoed --> Deleted : deleteDataset()
Public --> Deleted : deleteDataset()
State |
Determination |
DB representation |
|---|---|---|
Draft |
Unversioned, private |
|
Embargoed |
Versioned, private |
|
Public |
Versioned, public |
|
Deleted |
Dataset removed |
|
These states are implicit — there is no Dataset.status field. The code
does not use the term “embargoed”; both Draft and Embargoed datasets have
public = false and are distinguished only by the presence of snapshots.
Key constraints:
Draft → Embargoed is irreversible. Once a snapshot exists, the dataset cannot return to Draft.
Public → Embargoed requires admin privileges.
Creation¶
createDataset() creates a new Dataset document with public: false
and fires a { type: "created" } event.
JS:
packages/openneuro-server/src/datalad/dataset.ts
Snapshotting (Draft → Embargoed, or new version)¶
createSnapshot() tags the current HEAD as a new version. The first
snapshot transitions the dataset from Draft to Embargoed. Subsequent
snapshots do not change the dataset state.
JS:
packages/openneuro-server/src/datalad/snapshots.tsPython:
services/datalad/datalad_service/tasks/snapshots.pyEvent:
{ type: "versioned", version: tag }
Sequence:
Acquire distributed lock (
lockSnapshot(), 30-min TTL)Create
"versioned"eventMint DOI via DataCite MDS API (
createIfNotExistsDoi()) — format:doi:{prefix}/openneuro.{datasetId}.v{tag}Update
dataset_description.jsonwithDatasetDOIfieldUpdate
CHANGESfile with version and changelog entriesPOST to datalad-service to create git tag
Store
Snapshotdocument in MongoDBClear Redis caches
Queue for Elasticsearch indexing
Notify dataset followers
Preconditions: BIDS validation and git-annex fsck should pass before
creating a snapshot. This is currently enforced in the UI, not in the
createSnapshot() API.
Publishing (Embargoed → Public)¶
publishDataset() sets Dataset.public = true and triggers export to
S3 and GitHub.
JS resolver:
packages/openneuro-server/src/graphql/resolvers/publish.tsJS function:
packages/openneuro-server/src/datalad/dataset.ts—updatePublic()Python task:
services/datalad/datalad_service/tasks/publish.pyEvent:
{ type: "published", public: true }
Sequence:
Check write permissions
Set
Dataset.public = trueandDataset.publishDate = new Date()Create
"published"eventPOST to datalad-service
/datasets/{id}/publishCreate S3 and GitHub remotes (
create_remotes_and_export())Export dataset to S3-PUBLIC and GitHub (
export_dataset())Set S3 access tags to “public”
Run remote fsck to verify exported data
Drop local annexed files after verification
Re-embargo (Public → Embargoed)¶
updatePublic(datasetId, false, user) sets Dataset.public = false and
updates S3 access tags to “private”.
JS:
packages/openneuro-server/src/datalad/dataset.ts—updatePublic()Event:
{ type: "published", public: false }
Known issue: This also sets Dataset.publishDate = new Date() rather
than clearing it.
Deletion¶
deleteDataset() removes the dataset from the git backend and
Elasticsearch. Currently, datasets with snapshots require admin action to
delete.
JS:
packages/openneuro-server/src/datalad/dataset.ts—deleteDataset()Event:
{ type: "deleted" }Creates a
Deletiondocument (datasetId, user, reason, optional redirect URL)
Snapshot status¶
Snapshots can be independently deprecated without changing the dataset’s state.
stateDiagram-v2
[*] --> Active : createSnapshot()
Active --> Deprecated : deprecateSnapshot()
Deprecated --> Active : undoDeprecateSnapshot()
Status |
DB representation |
|---|---|
Active |
|
Deprecated |
|
JS:
packages/openneuro-server/src/graphql/resolvers/snapshots.ts
DOI assignment¶
Each snapshot is assigned a DOI via the DataCite MDS API at creation time. DOIs are minted immediately as findable — there is no state management after creation.
Field |
Value |
|---|---|
Format |
|
API |
DataCite MDS (XML metadata + |
Created |
During |
State |
Not tracked locally |
JS:
packages/openneuro-server/src/libs/doi/index.tsHandler:
packages/openneuro-server/src/handlers/doi.tsModel:
packages/openneuro-server/src/models/doi.ts— fields:datasetId,snapshotId,doi
DOI metadata includes creators, title, publisher (“Openneuro”),
publication year, and resource type. The DOI string is written into
dataset_description.json before the git tag is created.
DOI state is never updated after creation. The DOI remains findable at DataCite regardless of whether the dataset is later re-embargoed, the snapshot is deprecated, or the dataset is deleted.
Working tree¶
The working tree (git HEAD) can diverge from the latest snapshot when users upload or edit files. Draft datasets are always diverged (no snapshot exists). For Embargoed and Public datasets:
Status |
Determination |
|---|---|
Clean |
|
Diverged |
|
Divergence does not change the dataset’s lifecycle state. A new
createSnapshot() call is required to tag the current HEAD.
JS:
packages/openneuro-server/src/datalad/draft.ts—getDraftRevision(),getDraftInfo(),resetDraft()
Data retention¶
When the working tree diverges from the latest snapshot, a notification schedule enforces data retention:
14 days diverged: first warning email
21 days: second warning
28 days: deletion notice
No snapshot within 24h of first upload: one-time reminder
JS:
packages/openneuro-server/src/datalad/dataRetentionNotifications.ts
Validation¶
Validation is a precondition for snapshotting, not a persistent state. Two checks are involved:
BIDS schema validation¶
Runs the BIDS validator (deno-based, v2.3.2) against a specific commit.
JS resolver:
packages/openneuro-server/src/graphql/resolvers/validation.ts—revalidate()Python task:
services/datalad/datalad_service/tasks/validator.py—validate_dataset()Storage:
Validationcollection
git-annex fsck¶
Checks data consistency of annexed files.
JS resolver:
packages/openneuro-server/src/graphql/resolvers/fileCheck.ts—fsckDataset()Python task:
services/datalad/datalad_service/tasks/fsck.py—git_annex_fsck_local()Runs
git-annex fsck -J4with incremental 45-day scheduleStorage:
FileCheckcollection
Data model reference¶
MongoDB collections¶
Collection |
File |
Key fields |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All model files are under packages/openneuro-server/src/models/.
GraphQL types¶
Defined in packages/openneuro-server/src/graphql/schema.ts:
Dataset— core entity withpublic,publishDate,draft,snapshotsDraft— working tree withmodified,summary,validation,fileCheckSnapshot— tagged version withtag,hexsha,deprecatedDeprecatedSnapshot— deprecation recordDatasetValidation— validation results with error/warning counts
Mutations¶
Mutation |
Effect |
|---|---|
|
Creates dataset in Draft state |
|
Creates snapshot + DOI; Draft → Embargoed on first |
|
Embargoed → Public; exports to S3/GitHub |
|
Public → Embargoed (admin only) |
|
Marks a snapshot as deprecated |
|
Removes deprecation |
|
Removes dataset (admin required if snapshots exist) |
|
Triggers git-annex fsck |
|
Triggers BIDS validation |
Event types¶
Dataset events are stored in the DatasetEvent collection and track all
state transitions:
created · versioned · deleted · published · permissionChange ·
git · upload · note · contributorRequest · contributorCitation ·
contributorRequestResponse · contributorCitationResponse