<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeferson F Silva</title>
    <description>The latest articles on DEV Community by Jeferson F Silva (@jeferson0993).</description>
    <link>https://dev.to/jeferson0993</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F313302%2F910e5872-d4b4-4cfb-bcf1-6f68ceaac789.jpeg</url>
      <title>DEV Community: Jeferson F Silva</title>
      <link>https://dev.to/jeferson0993</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeferson0993"/>
    <language>en</language>
    <item>
      <title>Building a Biomedical Data Lake with FastAPI, MinIO, and PostgreSQL</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Wed, 17 Jun 2026 13:15:41 +0000</pubDate>
      <link>https://dev.to/jeferson0993/building-a-biomedical-data-lake-with-fastapi-minio-and-postgresql-50pk</link>
      <guid>https://dev.to/jeferson0993/building-a-biomedical-data-lake-with-fastapi-minio-and-postgresql-50pk</guid>
      <description>&lt;p&gt;&lt;strong&gt;How to implement a dataset catalog with 4 immutable layers, full provenance tracking, and automated backup for bioinformatics environments&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Biomedical computational research deals with data from dozens of public sources: NCBI GEO (gene expression), UniProt (proteins), PubMed (literature), PDB (structures), DrugBank, and more. Each with different formats, update frequencies, and quality levels.&lt;/p&gt;

&lt;p&gt;Without governance, the typical scenario is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data downloaded manually, scattered across folders&lt;/li&gt;
&lt;li&gt;Nobody knows which version was used in which analysis&lt;/li&gt;
&lt;li&gt;Reproducibility? Good luck&lt;/li&gt;
&lt;li&gt;Collaboration? Everyone has their own copy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We built the &lt;strong&gt;Biomedical Data Lake&lt;/strong&gt; to solve this — a centralized catalog with 4 immutable layers, graph-based provenance, and automated backup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The Data Lake organizes data into &lt;strong&gt;4 layers&lt;/strong&gt;, each corresponding to a MinIO bucket (S3-compatible):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;raw/        → Original collected data (immutable, 90-day object-lock)
processed/  → Filtered, normalized, or aligned data
curated/    → Curated and annotated data ready for consumption
archive/    → Historical snapshots for audit (180-day lifecycle)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Promotion between layers is &lt;strong&gt;always adjacent&lt;/strong&gt; (&lt;code&gt;raw → processed → curated → archive&lt;/code&gt;) and performs a &lt;strong&gt;copy&lt;/strong&gt; — no data is ever altered in-place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python 3.12+ / FastAPI (async)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ORM&lt;/td&gt;
&lt;td&gt;SQLAlchemy 2.0 (async) + Alembic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;Pydantic v2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object storage&lt;/td&gt;
&lt;td&gt;MinIO (S3-compatible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;PostgreSQL 16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla TypeScript + Vite + Plotly + Tailwind 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;pytest + httpx + respx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lint/Type&lt;/td&gt;
&lt;td&gt;ruff + mypy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;prometheus-fastapi-instrumentator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Data Model
&lt;/h2&gt;

&lt;p&gt;The core of the system is the &lt;code&gt;datasets&lt;/code&gt; table in PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/dataset.py
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;datasets&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapped_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as_uuid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SourceType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="c1"&gt;# geo, ncbi_gene, pubmed, uniprot, upload
&lt;/span&gt;    &lt;span class="n"&gt;external_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# GSE2034, P04637, 32581362...
&lt;/span&gt;    &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;       &lt;span class="c1"&gt;# raw, processed, curated, archive
&lt;/span&gt;    &lt;span class="n"&gt;minio_bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;minio_prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;file_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;total_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapped_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# {"source": "geo", "date": "2026-06-17", "version": "v1"}
&lt;/span&gt;    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapped_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each dataset carries mandatory JSONB metadata (&lt;code&gt;source&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;) — validated in the schema and auto-filled if omitted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/schemas/catalog.py
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatasetCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SourceType&lt;/span&gt;
    &lt;span class="n"&gt;external_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatasetLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;
    &lt;span class="n"&gt;minio_bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;minio_prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="nd"&gt;@model_validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;after&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_ensure_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DatasetCreate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Layer Promotion
&lt;/h2&gt;

&lt;p&gt;The golden rule: &lt;strong&gt;raw data is immutable&lt;/strong&gt;. The API blocks &lt;code&gt;DELETE&lt;/code&gt; on the &lt;code&gt;raw&lt;/code&gt; layer, and MinIO has active object-lock.&lt;/p&gt;

&lt;p&gt;Promoting a dataset performs a &lt;strong&gt;copy&lt;/strong&gt; of the objects in MinIO plus a provenance record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/services/layer_service.py
&lt;/span&gt;&lt;span class="n"&gt;_LAYER_ORDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;curated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DatasetLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;promote_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PromoteRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataset_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dataset not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;current_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_LAYER_ORDER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;target_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_LAYER_ORDER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_idx&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;current_idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ServiceError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot promote from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Only adjacent promotion is allowed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Copy objects in MinIO (never move)
&lt;/span&gt;    &lt;span class="n"&gt;mc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MinioClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minio_bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minio_prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;source_bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minio_bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;dest_bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;dest_object&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minio_prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;object_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;old_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minio_bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;

    &lt;span class="n"&gt;provenance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Provenance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;dataset_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ProvenanceAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;layer_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;old_layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;layer_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provenance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source_layer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;old_layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_layer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_layer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Graph Provenance
&lt;/h2&gt;

&lt;p&gt;Every transformation records its ancestry. The &lt;code&gt;/provenance/{id}/graph&lt;/code&gt; endpoint returns the full graph — useful for audit and lineage tracking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/provenance.py
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Provenance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provenance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;dataset_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# FK → datasets
&lt;/span&gt;    &lt;span class="n"&gt;source_dataset_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# FK → datasets (optional)
&lt;/span&gt;    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ProvenanceAction&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;       &lt;span class="c1"&gt;# collection, promotion, pipeline, manual
&lt;/span&gt;    &lt;span class="n"&gt;layer_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DatasetLayer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;layer_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DatasetLayer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapped_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  API Endpoints
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Catalog
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List/search datasets (&lt;code&gt;?layer=&amp;amp;source=&amp;amp;q=&amp;amp;tags=&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog/stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Statistics (datasets per layer, storage per source)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dataset details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog/{id}/files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List files in MinIO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog/{id}/download/{filename}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Presigned URL for download&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create dataset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/catalog/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete (blocked if layer = raw)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Provenance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/provenance/{dataset_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Linear lineage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/provenance/{dataset_id}/graph&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full graph (ancestors + descendants)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Backup
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/backup/trigger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trigger manual backup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/backup/jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/backup/jobs/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Job details&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Frontend: Scientific Dashboard
&lt;/h2&gt;

&lt;p&gt;The frontend (Vanilla TypeScript + Vite + Plotly) has 5 pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard&lt;/strong&gt; — Plotly charts: datasets per layer, storage per source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catalog&lt;/strong&gt; — table with search/filters/pagination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset Detail&lt;/strong&gt; — metadata, files, provenance timeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layers&lt;/strong&gt; — cards with counts, promote button, history&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup&lt;/strong&gt; — job status, manual trigger&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Practical Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Catalog a dataset
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8002/catalog &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "GSE2034 - Breast Cancer Metastasis",
    "source": "geo",
    "external_id": "GSE2034",
    "layer": "raw",
    "minio_bucket": "raw",
    "minio_prefix": "geo/GSE2034"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Promote to processed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8002/layers/promote &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "dataset_id": "&amp;lt;uuid&amp;gt;",
    "target_layer": "processed",
    "notes": "After FastQC + MultiQC"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View provenance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8002/provenance/&amp;lt;uuid&amp;gt;/graph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trigger backup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8002/backup/trigger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Automated Backup
&lt;/h2&gt;

&lt;p&gt;The scheduler runs on asyncio with hourly checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily&lt;/strong&gt; at 2 AM: copies data to &lt;code&gt;archive/backups/daily/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly&lt;/strong&gt; Sunday at 3 AM: &lt;code&gt;archive/backups/weekly/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/tasks/backup_scheduler.py
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_needs_backup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_run_backup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Testing: 29 Tests with Mocks
&lt;/h2&gt;

&lt;p&gt;The testing strategy combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit tests&lt;/strong&gt; — mock SQLAlchemy session and MinIO via fixtures in &lt;code&gt;conftest.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration tests&lt;/strong&gt; — requires real PostgreSQL + MinIO on &lt;code&gt;localhost&lt;/code&gt;, with &lt;code&gt;@pytest.mark.skipif&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Unit tests&lt;/span&gt;
uv run pytest tests/ &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Integration&lt;/span&gt;
uv run pytest tests/test_integration/ &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Async is great for I/O, terrible for debugging.&lt;/strong&gt; Async tests with &lt;code&gt;pytest-asyncio&lt;/code&gt; + mocks require careful fixture scoping.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Immutability pays dividends.&lt;/strong&gt; Having raw data protected by object-lock + API enforcement prevents accidents. Every transformation creates a new artifact — nothing is lost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JSONB with schema validation.&lt;/strong&gt; Mandatory metadata (&lt;code&gt;source&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;) is validated in Pydantic before reaching the database. The rest of the JSONB is free-form for each source.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MinIO + async is not trivial.&lt;/strong&gt; The &lt;code&gt;minio-py&lt;/code&gt; client is not natively async. We built a wrapper with &lt;code&gt;run_in_executor&lt;/code&gt; to avoid blocking the event loop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Promotion as copy.&lt;/strong&gt; Copying objects between buckets may seem inefficient, but it's the only way to guarantee the raw layer stays intact. For production with large datasets, an async job would be better.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frameworkless frontend.&lt;/strong&gt; Vanilla TS + Vite + Plotly handled a scientific dashboard well. Fewer dependencies, more control.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;This project is part of a larger monorepo (16 bioinformatics projects). The full code is at: &lt;a href="https://github.com/jeferson0993/02-data-lake" rel="noopener noreferrer"&gt;GitHub: jeferson0993/02-data-lake&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;02-data-lake/
├── app/           → FastAPI backend
├── frontend/      → TypeScript SPA
├── tests/         → 29 tests
└── docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you work with scientific data or need a governed dataset catalog, I hope this project serves as inspiration. The &lt;strong&gt;FastAPI + MinIO + PostgreSQL&lt;/strong&gt; stack is light enough for an academic lab and robust enough for production.&lt;/p&gt;

&lt;p&gt;Comments and questions are welcome!&lt;/p&gt;

&lt;p&gt;GET IN TOUCHE: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/jeferson-f-silva-a01083379/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeferson0993" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>postgres</category>
      <category>bioinformatics</category>
    </item>
    <item>
      <title>Integrated Biological Data Collection Platform: An Architecture for Automated Curation of Public Repositories</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Mon, 01 Jun 2026 12:51:29 +0000</pubDate>
      <link>https://dev.to/jeferson0993/integrated-biological-data-collection-platform-an-architecture-for-automated-curation-of-public-3fl7</link>
      <guid>https://dev.to/jeferson0993/integrated-biological-data-collection-platform-an-architecture-for-automated-curation-of-public-3fl7</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In contemporary research, the volume of biological data deposited in public repositories is growing exponentially. The Gene Expression Omnibus (GEO), NCBI Gene, PubMed, and UniProt accumulate thousands of new records daily, including sequences, expression profiles, scientific articles, and functional annotations. On the one hand, this scenario represents a unique opportunity for biomedical research. On the other hand, the diversity of data formats, access protocols, and metadata models creates a significant barrier: each source requires a specific collector, distinct rate-limiting strategies, and its own validation logic. Above all, the lack of standardization in data storage compromises the reproducibility of scientific studies. The need for integrated tools capable of unifying data extraction, curation, and persistence has been widely discussed. In practice, ad hoc solutions such as isolated scripts for individual repositories generate redundant work and make maintenance difficult. First and foremost, it is necessary to establish an architecture that treats data collection as a service rather than a collection of scattered artifacts.&lt;/p&gt;

&lt;p&gt;This work presents Project 1 of the Integrated Bioinformatics Platform: a containerized Biomedical Data Collector coupled with a Data Lake. Its objective is to provide a REST API capable of triggering asynchronous data collections from the four aforementioned sources, storing immutable raw data in MinIO, and persisting metadata in PostgreSQL, all while ensuring traceability and resilience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Development
&lt;/h1&gt;

&lt;p&gt;The system architecture is divided into three main layers. The first is the &lt;strong&gt;API and orchestration layer&lt;/strong&gt;, implemented using FastAPI. Its five endpoints — &lt;code&gt;POST /collections&lt;/code&gt;, &lt;code&gt;GET /collections&lt;/code&gt;, &lt;code&gt;GET /collections/{id}&lt;/code&gt;, &lt;code&gt;GET /collections/{id}/download/{dataset_id}&lt;/code&gt;, and &lt;code&gt;GET /health&lt;/code&gt; — expose a clean interface for initiating and monitoring collection processes. The second layer is the &lt;strong&gt;collector engine&lt;/strong&gt;, composed of abstract classes and concrete implementations for GEO, NCBI Gene, PubMed, and UniProt. Each collector follows the same lifecycle: fetch, validate, upload, and metadata generation. The third layer is the &lt;strong&gt;Data Lake&lt;/strong&gt;, built on MinIO for object storage and PostgreSQL for relational metadata management. Docker Compose orchestrates the three primary services — API, PostgreSQL, and MinIO — as well as a one-shot job responsible for creating the raw-data bucket.&lt;/p&gt;

&lt;p&gt;Furthermore, the collection workflow was designed with resilience in mind. When a user submits a POST request containing a &lt;code&gt;source&lt;/code&gt; and an &lt;code&gt;external_id&lt;/code&gt;, the system creates a &lt;code&gt;Collection(status=pending)&lt;/code&gt; record in PostgreSQL and launches an asynchronous background task. This task updates the status to &lt;code&gt;running&lt;/code&gt;, downloads data from the external source using configurable exponential retry and backoff mechanisms, validates both format and content, uploads the data to MinIO under the path &lt;code&gt;raw/{source}/{external_id}/&lt;/code&gt;, and generates a &lt;code&gt;metadata.json&lt;/code&gt; file alongside the collected data. Finally, it inserts the corresponding &lt;code&gt;Dataset&lt;/code&gt; records and marks the collection as &lt;code&gt;completed&lt;/code&gt;. In case of failure, the status is changed to &lt;code&gt;failed&lt;/code&gt;, and the error message is preserved for later inspection.&lt;/p&gt;

&lt;p&gt;The technology stack was selected carefully. The &lt;code&gt;uv&lt;/code&gt; dependency manager was chosen due to its speed and reproducible lockfile mechanism. SQLAlchemy 2.0 in asynchronous mode, combined with Alembic migrations, provides a robust persistence layer. Pydantic v2 integrates seamlessly with FastAPI, allowing the same schemas to be reused for validation and automatic documentation. Testing frameworks such as &lt;code&gt;pytest&lt;/code&gt;, &lt;code&gt;httpx&lt;/code&gt;, &lt;code&gt;pytest-asyncio&lt;/code&gt;, and &lt;code&gt;respx&lt;/code&gt; enable HTTP request mocking without depending on external repositories. Meanwhile, &lt;code&gt;ruff&lt;/code&gt; unifies linting and formatting, and &lt;code&gt;mypy&lt;/code&gt; ensures type safety throughout the codebase.&lt;/p&gt;

&lt;p&gt;As a result, the project directory structure reflects a clear separation of responsibilities. The &lt;code&gt;app/&lt;/code&gt; directory contains the submodules &lt;code&gt;models/&lt;/code&gt;, &lt;code&gt;schemas/&lt;/code&gt;, &lt;code&gt;api/&lt;/code&gt;, &lt;code&gt;collectors/&lt;/code&gt;, &lt;code&gt;storage/&lt;/code&gt;, and &lt;code&gt;utils/&lt;/code&gt;. Each collector resides in its own package — &lt;code&gt;geo/&lt;/code&gt;, &lt;code&gt;ncbi_gene/&lt;/code&gt;, &lt;code&gt;pubmed/&lt;/code&gt;, and &lt;code&gt;uniprot/&lt;/code&gt; — facilitating the addition of new data sources in the future. The test suite mirrors the same organization, with dedicated modules for collectors, API functionality, and storage components.&lt;/p&gt;

&lt;p&gt;Several design decisions are particularly important for scientific reproducibility. First, raw data immutability is enforced: once stored in MinIO, files cannot be modified. Every collection operation generates new files, even when the same &lt;code&gt;external_id&lt;/code&gt; has already been collected. Likewise, the accompanying &lt;code&gt;metadata.json&lt;/code&gt; file contains fields such as &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, and &lt;code&gt;parameters&lt;/code&gt;, ensuring complete data provenance. Additionally, fixing the random seed with &lt;code&gt;random.seed(42)&lt;/code&gt; guarantees reproducibility for any sampling procedures that may occur. Consequently, researchers can trust that the same parameters will always produce identical datasets over time.&lt;/p&gt;

&lt;p&gt;The data model itself is concise and functional. The &lt;code&gt;Collection&lt;/code&gt; table stores a UUID identifier, source (&lt;code&gt;geo&lt;/code&gt;, &lt;code&gt;ncbi_gene&lt;/code&gt;, &lt;code&gt;pubmed&lt;/code&gt;, or &lt;code&gt;uniprot&lt;/code&gt;), external ID, status (&lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;running&lt;/code&gt;, &lt;code&gt;completed&lt;/code&gt;, or &lt;code&gt;failed&lt;/code&gt;), MinIO storage path, JSONB metadata, error messages, and creation/update timestamps. The &lt;code&gt;Dataset&lt;/code&gt; table, linked through a foreign key to &lt;code&gt;Collection&lt;/code&gt;, records each individual file, including its name, format, size, SHA-256 checksum, and full MinIO path.&lt;/p&gt;

&lt;p&gt;As a consequence, researchers can track the progress of any collection using simple HTTP requests. A Bash script utilizing &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt; can initiate a collection, poll for completion, and list generated datasets in just a few lines of code. Both synchronous and asynchronous Python clients are also supported, as demonstrated in the usage documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Project 1 establishes the foundation upon which the remaining fifteen projects of the platform will be built. In summary, it addresses the challenge of fragmented biological data sources by providing a unified API, immutable storage, and standardized metadata management. In this context, future projects focused on genomics, transcriptomics, proteomics, biomarker discovery, biological networks, molecular docking, and related domains will be able to consume curated and traceable datasets directly from the Data Lake. As a result, operational bottlenecks are eliminated, and the integrity, documentation, and reproducibility of raw data—the cornerstone of any scientific analysis—are ensured. Ultimately, Project 1 is far more than a data collector; it serves as the backbone of the entire Integrated Bioinformatics Platform.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>automation</category>
      <category>dataengineering</category>
      <category>science</category>
    </item>
    <item>
      <title>I Just Launched a Meme Coin!</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Sun, 05 Jan 2025 12:53:39 +0000</pubDate>
      <link>https://dev.to/jeferson0993/i-just-launched-a-meme-coin-a71</link>
      <guid>https://dev.to/jeferson0993/i-just-launched-a-meme-coin-a71</guid>
      <description>&lt;h2&gt;
  
  
  The Birth of Dev Lol Coin
&lt;/h2&gt;

&lt;p&gt;It started as a joke. Like many developers, I’ve spent countless hours debugging code, staring at errors that make no sense, and deploying fixes at 3 AM only to find out they broke something else. Amid this chaos, I thought: &lt;em&gt;What if we could immortalize this hilarity on the blockchain?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Dev Lol Coin ($LOLDEV)&lt;/strong&gt;. It’s a satirical meme coin designed to celebrate (or mock) the trials and tribulations of developers worldwide. Built on the Solana blockchain, $LOLDEV is fast, absurd, and unapologetically ridiculous—just like the dev life.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://pump.fun/coin/378jHA9sF9z4UNZzT64PkdN8EgjTTtDorY35zTBGpump" rel="noopener noreferrer"&gt;Buy the $LOLDEV token here with your phantom wallet&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why Launch a Meme Coin?
&lt;/h2&gt;

&lt;p&gt;Meme coins are the ultimate internet inside joke. They’re born out of cultural moments, shared frustrations, or just sheer randomness. For me, $LOLDEV is a way to capture the developer’s experience: the bugs, the builds, and the occasional breakthrough.&lt;/p&gt;

&lt;p&gt;Plus, why not? If Dogecoin can take us to the moon, maybe $LOLDEV can take us to… the next successful CI/CD pipeline?&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Creating a token on Solana is surprisingly straightforward (at least for devs who have been knee-deep in documentation before). Here’s a quick breakdown of how $LOLDEV came to life:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choosing the Blockchain:&lt;/strong&gt; Solana was a no-brainer. It’s fast, has low fees, and offers robust developer tools. Perfect for a meme coin that needs to move as quickly as developers pushing a hotfix.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developing the Token:&lt;/strong&gt; Using the Solana CLI and the SPL Token program, I generated $LOLDEV with a fixed supply to keep it simple.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creating the Ticker:&lt;/strong&gt; $LOLDEV. Short, sweet, and packed with irony.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minting the Coin:&lt;/strong&gt; I minted an initial supply of $1,000,000,000 LOLDEV tokens. Because why stop at millions when you can have billions?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Designing the Branding:&lt;/strong&gt; A meme coin needs memes. I’ve put together a collection of developer-themed memes to promote $LOLDEV across social media. "&lt;em&gt;Error 404: Serious Investment Not Found.&lt;/em&gt;"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What’s Next for $LOLDEV?
&lt;/h2&gt;

&lt;p&gt;Right now, $LOLDEV is just for fun. I’ve airdropped some to fellow developers and friends who share my sense of humor. Here’s what I’m planning next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Meme Marketplace:&lt;/strong&gt; A platform where $LOLDEV can be used to buy, sell, and trade developer-themed memes and NFTs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community Engagement:&lt;/strong&gt; Hosting meme competitions and dev challenges, with $LOLDEV as rewards.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;More Laughs:&lt;/strong&gt; Turning $LOLDEV into a symbol of solidarity for devs. Because if we can’t laugh at our bugs, what can we do?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Launching a meme coin taught me a lot about blockchain, community building, and the power of humor in tech. But more importantly, it reminded me that the best projects often start with a simple idea: &lt;em&gt;Let’s have some fun.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So here’s to $LOLDEV, the meme coin for anyone who’s ever yelled "&lt;em&gt;It works on my machine!&lt;/em&gt;" Cheers to the devs, the memes, and the madness.&lt;/p&gt;

&lt;p&gt;Let’s see where this ride takes us.&lt;/p&gt;




&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my portfolio &lt;a href="https://jef-dev.web.app" rel="noopener noreferrer"&gt;here&lt;/a&gt; to see my latest projects, and connect with me on &lt;a href="https://www.linkedin.com/in/jeferson-silva-b68a56302/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to discuss how I can help bring your next project to fruition!&lt;/p&gt;

</description>
      <category>loldev</category>
      <category>solana</category>
    </item>
    <item>
      <title>Why Monorepo Projects Sucks: Performance Considerations with Nx</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Wed, 11 Dec 2024 00:17:40 +0000</pubDate>
      <link>https://dev.to/jeferson0993/why-monorepo-projects-sucks-performance-considerations-with-nx-2mnk</link>
      <guid>https://dev.to/jeferson0993/why-monorepo-projects-sucks-performance-considerations-with-nx-2mnk</guid>
      <description>&lt;p&gt;In the world of software development, monorepo setups have become a popular trend, especially with tools like Nx that promise better integration, faster builds, and more efficient workflows. A monorepo is where multiple projects, often microservices or libraries, live in a single repository. Sounds convenient, right? One repo to rule them all! But not so fast — while the monorepo approach might shine in some cases, it’s not always the best solution, especially when performance is a key concern.&lt;/p&gt;

&lt;p&gt;Let's dive into some of the key performance issues with monorepo projects, and why Nx, despite its benefits, may not always be the silver bullet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Longer Build Times for Large Projects
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwypmhqj4e76kpmtefuxk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwypmhqj4e76kpmtefuxk.gif" alt="Mr Bean waiting" width="640" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Monorepos are supposed to streamline things by centralizing code, but as the number of projects grows, so do build times. Even though Nx is optimized to run tasks efficiently, a monorepo with hundreds of libraries or services means that dependency graphs can get extremely large. When a change is made, Nx needs to analyze dependencies and determine what needs to be rebuilt. In some cases, this process can get complex and slow.&lt;/p&gt;

&lt;p&gt;Imagine that a tiny bug fix in a small library requires building a significant portion of the repo. This overhead can result in frustratingly long build times, killing developer productivity and increasing CI pipeline duration. In contrast, a polyrepo approach (where each project lives in its own repository) may allow independent builds, reducing the scope of what needs to be compiled and tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overhead with Task Scheduling
&lt;/h2&gt;

&lt;p&gt;Nx introduces task scheduling to optimize parallel builds and test runs. However, this scheduling system adds a layer of complexity. As the number of developers and commits grows, task execution can become bottlenecked. Nx does a good job of managing this, but in large monorepos, the overhead of orchestrating hundreds or thousands of tasks becomes inefficient.&lt;/p&gt;

&lt;p&gt;Moreover, Nx’s caching mechanism, designed to speed up builds by reusing previous results, can sometimes lead to cache misses due to small changes, forcing a rebuild of many unrelated parts of the repo. This negates the caching benefits and causes slowdowns, which can be especially problematic in CI environments where time is crucial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Bloat and Codebase Size
&lt;/h2&gt;

&lt;p&gt;don’t actually need for a specific service or library but are kept for “convenience.” This leads to increased disk usage, slower git operations, and more complicated dependency management.&lt;/p&gt;

&lt;p&gt;Over time, this leads to situations where developers are dealing with dependency hell. Updating shared libraries or dependencies becomes a monumental task, as every project in the monorepo must be considered. This can create a ripple effect, leading to longer build times, merge conflicts, and higher risk of bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling Development Teams
&lt;/h2&gt;

&lt;p&gt;In smaller teams or projects, a monorepo with Nx might work fine. But as your team scales, so do the issues. With a monorepo, you are essentially coupling everything together. Even though teams may work on different parts of the codebase, they are still impacted by changes in other parts of the repo. This increases the coordination overhead, slowing down development and causing friction between teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmadw67rgsezar40abmdo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmadw67rgsezar40abmdo.gif" alt="spogebong patrick" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A polyrepo setup allows teams to work more independently, with fewer merge conflicts and less coordination. When you have multiple teams contributing to a single monorepo, the velocity of development can decrease due to these conflicts, hurting overall productivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI/CD Pipeline Bottlenecks
&lt;/h2&gt;

&lt;p&gt;CI/CD pipelines in monorepos can become a nightmare. Despite Nx’s ability to run only affected projects, changes in shared libraries or configurations can still trigger the build and test of a large number of projects. The more services or libraries you have in a single repo, the more your pipeline becomes clogged with tasks. Nx’s distributed caching can help alleviate some of this, but it's not a perfect solution, especially in a fast-paced environment where small changes can trigger large rebuilds.&lt;/p&gt;

&lt;p&gt;In contrast, in a polyrepo setup, the CI/CD pipeline can be much more granular, running builds and tests only for the specific project where the changes were made. This localized pipeline approach can result in faster deployments and quicker feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Is Nx Always the Best Solution?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqhk56na9c9c63dla1a6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqhk56na9c9c63dla1a6.gif" alt="thumbsdown" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While Nx and the monorepo approach offer some significant benefits, such as code sharing and streamlined tooling, they can introduce serious performance bottlenecks for large, complex codebases. Build times, task scheduling overhead, dependency bloat, and scaling issues are all valid reasons why monorepos might not be the best fit in certain scenarios.&lt;/p&gt;

&lt;p&gt;For smaller projects, or tightly integrated systems, a monorepo can be highly effective. But as your codebase and teams grow, you might find that the performance penalties outweigh the benefits. In those cases, it’s worth considering a polyrepo setup, or at least weighing the trade-offs before fully committing to Nx and monorepos.&lt;/p&gt;

&lt;p&gt;Ultimately, the right approach depends on the size of your project, team structure, and performance needs. Monorepos aren’t a one-size-fits-all solution — and sometimes, they suck.&lt;/p&gt;

&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my &lt;a href="https://jef-dev.web.app" rel="noopener noreferrer"&gt;portfolio here&lt;/a&gt; to see my latest projects, and connect with me on &lt;a href="https://www.linkedin.com/in/jeferson-silva-b68a56302/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to discuss how I can help bring your next project to fruition!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>productivity</category>
      <category>nx</category>
    </item>
    <item>
      <title>How to Optimize a Website for Search Engines: A Comprehensive Guide</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Wed, 20 Nov 2024 16:33:25 +0000</pubDate>
      <link>https://dev.to/jeferson0993/how-to-optimize-a-website-for-search-engines-a-comprehensive-guide-23op</link>
      <guid>https://dev.to/jeferson0993/how-to-optimize-a-website-for-search-engines-a-comprehensive-guide-23op</guid>
      <description>&lt;p&gt;Optimizing a website for search engines like google and yahoo, usually called search engine marketing (Search Engine Optimization), is vital for enhancing visibility, riding organic visitors, and improving rankings on seek engine result pages (SERPs). Below is a step-with the aid of-step manual to help you acquire effective SEO to your website.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. &lt;strong&gt;Conduct Keyword Research&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why it Matters&lt;/strong&gt;: Keywords are the foundation of search engine optimization. Understanding what phrases users search for can help you goal their desires.&lt;/p&gt;

&lt;p&gt;👣 &lt;strong&gt;Steps&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use equipment like Google Keyword Planner, Ahrefs, or SEMrush to find relevant key phrases.&lt;/li&gt;
&lt;li&gt;Identify &lt;strong&gt;number one key phrases&lt;/strong&gt; (excessive-volume, high-relevance) and &lt;strong&gt;long-tail key phrases&lt;/strong&gt; (low-extent, high-specificity).&lt;/li&gt;
&lt;li&gt;Analyze competitor web sites for keyword opportunities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prioritize keywords with excessive search volume but mild competition.&lt;/li&gt;
&lt;li&gt;Consider consumer reason behind each key-word: informational, navigational, or transactional.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. &lt;strong&gt;Optimize On-Page search engine optimization Elements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Key Elements to Focus On&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Title Tags&lt;/strong&gt;: Include number one keywords and restriction titles to 60 characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meta Descriptions&lt;/strong&gt;: Summarize the content compellingly at the same time as such as keywords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headings (H1, H2, H3)&lt;/strong&gt;: Use clean, keyword-optimized headings to shape your content material.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL Structure&lt;/strong&gt;: Keep URLs short, descriptive, and key-word-rich.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Alt Text&lt;/strong&gt;: Add descriptive text to all snap shots for accessibility and search engine optimization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;br&gt;
Instead of: &lt;code&gt;www.Instance.Com/p123&lt;/code&gt;&lt;br&gt;
Use: &lt;code&gt;www.Example.Com/search-engine-optimization-guide&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. &lt;strong&gt;Create High-Quality Content&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Content Strategies&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write particular, in-intensity articles tailored in your target audience's wishes.&lt;/li&gt;
&lt;li&gt;Incorporate keywords obviously to keep away from overstuffing.&lt;/li&gt;
&lt;li&gt;Include &lt;strong&gt;visual content&lt;/strong&gt; including photographs, infographics, and films to decorate engagement.&lt;/li&gt;
&lt;li&gt;Regularly update antique content material to keep it applicable and sparkling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aim for a readability rating appropriate in your target audience.&lt;/li&gt;
&lt;li&gt;Use internal links to guide users to related pages in your internet site.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  four. &lt;strong&gt;Improve Technical search engine optimization&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Technical search engine optimization Components&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Site Speed&lt;/strong&gt;: Ensure your website loads inside 2–three seconds using equipment like Google PageSpeed Insights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile-Friendliness&lt;/strong&gt;: Implement responsive design to make sure compatibility with all gadgets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crawlability&lt;/strong&gt;: Submit a sitemap to engines like google to make your site simpler to index.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Protocols&lt;/strong&gt;: Use HTTPS instead of HTTP to secure consumer statistics and construct believe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix broken hyperlinks to beautify the user revel in.&lt;/li&gt;
&lt;li&gt;Use based data (schema markup) to help search engines like google and yahoo understand your content.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. &lt;strong&gt;Leverage Off-Page search engine marketing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tactics&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backlink Building&lt;/strong&gt;: Earn top notch backlinks from authoritative websites via guest running a blog, outreach, or partnerships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social Media&lt;/strong&gt;: Share your content throughout platforms to increase visibility and generate referral traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online Directories&lt;/strong&gt;: Ensure your website is listed in relevant directories with steady records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on exceptional over amount for one way links.&lt;/li&gt;
&lt;li&gt;Engage in on line groups to construct relationships and credibility.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. &lt;strong&gt;Monitor and Analyze Performance&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🛠️&lt;strong&gt;Tools&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Analytics&lt;/strong&gt;: Track traffic resources, user conduct, and conversions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt;: Identify technical troubles and display key-word performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;search engine marketing Tools&lt;/strong&gt;: Use structures like Ahrefs, Moz, or SEMrush to research scores and oneway links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set benchmarks to degree the achievement of your optimization efforts.&lt;/li&gt;
&lt;li&gt;Perform ordinary search engine marketing audits to discover new opportunities and problems.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. &lt;strong&gt;Local search engine optimization (If Applicable)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;👣 &lt;strong&gt;Steps&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claim your Google Business Profile and make certain accurate records.&lt;/li&gt;
&lt;li&gt;Include nearby keywords on your content material.&lt;/li&gt;
&lt;li&gt;Encourage satisfied customers to depart reviews on platforms like Google or Yelp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Pro Tips&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embed Google Maps for nearby agencies.&lt;/li&gt;
&lt;li&gt;Use place-specific landing pages if serving a couple of areas.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. &lt;strong&gt;Maintain an search engine marketing-First Mindset&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why It Matters&lt;/strong&gt;:&lt;br&gt;
search engine optimization isn't always a one-time interest. Consistency and adaptability are crucial as search engines like google and yahoo update their algorithms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regular Practices&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publish new content regularly.&lt;/li&gt;
&lt;li&gt;Monitor competitor techniques and adapt as a consequence.&lt;/li&gt;
&lt;li&gt;Stay up to date on search engine optimization developments and algorithm adjustments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Optimizing a website for serps requires a combination of strategic planning, technical talent, and consistent attempt. By following the steps outlined above, you can decorate your web page's visibility, attract more visitors, and gain your commercial enterprise goals.&lt;/p&gt;




&lt;h3&gt;
  
  
  Relevant Image Concepts:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keyword Research Visualization&lt;/strong&gt;: A chart or tool interface displaying keyword facts like search volume and opposition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-Page search engine optimization Elements&lt;/strong&gt;: An infographic highlighting the name tag, meta description, and URL structure on a webpage.
Three. &lt;strong&gt;Content Optimization Workflow&lt;/strong&gt;: A step-by-step visual guide to creating search engine marketing-friendly content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical SEO Checklist&lt;/strong&gt;: A diagram showing key factors like web page velocity, cellular optimization, and HTTPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Tracking Dashboard&lt;/strong&gt;: A graphical depiction of analytics information for monitoring search engine optimization fulfillment.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my portfolio &lt;a href="https://jef-dev.web.app" rel="noopener noreferrer"&gt;here&lt;/a&gt; to see my latest projects, and connect with me on &lt;a href="https://www.linkedin.com/in/jeferson-silva-b68a56302/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to discuss how I can help bring your next project to fruition!&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>A Handy Guide to Closed Source Licenses: Protecting Your Code Like a Pro</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Wed, 23 Oct 2024 11:52:50 +0000</pubDate>
      <link>https://dev.to/jeferson0993/a-handy-guide-to-closed-source-licenses-protecting-your-code-like-a-pro-10b3</link>
      <guid>https://dev.to/jeferson0993/a-handy-guide-to-closed-source-licenses-protecting-your-code-like-a-pro-10b3</guid>
      <description>&lt;p&gt;So, you’ve decided to keep your project behind the curtain—whether it's because you’re working on the next billion-dollar app, or you simply want to maintain control over your code. In the land of &lt;strong&gt;closed source software&lt;/strong&gt;, licenses play a crucial role in protecting your hard work. They set the boundaries on who can use your code, how they can use it, and—just as important—how they &lt;strong&gt;cannot&lt;/strong&gt; use it.&lt;/p&gt;

&lt;p&gt;This guide will walk you through the most common licenses used for closed source projects, what they cover, and why it’s essential to pick the right one. Plus, I’ll explain how licenses can save you from potential legal nightmares. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;strong&gt;Proprietary License: Lock It Down&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Total control, no freebies here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: A proprietary license is essentially a "no trespassing" sign for your code. The software remains the property of the creator or company, and the user is given very limited rights—usually to run or use the software under specific conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Businesses or developers who want to keep all rights to their software and only allow others to use it under strict terms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You keep &lt;strong&gt;full ownership&lt;/strong&gt; over the code, including its distribution and use.&lt;/li&gt;
&lt;li&gt;Users can only use your software in ways that you explicitly allow, typically by purchasing a license.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users may not like the lack of freedom and flexibility, which could be a turn-off, especially for individual consumers.&lt;/li&gt;
&lt;li&gt;Maintenance and licensing enforcement can be resource-intensive if you expect large-scale distribution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;EULA (End-User License Agreement): The "You Can Use It, But…" Contract&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Here’s what you can and cannot do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: An EULA is an agreement between the software developer and the end user. It details how the user can use the software, what’s forbidden (e.g., reverse engineering, sharing copies), and the consequences for breaking the terms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Software distributed directly to customers or businesses, especially apps or products with complex features that need some legal protections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can specify &lt;strong&gt;exactly how&lt;/strong&gt; the user can interact with your software (e.g., install on one computer, no reverse-engineering, etc.).&lt;/li&gt;
&lt;li&gt;It’s a standard way to prevent misuse and protect intellectual property while granting users the rights they need to use the software.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EULAs are often long and filled with legal jargon, which can frustrate users.&lt;/li&gt;
&lt;li&gt;Enforcing an EULA can be difficult across jurisdictions, especially when selling globally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;SaaS Agreement: Rent, Don’t Own&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: You’re not buying the software, you’re just borrowing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: A SaaS (Software as a Service) agreement governs how users can access and use cloud-based software. Rather than "owning" the software, users subscribe to the service, with the provider retaining all rights to the software and its infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Cloud-based applications and services where customers are paying for ongoing access rather than a one-time download.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You retain &lt;strong&gt;full control&lt;/strong&gt; of the software and can update or modify it whenever necessary.&lt;/li&gt;
&lt;li&gt;The subscription model can create a continuous revenue stream, and you don’t have to worry about piracy in the traditional sense since the software is never directly installed by the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If your infrastructure fails or your servers go down, your customers lose access, which could create dissatisfaction.&lt;/li&gt;
&lt;li&gt;Legal and compliance challenges are often greater for SaaS providers, especially when dealing with global markets and data privacy laws.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;Shrink-Wrap and Click-Wrap Licenses: Old-School Meets New-School&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Simple but effective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: These licenses are all about &lt;strong&gt;consent by action&lt;/strong&gt;. With shrink-wrap licenses (think of boxed software), the license agreement is accepted when the user opens the packaging. Click-wrap licenses are their digital counterpart—users accept the terms by clicking "I Agree" during installation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Software that is distributed both physically and digitally, especially older programs or those with straightforward terms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s straightforward and can be &lt;strong&gt;automated&lt;/strong&gt; (e.g., software installation won't continue until the user agrees).&lt;/li&gt;
&lt;li&gt;It works well for standard commercial software that doesn’t need complex or tailored agreements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Shrink-wrap licenses are becoming outdated as digital distribution takes over.&lt;/li&gt;
&lt;li&gt;Users might just click "Agree" without reading, which could create legal headaches later if there's a dispute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Commercial License: License to Sell&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Money talks, and software sells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: A commercial license allows users to purchase software under a set of terms, often restricting how they can distribute, modify, or copy the software. It’s designed to give you, the developer, &lt;strong&gt;monetary compensation&lt;/strong&gt; for your work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Developers who want to &lt;strong&gt;sell&lt;/strong&gt; their software for profit and maintain strict control over its use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You retain all rights to your software, and customers are legally bound to your terms.&lt;/li&gt;
&lt;li&gt;This license allows you to set terms for individual or corporate usage and collect revenue based on the agreement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You’ll need to invest in some level of &lt;strong&gt;licensing enforcement&lt;/strong&gt; to prevent unauthorized use or piracy.&lt;/li&gt;
&lt;li&gt;The more restrictive the license, the fewer freedoms the end user has, which might limit your customer base.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why Licenses Are Critical in Closed Source Projects&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Licenses aren’t just formalities—they are your &lt;strong&gt;first line of defense&lt;/strong&gt; against misuse, theft, and even legal disputes. Here’s why adding a license to your closed source project is a must:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Control Over Your Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Licenses give you control over how your software is distributed and used. Without one, your software is left in a legal gray zone, and users might assume they can do whatever they want with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Prevention of Unauthorized Use&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By setting clear terms, you can prevent users from illegally copying, redistributing, or reverse-engineering your code. This is particularly crucial in competitive industries where intellectual property theft can cost you big time.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Monetization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For commercial and proprietary licenses, you have the right to charge users for your software and dictate how it can be used in business environments. Without a proper license, collecting payment or enforcing contracts would be challenging.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Legal Protection&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A well-crafted license protects you from lawsuits or legal issues down the road. For example, if your software crashes or causes damage, a license can include disclaimers that limit your liability. In other words, &lt;strong&gt;it’s your safety net&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to Choose the Right Closed Source License for Your Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do you want complete control?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A &lt;strong&gt;proprietary license&lt;/strong&gt; ensures that nobody can do anything with your software unless you explicitly allow it. It’s ideal for companies or developers who want to protect their code and monetize it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are you offering a service rather than software?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you’re in the cloud-based software game, a &lt;strong&gt;SaaS agreement&lt;/strong&gt; is the way to go. You keep all control over the software, while users pay for access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are you worried about users reverse-engineering or modifying your software?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go for a &lt;strong&gt;commercial license&lt;/strong&gt; or an &lt;strong&gt;EULA&lt;/strong&gt;, which lays out specific terms about what users can and can’t do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Need something simple for digital distribution?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A &lt;strong&gt;click-wrap license&lt;/strong&gt; is easy to implement for standard software and ensures users agree to your terms before using the software.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion: Cover Your Code’s Back!&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Choosing the right license for your closed source project is crucial to protecting your intellectual property, enforcing your rights, and ensuring that you get compensated for your hard work. Not only can it prevent unauthorized use or distribution, but it can also keep you out of legal hot water when things go wrong.&lt;/p&gt;

&lt;p&gt;Whether you want tight control with a proprietary license or you’re providing a service with a SaaS agreement, there’s a license out there for every project. And remember, without a license, your code is like an unlocked door—anyone can come in and take what they want. So, lock it down and keep it safe!&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;References&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/2513/end-user-license-agreement-eula" rel="noopener noreferrer"&gt;End-User License Agreement (EULA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.lawinsider.com/resources/insights/shrinkwrap-vs-clickwrap-agreements-which-is-better-for-you" rel="noopener noreferrer"&gt;Shrink-Wrap and Click-Wrap Licenses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.contractscounsel.com/t/us/saas-agreement" rel="noopener noreferrer"&gt;SaaS Agreements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.law.cornell.edu/wex/proprietary_software" rel="noopener noreferrer"&gt;Proprietary Software Licensing Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techrepublic.com/article/how-to-manage-software-licenses-in-the-enterprise/" rel="noopener noreferrer"&gt;Commercial Software Licenses&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my portfolio &lt;a href="https://jef-dev.web.app" rel="noopener noreferrer"&gt;here&lt;/a&gt; to see my latest projects, and connect with me on &lt;a href="https://www.linkedin.com/in/jeferson-silva-b68a56302/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to discuss how I can help bring your next project to fruition!&lt;/p&gt;

&lt;p&gt;Happy coding! 🎉&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>documentation</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A Fun Guide to Open Source Licenses: Finding the Perfect Fit for Your Project</title>
      <dc:creator>Jeferson F Silva</dc:creator>
      <pubDate>Sat, 19 Oct 2024 12:25:33 +0000</pubDate>
      <link>https://dev.to/jeferson0993/a-fun-guide-to-open-source-licenses-finding-the-perfect-fit-for-your-project-6a9</link>
      <guid>https://dev.to/jeferson0993/a-fun-guide-to-open-source-licenses-finding-the-perfect-fit-for-your-project-6a9</guid>
      <description>&lt;p&gt;Welcome to the magical world of &lt;strong&gt;open source licenses&lt;/strong&gt;—where code runs free, but with a few rules attached. If you're starting an open source project, or contributing to one, you might be wondering: &lt;em&gt;"Do I really need a license for this?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Spoiler alert: Yes, you do! &lt;/p&gt;

&lt;p&gt;Licenses are like the rules of the road for your code. They tell people what they can and can't do with it. But with so many licenses floating around, which one should you choose? Don’t worry—I’m here to break down the most popular ones, show you their quirks, and help you decide which one is perfect for your project!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;strong&gt;MIT License: The Cool Kid of Licenses&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Super chill, super permissive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: Almost anything. People can use, modify, distribute, and even sell your code with no strings attached, as long as they give you credit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: If you’re looking for a &lt;strong&gt;"code belongs to the streets"&lt;/strong&gt; vibe, the MIT license is your go-to. It's simple, concise, and gets the job done without hassle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You don't care what people do with your code, as long as they shout you out.&lt;/li&gt;
&lt;li&gt;It's easy to understand, making it great for both small and large projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you want more control over how your code is used (e.g., no commercial use or modifications without permission), this might be too lenient.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;GNU General Public License (GPL): The Share-Alike License&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: You can play with my code, but &lt;strong&gt;you gotta share&lt;/strong&gt; what you build with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: You can use, modify, and distribute the code, but if you share your project, it must also be licensed under the GPL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Those who love community-driven projects and want to ensure that the open source spirit lives on in all derivatives of their code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're passionate about keeping code open. If someone builds on your code, they &lt;strong&gt;have to share&lt;/strong&gt; their work under the same license.&lt;/li&gt;
&lt;li&gt;It promotes collaboration and prevents proprietary takeovers of your work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Some businesses avoid GPL because they don’t want to open-source their entire project. It's not a good fit if you're open to commercial use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Apache License 2.0: The Business-Friendly Option&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Open source but cool with making money, just don't sue me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: It’s a permissive license like MIT, but it adds explicit protection against patent claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Developers who want to allow others to use their code commercially, but with some legal safeguards in place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It's friendly to commercial use without forcing others to open-source their modifications.&lt;/li&gt;
&lt;li&gt;It has strong protections for contributors, including a clause that prevents patent trolls from attacking your project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s a bit longer and more complicated than MIT, and some find the added legal jargon unnecessary for smaller projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;BSD License (3-Clause): The Academic One&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Similar to MIT, but with a few more words and restrictions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: Permissive like MIT, but it includes a clause preventing others from using your name to promote derivative works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Developers who want a permissive license but don’t want their name plastered all over projects they didn’t directly create.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you're okay with others doing pretty much whatever they want with your code, but don’t want them to use &lt;strong&gt;your name&lt;/strong&gt; to do it.&lt;/li&gt;
&lt;li&gt;It’s very popular in academic and scientific communities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It's more restrictive than MIT, and the additional clause might be unnecessary for many projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Creative Commons (CC0): No Rights Reserved&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: Do whatever you want—literally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: This is the most permissive of all licenses—it's essentially the public domain. You give up all rights to the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Projects where you truly don’t care what happens to your work, and want it to be free for any use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The code can be used by anyone, anywhere, for any purpose. No strings attached.&lt;/li&gt;
&lt;li&gt;If you want to contribute to the public domain and have absolutely no restrictions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You get &lt;strong&gt;zero&lt;/strong&gt; control. Once it’s out there, it’s gone for good. No attribution or anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. &lt;strong&gt;Mozilla Public License (MPL 2.0): The Middle Ground&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Vibe Check&lt;/strong&gt;: You can keep your project private, but share your modifications to open-source parts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What It Covers&lt;/strong&gt;: You can use and modify MPL-covered code, but you must share the changes you make to the original open-source files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal For&lt;/strong&gt;: Developers who want a &lt;strong&gt;compromise&lt;/strong&gt; between permissive licenses and stricter copyleft licenses like GPL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You’d Love It:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It strikes a balance. You can use MPL-covered code in proprietary projects, but if you modify open-source parts, those changes have to be shared.&lt;/li&gt;
&lt;li&gt;It’s great for large software projects where only certain modules need to be open-source.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Might Swipe Left:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s not as permissive as MIT or Apache, but not as strict as GPL. Some might find it an odd middle-ground.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to Choose the Right License for Your Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do you want total freedom?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go with MIT or BSD. These licenses are like handing out candy—everyone can enjoy them with little to no restrictions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do you want others to contribute and share back?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
GPL is your best buddy. If you’re all about keeping the open-source community alive, this is the way to go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are you concerned about patents?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Apache 2.0 has got your back with patent protections while staying permissive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Need some balance?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
MPL is your middle ground, allowing proprietary code to coexist with open-source parts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Want to go full public domain?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
CC0 is your path to ultimate code freedom. Just let it go!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opensource.org/licenses/MIT" rel="noopener noreferrer"&gt;MIT License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/licenses/gpl-3.0.en.html" rel="noopener noreferrer"&gt;GNU General Public License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apache.org/licenses/LICENSE-2.0" rel="noopener noreferrer"&gt;Apache License 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opensource.org/licenses/BSD-3-Clause" rel="noopener noreferrer"&gt;BSD 3-Clause License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mozilla.org/en-US/MPL/2.0/" rel="noopener noreferrer"&gt;Mozilla Public License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://creativecommons.org/share-your-work/public-domain/cc0/" rel="noopener noreferrer"&gt;Creative Commons CC0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there you have it! Open source licenses don’t have to be boring legal documents. Choose the one that matches your project's goals, and set your code free (with a few rules attached, of course)!&lt;/p&gt;




&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my portfolio &lt;a href="https://jef-dev.web.app" rel="noopener noreferrer"&gt;here&lt;/a&gt; to see my latest projects, and connect with me on &lt;a href="https://www.linkedin.com/in/jeferson-silva-b68a56302/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to discuss how I can help bring your next project to fruition!&lt;/p&gt;

&lt;p&gt;Happy coding! 🎉&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>documentation</category>
    </item>
  </channel>
</rss>
