Architecture

This document contains the architectural design for zen-do. For design details of the Seedcase Project as a whole, see the Seedcase Design documentation.

The purpose of this description is to ensure that the team shares a common understanding about the implementation and to outline the design to anyone else interested in the internal workings of the package.

Actions and objects

This section describes the different actions and objects used throughout the package.

Objects used in zen-do.
Object Description
deposit(s) A Zenodo deposit is the combined set of files and metadata that make up the content that will eventually form the published record.
record(s) A Zenodo record is a given published set of metadata and files for a specific DOI.
metadata The metadata for a deposit, kept within a file .zenodo.toml.
file(s) The files to add to a deposit.
format The file formats for the Zenodo metadata file(s) to convert between.
token The Zenodo personal access token to authenticate with the Zenodo API.
Actions used in zen-do.
Action Description
init Create an empty metadata file to be filled in.
list List all Zenodo deposits in an account.
get Get a Zenodo deposit in an account from a metadata file.
convert Convert metadata files to and from different formats.
update Updates an existing Zenodo deposit’s metadata only (not file) based on the contents of a metadata file.
publish Publish a new Zenodo record from an existing or new Zenodo deposit based on the metadata file and, if given, updating the file(s) in the deposit.
discard Discard a draft of or update to a Zenodo deposit (but not record).

Metadata file

The only allowable metadata file format that zen-do uses is TOML, which is a simple, human-readable format that is easy to write and read. Why TOML rather than Zenodo’s suggested JSON format? JSON is not a friendly format for humans to write and read, it doesn’t allow comments, and doesn’t support multi-line strings, which can be useful for writing long descriptions. TOML is the opposite, as it allows comments, multi-line strings, and is more human-friendly.

The file is named .zenodo.toml and contains all the metadata for a Zenodo deposit. The file can be converted to and from other formats, such as .zenodo.json, _quarto.yml, pyproject.toml, and CITATION.cff (filling in the relevant fields where relevant in those other formats).

We use the design pattern of “one .zenodo.toml file for one Zenodo deposit”. So this file must be given (or present in the working directory) for many of the actions to work. There must also be a unique “related identifier” for this (new or existing) deposit added to this .zenodo.toml file in order to identify it within the list of deposits of a user’s account. This is described in more detail in the interface documentation.

C4 Models

This section contains diagrams for zen-do that are inspired by the C4 Model. The C4 Model is an established visualisation approach to describe the architecture of a software system. It breaks the system down into four levels of architectural abstraction: system context, containers, components, and code. For zen-do, we only use diagrams that are similar to the context and container models.

System context

The system context diagram shows the users and external systems that interact with zen-do. The users provide zen-do with the metadata file, the file or files to add to a Zenodo deposit, and the token for the Zenodo account.

flowchart TB
    user("User<br>[person]"):::user
    metadata[/"Metadata file<br>['.zenodo.toml']"/]
    metadata_formats("Metadata formats<br>[e.g. 'cff', 'json',<br>'toml', 'yml']")
    deposit("Deposit<br>[Zenodo server]"):::external
    record("Record<br>[Zenodo server]"):::external
    file[/"File<br>[e.g. PDF]"/]
    token[/"Token<br>[authentication]"/]
    zen_do["zen-do<br>[CLI]"]

    user -->|edit| metadata
    user -->|provide| token
    metadata -->|read| zen_do
    metadata <-.->|convert| metadata_formats
    token --> zen_do
    zen_do -->|convert| metadata_formats
    file -->|add| zen_do
    user --> file
    zen_do -->|publish<br>update<br>discard<br>list<br>get| deposit
    deposit -.->|publish| record

    %% Styling
    classDef user fill:#FFFFFF,color:#000000;
    classDef external fill:#F5F5F5;
Figure 1: Diagram showing the interaction between user and external systems that zen-do interacts with. The parallogram boxes represent input, the rectangle represents the CLI, and the rounded boxes represent the start and end points of the flow. The gray boxes represent external systems, in this case, the Zenodo server.

Container/component

In C4, a container diagram zooms in on the system boundary to show the containers within it while a a component diagram is “a grouping of related functionality encapsulated behind a well-defined interface”, like a class or a module. For zen-do, we have a single container (the CLI) so we combine the container and component diagrams into one. The diagram below shows the main actions and objects within zen-do, how they interact with each other at a high level, and the technologies used for each.

flowchart TB
    user("User<br>[person]"):::user

    subgraph input ["Input"]
        metadata[/"Metadata file<br>['.zenodo.toml']"/]
        file[/"File<br>[e.g. PDF]"/]
        token[/"Token<br>[authentication]"/]
    end

    subgraph zen-do
        init["init<br>[Python]"]
        get["get<br>[Python]"]
        list["list<br>[Python]"]
        convert["convert<br>[Python]"]
        update["update<br>[Python]"]
        publish["publish<br>[Python]"]
        discard["discard<br>[Python]"]
        deposit[/"Deposit<br>[Zenodo server]"/]:::external
        account[/"Account<br>[Zenodo server]"/]:::external

        update & discard & publish -->|request| deposit
        get & list -->|request| account
    end

    subgraph output ["Output"]
        record("Record<br>[Zenodo server]"):::external
        metadata_formats("Metadata formats<br>[e.g. 'cff', 'json',<br>'toml', 'yml']")
        empty_metadata("Empty metadata file<br>['.zenodo.toml']")
        deposit_get("Deposit<br>[JSON]")
        deposits_list("List of deposits<br>[JSON]")
    end

    deposit -.->|publish| record
    account -->|response| deposit_get
    account -->|response| deposits_list
    convert --> metadata_formats
    init -->|create| empty_metadata
    user --> input
    token -->|required<br>except init<br>and convert| zen-do
    metadata -->|required<br>except init<br>and list| zen-do
    file -->|required| publish

    %% Styling
    style zen-do fill:#FFFFFF,color:#000000;
    style output fill:#FFFFFF,color:#000000;
    style input fill:#FFFFFF,color:#000000;
    classDef user fill:#FFFFFF,color:#000000;
    classDef external fill:#F5F5F5;
Figure 2: Diagram showing the inputs, outputs, and actions within zen-do. Parallogram boxes represent input and output, the rectangles represents actions, and the rounded boxes represent the start and end points of the flow. The gray boxes represent external systems, in this case, the Zenodo server.