Skip to content

Comments

Add Mermaid system, components and container diagrams#2222

Open
gildub wants to merge 4 commits intoguacsec:mainfrom
gildub:data-model-diagram
Open

Add Mermaid system, components and container diagrams#2222
gildub wants to merge 4 commits intoguacsec:mainfrom
gildub:data-model-diagram

Conversation

@gildub
Copy link
Contributor

@gildub gildub commented Jan 29, 2026

The design/README.md articulates together the design information of the Trustify project using Mermaid providing diagram as code with the following :

  • The domain model, which purpose is to have a common domain knowledge for all participate to communicate efficiently.
  • The architecture (C4 diagrams): the system context, the container's diagram, 2 components views (API service, Ingestor service)
  • The data model represented with erDiagram (Entity Relation)
  • An how to install and use mermaid-cli tool in order to regenerate images (PNG, SVG or PDF) along with the default theme and scale parameters.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 29, 2026

Reviewer's Guide

Adds a new Mermaid-based UML classDiagram documenting the Trustify data model, including entities, relationships, and key design patterns for PURLs, SBOMs, relationships, statuses, versions, and licensing.

ER diagram for core Trustify data model

erDiagram
    advisory {
        UUID id
        UUID issuer_id
        timestamp published
        timestamp modified
        timestamp withdrawn
        String identifier
        String title
        String version
        String document_id
        jsonb labels
        UUID source_document_id
        bool deprecated
    }

    vulnerability {
        String id
        String title
        timestamp published
        timestamp modified
        timestamp withdrawn
        timestamp reserved
        text[] cwes
    }

    advisory_vulnerability {
        UUID advisory_id
        String vulnerability_id
        String title
        String summary
        String description
        timestamp discovery_date
        timestamp release_date
        timestamp reserved_date
        text[] cwes
    }

    sbom {
        UUID sbom_id
        String node_id
        String document_id
        timestamp published
        String[] authors
        jsonb labels
        UUID source_document_id
        text[] data_licenses
    }

    product {
        UUID id
        UUID vendor_id
        String name
        String cpe_key
    }

    product_version {
        UUID id
        UUID product_id
        UUID sbom_id
        String version
        timestamp timestamp
    }

    base_purl {
        UUID id
        timestamp timestamp
        String type
        String namespace
        String name
    }

    versioned_purl {
        UUID id
        UUID base_purl_id
        String version
        timestamp timestamp
    }

    qualified_purl {
        UUID id
        UUID versioned_purl_id
        jsonb qualifiers
        jsonb purl
        timestamp timestamp
    }

    status {
        UUID id
        String slug
        String name
        String description
    }

    purl_status {
        UUID id
        UUID advisory_id
        UUID status_id
        UUID base_purl_id
        UUID version_range_id
        String vulnerability_id
        UUID context_cpe_id
    }

    product_status {
        UUID id
        UUID advisory_id
        String vulnerability_id
        UUID status_id
        UUID product_version_range_id
        UUID context_cpe_id
        String package
    }

    license {
        UUID id
        String text
        text[] spdx_licenses
        text[] spdx_license_exceptions
    }

    purl_license_assertion {
        UUID id
        UUID license_id
        UUID sbom_id
        UUID versioned_purl_id
    }

    cpe_license_assertion {
        UUID id
        UUID license_id
        UUID sbom_id
        UUID cpe_id
    }

    cpe {
        UUID id
        String part
        String vendor
        String product
        String version
        String update
        String edition
        String language
        String sw_edition
        String target_sw
        String target_hw
        String other
    }

    advisory ||--o{ advisory_vulnerability : has
    vulnerability ||--o{ advisory_vulnerability : reported_in

    product ||--o{ product_version : has
    product_version }o--|| sbom : documented_by

    base_purl ||--o{ versioned_purl : has_versions
    versioned_purl ||--o{ qualified_purl : has_qualifiers

    advisory ||--o{ purl_status : affects
    advisory ||--o{ product_status : affects
    status ||--o{ purl_status : classifies
    status ||--o{ product_status : classifies

    license ||--o{ purl_license_assertion : asserted_for
    license ||--o{ cpe_license_assertion : asserted_for
    purl_license_assertion }o--|| versioned_purl : applies_to
    purl_license_assertion }o--|| sbom : in_context
    cpe_license_assertion }o--|| cpe : applies_to
    cpe_license_assertion }o--|| sbom : in_context
Loading

Class diagram for PURL hierarchy and license assertions

classDiagram
    class base_purl {
        +UUID id
        +timestamp timestamp
        +String type
        +String namespace
        +String name
    }

    class versioned_purl {
        +UUID id
        +UUID base_purl_id
        +String version
        +timestamp timestamp
    }

    class qualified_purl {
        +UUID id
        +UUID versioned_purl_id
        +jsonb qualifiers
        +jsonb purl
        +timestamp timestamp
    }

    class sbom {
        +UUID sbom_id
        +String node_id
        +String document_id
        +timestamp published
        +String[] authors
        +jsonb labels
        +UUID source_document_id
        +text[] data_licenses
    }

    class sbom_package {
        +UUID sbom_id
        +String node_id
        +String version
    }

    class sbom_package_purl_ref {
        +UUID sbom_id
        +String node_id
        +UUID qualified_purl_id
    }

    class cpe {
        +UUID id
        +String part
        +String vendor
        +String product
        +String version
        +String update
        +String edition
        +String language
        +String sw_edition
        +String target_sw
        +String target_hw
        +String other
    }

    class sbom_package_cpe_ref {
        +UUID sbom_id
        +String node_id
        +UUID cpe_id
    }

    class license {
        +UUID id
        +String text
        +text[] spdx_licenses
        +text[] spdx_license_exceptions
    }

    class purl_license_assertion {
        +UUID id
        +UUID license_id
        +UUID sbom_id
        +UUID versioned_purl_id
    }

    class cpe_license_assertion {
        +UUID id
        +UUID license_id
        +UUID sbom_id
        +UUID cpe_id
    }

    %% PURL hierarchy
    base_purl "1" --> "*" versioned_purl : has_versions
    versioned_purl "1" --> "*" qualified_purl : has_qualifiers

    %% SBOM package references
    sbom "1" --> "*" sbom_package : contains
    sbom_package "1" --> "*" sbom_package_purl_ref : has
    sbom_package "1" --> "*" sbom_package_cpe_ref : has

    %% CPE relations
    cpe "1" --> "*" sbom_package_cpe_ref : referenced_in
    cpe "1" --> "*" cpe_license_assertion : has

    %% License assertions
    license "1" --> "*" purl_license_assertion : asserted_for
    license "1" --> "*" cpe_license_assertion : asserted_for

    purl_license_assertion "*" --> "1" versioned_purl : applies_to
    purl_license_assertion "*" --> "1" sbom : in_context
    cpe_license_assertion "*" --> "1" sbom : in_context
Loading

Class diagram for advisory, vulnerability, product, and status model

classDiagram
    class advisory {
        +UUID id
        +UUID issuer_id
        +timestamp published
        +timestamp modified
        +timestamp withdrawn
        +String identifier
        +String title
        +String version
        +String document_id
        +jsonb labels
        +UUID source_document_id
        +bool deprecated
    }

    class advisory_vulnerability {
        +UUID advisory_id
        +String vulnerability_id
        +String title
        +String summary
        +String description
        +timestamp discovery_date
        +timestamp release_date
        +timestamp reserved_date
        +text[] cwes
    }

    class vulnerability {
        +String id
        +String title
        +timestamp published
        +timestamp modified
        +timestamp withdrawn
        +timestamp reserved
        +text[] cwes
    }

    class vulnerability_description {
        +UUID id
        +String vulnerability_id
        +UUID advisory_id
        +String lang
        +String description
        +timestamp timestamp
    }

    class weakness {
        +text id
        +text description
        +text extended_description
        +text[] child_of
        +text[] parent_of
        +text[] starts_with
        +text[] can_follow
        +text[] can_precede
        +text[] required_by
        +text[] requires
        +text[] can_also_be
        +text[] peer_of
    }

    class cvss3 {
        +int minor_version
        +UUID advisory_id
        +String vulnerability_id
        +cvss3_av av
        +cvss3_ac ac
        +cvss3_pr pr
        +cvss3_ui ui
        +cvss3_s s
        +cvss3_c c
        +cvss3_i i
        +cvss3_a a
        +double score
        +cvss3_severity severity
    }

    class cvss4 {
        +int minor_version
        +UUID advisory_id
        +String vulnerability_id
        +cvss4_av av
        +cvss4_ac ac
        +cvss4_at at
        +cvss4_pr pr
        +cvss4_ui ui
        +cvss4_vc vc
        +cvss4_vi vi
        +cvss4_va va
        +cvss4_sc sc
        +cvss4_si si
        +cvss4_sa sa
    }

    class organization {
        +UUID id
        +String name
        +String cpe_key
        +String website
    }

    class product {
        +UUID id
        +UUID vendor_id
        +String name
        +String cpe_key
    }

    class product_version {
        +UUID id
        +UUID product_id
        +UUID sbom_id
        +String version
        +timestamp timestamp
    }

    class product_version_range {
        +UUID id
        +UUID product_id
        +UUID version_range_id
        +String cpe_key
    }

    class status {
        +UUID id
        +String slug
        +String name
        +String description
    }

    class purl_status {
        +UUID id
        +UUID advisory_id
        +UUID status_id
        +UUID base_purl_id
        +UUID version_range_id
        +String vulnerability_id
        +UUID context_cpe_id
    }

    class product_status {
        +UUID id
        +UUID advisory_id
        +String vulnerability_id
        +UUID status_id
        +UUID product_version_range_id
        +UUID context_cpe_id
        +String package
    }

    class version_range {
        +UUID id
        +String version_scheme_id
        +String low_version
        +bool low_inclusive
        +String high_version
        +bool high_inclusive
    }

    class version_scheme {
        +String id
        +String name
        +String description
    }

    class base_purl {
        +UUID id
        +timestamp timestamp
        +String type
        +String namespace
        +String name
    }

    class cpe {
        +UUID id
        +String part
        +String vendor
        +String product
        +String version
        +String update
        +String edition
        +String language
        +String sw_edition
        +String target_sw
        +String target_hw
        +String other
    }

    class sbom {
        +UUID sbom_id
        +String node_id
        +String document_id
        +timestamp published
        +String[] authors
        +jsonb labels
        +UUID source_document_id
        +text[] data_licenses
    }

    %% Advisory and vulnerability relations
    advisory "1" --> "*" advisory_vulnerability : has
    advisory "1" --> "*" cvss3 : has_scores
    advisory "1" --> "*" cvss4 : has_scores
    advisory "1" --> "*" purl_status : affects
    advisory "1" --> "*" product_status : affects
    advisory "1" --> "*" vulnerability_description : has

    vulnerability "1" --> "*" advisory_vulnerability : reported_in
    vulnerability "1" --> "*" vulnerability_description : has
    vulnerability "1" --> "*" cvss3 : has_scores
    vulnerability "1" --> "*" cvss4 : has_scores
    weakness "1" --> "*" vulnerability : categorizes

    %% Product hierarchy
    organization "1" --> "*" product : owns
    product "1" --> "*" product_version : has
    product "1" --> "*" product_version_range : has
    product_version "*" --> "0..1" sbom : documented_by
    product_version_range "*" --> "1" version_range : uses

    %% Status tracking
    purl_status "*" --> "1" base_purl : applies_to
    purl_status "*" --> "1" status : has
    purl_status "*" --> "1" advisory : from
    purl_status "*" --> "1" version_range : version_constraint
    purl_status "*" --> "0..1" cpe : context

    product_status "*" --> "1" status : has
    product_status "*" --> "1" advisory : from
    product_status "*" --> "1" product_version_range : applies_to
    product_status "*" --> "0..1" cpe : context

    %% Version scheme
    version_range "*" --> "1" version_scheme : uses_scheme
Loading

File-Level Changes

Change Details Files
Introduce Mermaid UML class diagram documenting the Trustify data model.
  • Create docs/design/data-model.md with a Mermaid classDiagram describing all core domain tables (advisory, vulnerability, SBOM, PURL hierarchy, products, statuses, licenses, CPEs, importer, etc.) and their attributes.
  • Model entity relationships directly in Mermaid (associations, inheritance, multiplicities) to show how advisories, vulnerabilities, SBOM components, PURLs, products, and statuses connect.
  • Annotate the model with Mermaid notes to clarify conceptual roles of key entities like base_purl, sbom, advisory, and vulnerability.
docs/design/data-model.md
Document key architectural patterns used in the data model.
  • Describe the three-tier PURL hierarchy (BasePurl, VersionedPurl, QualifiedPurl) and how it normalizes package URLs.
  • Explain the SBOM node hierarchy using a discriminated-union pattern between sbom_node, sbom_package, and sbom_file.
  • Outline the relationship graph pattern using package_relates_to_package and relationship to model directed edges between packages.
  • Summarize dual status tracking for purl_status and product_status to distinguish package URL vs product-centric vulnerability status.
  • Describe version matching via version_scheme and version_range, hinting at PostgreSQL-backed comparison per version scheme.
docs/design/data-model.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Consider adding a short legend/section explaining the meaning of the data types used in the diagram (e.g., String vs text vs jsonb, timestamp vs timestamptz) so that readers can more easily map them to the actual database types and semantics.
  • Some entities mix String-based identifiers and UUID-based identifiers for id fields (e.g., vulnerability.id as String vs most others as UUID); it may help to briefly call out where String IDs represent external identifiers (like CVE IDs) to avoid confusion with internal primary keys.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider adding a short legend/section explaining the meaning of the data types used in the diagram (e.g., String vs text vs jsonb, timestamp vs timestamptz) so that readers can more easily map them to the actual database types and semantics.
- Some entities mix String-based identifiers and UUID-based identifiers for `id` fields (e.g., `vulnerability.id` as String vs most others as UUID); it may help to briefly call out where String IDs represent external identifiers (like CVE IDs) to avoid confusion with internal primary keys.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link

codecov bot commented Jan 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.24%. Comparing base (083ccfe) to head (58ae3a3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2222      +/-   ##
==========================================
+ Coverage   69.22%   69.24%   +0.01%     
==========================================
  Files         414      414              
  Lines       23304    23304              
  Branches    23304    23304              
==========================================
+ Hits        16132    16136       +4     
+ Misses       6262     6252      -10     
- Partials      910      916       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ctron
Copy link
Contributor

ctron commented Jan 30, 2026

Wouldn't an ER diagram be a better fit for this?

Also, why does it have another diagram as PNG? And how do we ensure this stays in sync? Which tool was used to create this? Can the resolution be enhanced.

@gildub
Copy link
Contributor Author

gildub commented Jan 31, 2026

Wouldn't an ER diagram be a better fit for this?

You're right, I've changed it to an ER diagram. This was actually an intermediary stage as I had to create the domain model (added now) by reverse engineer the data model.

Also, why does it have another diagram as PNG? And how do we ensure this stays in sync? Which tool was used to create this? Can the resolution be enhanced.

Having diagrams exported as a png files provides extra visualization options offering flexibility to communicate about the project.
I created a README.md file providing the Mermaid tool rendering images so we can ultimately have those regenerated automatically from the diagram code.

@gildub gildub force-pushed the data-model-diagram branch 3 times, most recently from 7537a59 to a8ac001 Compare January 31, 2026 12:38
@gildub gildub changed the title Add Mermaid data model diagram Add Mermaid system, components and container diagrams Feb 1, 2026
@gildub gildub force-pushed the data-model-diagram branch 2 times, most recently from 5d6d8f0 to 6c5567c Compare February 4, 2026 14:25
@ctron
Copy link
Contributor

ctron commented Feb 6, 2026

Thanks for explaining this. I still don't see the benefit of having the (quite small) PNG, compared to the complexity it adds. And the problems when things go out of alignment.

I think it's easy enough to view the diagram on GitHub, and at least in IntelliJ too. I'd assume VScode has something similar.

So which case would require having this PNG?

@gildub
Copy link
Contributor Author

gildub commented Feb 10, 2026

@ctron,

The PNG (or SVG, JPEG) are definitely optional and I understand everyone might have different needs to use them or not. I removed the images and let's keep only the instruction for anyone to generate them if needed.

@ctron
Copy link
Contributor

ctron commented Feb 11, 2026

@ctron,

The PNG (or SVG, JPEG) are definitely optional and I understand everyone might have different needs to use them or not. I removed the images and let's keep only the instruction for anyone to generate them if needed.

Could it be that you forgot to push those changes, as they still seem to be part of the PR.

@ctron
Copy link
Contributor

ctron commented Feb 11, 2026

Just to understand the process, whenever we do changes in the codebase, how to we update these diagrams?

@gildub gildub force-pushed the data-model-diagram branch from 6c5567c to 49372a2 Compare February 16, 2026 09:30
@gildub
Copy link
Contributor Author

gildub commented Feb 16, 2026

@ctron, sorry I missed the change, now the generated images are removed.

Regarding the process of updating the diagrams, I believe that should be initiated from a new ADR.

@gildub gildub force-pushed the data-model-diagram branch from 49372a2 to 58ae3a3 Compare February 18, 2026 07:45
@ctron
Copy link
Contributor

ctron commented Feb 18, 2026

Regarding the process of updating the diagrams, I believe that should be initiated from a new ADR.

Yes, how would that relate to the folder https://github.com/guacsec/trustify/blob/main/docs/design/

@helio-frota
Copy link
Contributor

nice content 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants