<?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: Adriano Vieira</title>
    <description>The latest articles on DEV Community by Adriano Vieira (@adrianovieira).</description>
    <link>https://dev.to/adrianovieira</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F633756%2Fb99a810a-b476-417b-96a9-e9e96aab55bd.png</url>
      <title>DEV Community: Adriano Vieira</title>
      <link>https://dev.to/adrianovieira</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrianovieira"/>
    <language>en</language>
    <item>
      <title>Stop Leaking Data in Multi-Tenant Apps</title>
      <dc:creator>Adriano Vieira</dc:creator>
      <pubDate>Wed, 18 Mar 2026 19:22:49 +0000</pubDate>
      <link>https://dev.to/adrianovieira/stop-leaking-data-in-multi-tenant-apps-1edp</link>
      <guid>https://dev.to/adrianovieira/stop-leaking-data-in-multi-tenant-apps-1edp</guid>
      <description>&lt;p&gt;Why Your application logic isn't Enough: The Case for Database-Level Row-Level Security&lt;/p&gt;

&lt;p&gt;You've built a robust multi-tenant SaaS. You've implemented tenant_id filters in every query, added middleware checks, and written unit tests. But here's the hard truth: Application-layer security is fragile. One missed filter, one rogue script, or a direct database connection bypasses your entire safety net.&lt;/p&gt;

&lt;p&gt;It's time to move your security perimeter from the code to the database itself.&lt;/p&gt;

&lt;p&gt;The Short Summary: In this deep dive, we dismantle the myth that RLS is just a "Postgres feature" and demonstrate how to seamlessly integrate Row-Level Security (RLS) into your SQLAlchemy ORM and Alembic migration workflow. We move beyond basic theory to cover the gritty details of production-ready implementation:&lt;/p&gt;

&lt;p&gt;Why relying solely on &lt;code&gt;WHERE tenant_id = ?&lt;/code&gt; in your code is a ticking time bomb.&lt;br&gt;
Step-by-step Alembic migration scripts to enable RLS and define policies without breaking your CI/CD pipeline.&lt;br&gt;
How to inject dynamic tenant context into SQLAlchemy sessions using contextvars and event listeners, ensuring your ORM queries automatically respect database policies.&lt;br&gt;
Critical pitfalls like admin bypass strategies, performance indexing, and the difference between PERMISSIVE and RESTRICTIVE policies.&lt;/p&gt;

&lt;p&gt;Stop hoping your developers never forget a filter. Start enforcing security where it matters most: at the data layer.&lt;/p&gt;

&lt;p&gt;👉 Read the full technical guide with complete code examples, migration templates, and testing strategies on &lt;a href="https://www.adrianovieira.eng.br/en/posts/architecture/row-level-security-sqlachemy-alembic-guide/" rel="noopener noreferrer"&gt;https://www.adrianovieira.eng.br/en/posts/architecture/row-level-security-sqlachemy-alembic-guide/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecturaldecision</category>
      <category>softwareengineering</category>
      <category>rowlevelsecuritystrategy</category>
      <category>postgres</category>
    </item>
    <item>
      <title>High performing, Scalable APIs &amp; Python</title>
      <dc:creator>Adriano Vieira</dc:creator>
      <pubDate>Wed, 03 Dec 2025 05:21:18 +0000</pubDate>
      <link>https://dev.to/adrianovieira/agile-scalable-apis-python-2ma</link>
      <guid>https://dev.to/adrianovieira/agile-scalable-apis-python-2ma</guid>
      <description>&lt;p&gt;The demand for fast, scalable, and easy‑to‑maintain APIs has been growing exponentially. In the same vein, developing asynchronous APIs has become essential for applications that require high concurrency and low latency.&lt;br&gt;
This article presents the construction of a &lt;strong&gt;“simple” API&lt;/strong&gt; focused on managing CrossFit trainings, built as a practical lab to demonstrate the full use of &lt;strong&gt;Python&lt;/strong&gt;, &lt;strong&gt;FastAPI&lt;/strong&gt;, and the &lt;strong&gt;SQLAlchemy&lt;/strong&gt; ORM in an &lt;strong&gt;&lt;em&gt;end‑to‑end asynchronous flow&lt;/em&gt;&lt;/strong&gt;, including integration tests with &lt;strong&gt;PyTest&lt;/strong&gt;.&lt;br&gt;
To ensure code quality and endpoint reliability, we incorporated &lt;strong&gt;integrated tests&lt;/strong&gt; using &lt;strong&gt;PyTest&lt;/strong&gt; with support for asynchronous operations. These tests cover everything from validating &lt;strong&gt;Pydantic&lt;/strong&gt; models to verifying the behaviour of the persistence layer, providing rapid feedback during development.&lt;br&gt;
The ultimate goal is to deliver a functional prototype that illustrates best practices in architecture, API documentation, code organisation, and performance optimisation in asynchronous environments. Additionally, it offers a well‑structured, functional example that can serve as a starting point for real projects requiring high performance, simplified maintenance, and comprehensive test coverage—whether for sports training or any other application needing a modern, responsive API.&lt;/p&gt;
&lt;h2&gt;
  
  
  Functional Requirements
&lt;/h2&gt;

&lt;p&gt;For the lab, the considered functionalities are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A CrossFit athlete belongs to only one category (CrossFit level).&lt;/li&gt;
&lt;li&gt;Each category can contain multiple athletes.&lt;/li&gt;
&lt;li&gt;An athlete can train at different training centres.&lt;/li&gt;
&lt;li&gt;Training centres can host several athletes training simultaneously.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The Technologies
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Why FastAPI?
&lt;/h3&gt;

&lt;p&gt;FastAPI was chosen as the primary framework for two fundamental reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declarative Model + Automatic Validation&lt;/strong&gt; – It uses &lt;em&gt;type hints&lt;/em&gt; and &lt;em&gt;Pydantic&lt;/em&gt; to validate payloads with minimal extra effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Async/Await Support&lt;/strong&gt; – Each route can be declared as async, allowing the server (Uvicorn or Hypercorn) to handle thousands of concurrent connections without blocking the event loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These characteristics drastically reduce boilerplate and deliver high performance &lt;em&gt;out‑of‑the‑box&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Asynchronous Persistence with SQLAlchemy
&lt;/h3&gt;

&lt;p&gt;SQLAlchemy provides an asynchronous driver (asyncpg for PostgreSQL).&lt;/p&gt;

&lt;p&gt;It combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full‑featured ORM&lt;/strong&gt; – Maps Python classes to relational tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Session&lt;/strong&gt; – CRUD operations can be executed inside Python &lt;strong&gt;coroutines&lt;/strong&gt;, preserving transactional consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alembic Integration&lt;/strong&gt; – Schema migrations are managed to take advantage of the asyncpg driver’s asynchronous implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Partial example of the Domain Model:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&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;timezone&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&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;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.ext.asyncio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncAttrs&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DeclarativeBase&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;mapped_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ORMBase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncAttrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeclarativeBase&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;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="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;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;autoincrement&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;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="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;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&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;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;timezone&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="n"&gt;server_default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&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="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;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;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&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;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;timezone&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="n"&gt;server_default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&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;server_onupdate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&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;onupdate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ORMBase&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;category&lt;/span&gt;&lt;span class="sh"&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="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;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;unique&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;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&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;__repr__&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="k"&gt;return&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;&amp;lt;Category(id=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, name=&lt;/span&gt;&lt;span class="si"&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;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;athletes&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AthleteCategory&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;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;back_populates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;categories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cascade&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all, delete-orphan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Layer with FastAPI
&lt;/h3&gt;

&lt;p&gt;Main directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── docs                &lt;span class="c"&gt;# Documentation (solution design, ER, UML, OpenAPI)&lt;/span&gt;
├── alembic             &lt;span class="c"&gt;# Database migration scripts&lt;/span&gt;
└── src
    ├── api
    │   ├── controllers   &lt;span class="c"&gt;# Feature handlers&lt;/span&gt;
    │   ├── main.py       &lt;span class="c"&gt;# Entry point&lt;/span&gt;
    │   ├── models
    │   │   ├── dto       &lt;span class="c"&gt;# Pydantic models (DTO)&lt;/span&gt;
    │   │   └── orm       &lt;span class="c"&gt;# SQLAlchemy models&lt;/span&gt;
    │   ├── services      &lt;span class="c"&gt;# Service handlers (e.g., async DB context manager, bus)&lt;/span&gt;
    │   ├── setup         &lt;span class="c"&gt;# Base setup (API, DB connection)&lt;/span&gt;
    │   └── views         &lt;span class="c"&gt;# Route definitions&lt;/span&gt;
    └── tests
        ├── category      &lt;span class="c"&gt;# Test cases for Category&lt;/span&gt;
        ├── conftest.py   &lt;span class="c"&gt;# Test fixtures&lt;/span&gt;
        └── health        &lt;span class="c"&gt;# Health‑check test cases&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Migrations with Alembic (Asynchronous Mode)
&lt;/h3&gt;

&lt;p&gt;Although Alembic is synchronous by default, it was adapted to work with the asyncpg driver. It is also part of the CI/CD pipeline, where migrations are applied before running tests or deploying to staging/production.&lt;/p&gt;

&lt;p&gt;Partial adapted env.py example:&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;# ...
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_run_migrations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Connection&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="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;target_metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;begin_transaction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_migrations&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;run_async_migrations&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Create an engine and associate a connection with the context.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;connectable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;async_engine_from_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config_ini_section&lt;/span&gt;&lt;span class="p"&gt;,&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqlalchemy.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;poolclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NullPool&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;with&lt;/span&gt; &lt;span class="n"&gt;connectable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;connection&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_run_migrations&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;connectable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automated Tests with PyTest (Asynchronous)
&lt;/h3&gt;

&lt;p&gt;Database fixtures could be in‑memory, but for integration testing the routines run against the actual application, validating the real database modules.&lt;br&gt;
Partial example of Category test cases:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestCategory&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;test_category_post_success&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;aioclient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category_out&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Given – set up the stage (category_in)
&lt;/span&gt;        &lt;span class="c1"&gt;# When – perform the action
&lt;/span&gt;        &lt;span class="n"&gt;response&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;aioclient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&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;_CATEGORY_URL_PREFIX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;category_in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Then – verify the outcome
&lt;/span&gt;        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_201_CREATED&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&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;category_in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;category_out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;category_out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&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;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests use httpx.AsyncClient to run the API in memory, ensuring the whole flow—Pydantic validation, CRUD layer, and asynchronous session—is exercised. Moreover, the CI/CD pipeline includes test‑coverage analysis and code listing.&lt;/p&gt;

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

&lt;p&gt;I’ve shown how to combine the most modern tools in the &lt;strong&gt;Python&lt;/strong&gt; ecosystem to build a fully asynchronous, testable, and production‑ready API. While the use case focuses on CrossFit training management, the presented architecture - FastAPI + SQLAlchemy + Alembic + PyTest - can be reapplied to any domain that demands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real‑time responses&lt;/li&gt;
&lt;li&gt;Horizontal scalability&lt;/li&gt;
&lt;li&gt;Simplified maintenance thanks to strong typing and automatic validation&lt;/li&gt;
&lt;li&gt;Quality assurance through integrated testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From here, you can extend the solution by adding &lt;strong&gt;JWT&lt;/strong&gt; authentication, &lt;strong&gt;WebSockets&lt;/strong&gt; for live result pushes, integrating a distributed cache (e.g., &lt;strong&gt;Valkey&lt;/strong&gt; or Redis) to lower query latency, or implementing event‑driven components (e.g., &lt;strong&gt;Kafka&lt;/strong&gt;) to expose data for further analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Check out the source code at &lt;a href="https://gitlab.com/adrianovieira/workout-api" rel="noopener noreferrer"&gt;https://gitlab.com/adrianovieira/workout-api&lt;/a&gt; for the API described above.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you have any suggestions/tips to improve that?&lt;/p&gt;

&lt;p&gt;Let’s keep having fun… ;)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I used the generative AI tools Grammarly and Lumo AI to support me in creating this document in English.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>fastapiasync</category>
      <category>crossfittech</category>
      <category>solutionarchitecturedesign</category>
      <category>pythonapidesign</category>
    </item>
    <item>
      <title>Concorrência em Python e o GIL</title>
      <dc:creator>Adriano Vieira</dc:creator>
      <pubDate>Sun, 03 Aug 2025 22:28:59 +0000</pubDate>
      <link>https://dev.to/adrianovieira/pythonista-conheca-o-global-interpreter-lock-gil-4pin</link>
      <guid>https://dev.to/adrianovieira/pythonista-conheca-o-global-interpreter-lock-gil-4pin</guid>
      <description>&lt;h2&gt;
  
  
  Conheça o "GIL"
&lt;/h2&gt;

&lt;p&gt;O GIL e o futuro - agora como opcional no Python-3.13 em diante.&lt;/p&gt;

&lt;p&gt;O Python &lt;em&gt;Global Interpreter Lock&lt;/em&gt; (GIL)[^GIL] é um mecanismo de sincronização que permite que apenas uma thread execute código Python por vez em um processo.&lt;/p&gt;

&lt;p&gt;É uma das características mais distintivas e, por vezes, controversas da implementação padrão do Python (CPython).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Adaptado do original publicado em: &lt;a href="https://www.adrianovieira.eng.br/posts/development/python/python-gil/" rel="noopener noreferrer"&gt;https://www.adrianovieira.eng.br/posts/development/python/python-gil/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Como funciona o GIL
&lt;/h3&gt;

&lt;p&gt;O GIL é essencialmente um mutex global que protege o acesso aos objetos Python,&lt;br&gt;
impedindo que múltiplas threads nativas executem código Python simultaneamente.&lt;/p&gt;

&lt;p&gt;Quando uma thread precisa executar código Python, ela deve primeiro adquirir o GIL.&lt;br&gt;
Assim, outras threads ficam bloqueadas até que o GIL seja liberado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que o GIL existe
&lt;/h3&gt;

&lt;p&gt;O GIL foi criado para resolver problemas de gerenciamento de memória no CPython:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proteção do contador de referências&lt;/strong&gt;: O Python usa contagem de referências para
gerenciamento de memória. Sem o GIL, múltiplas threads poderiam modificar simultaneamente
os contadores de referência dos objetos, causando vazamentos de memória ou liberação
prematura de objetos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicidade de implementação&lt;/strong&gt;: O GIL simplifica significativamente a implementação do
interpretador, evitando a necessidade de alocação em toda a base de código.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proteção de extensões C&lt;/strong&gt;: Muitas extensões C não são thread-safe, e o GIL garante que
não sejam executadas concorrentemente.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitações do GIL
&lt;/h3&gt;

&lt;p&gt;O GIL impõe restrições importantes ao paralelismo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Threading limitado&lt;/strong&gt;: Threads Python não podem executar código Python verdadeiramente em 
paralelo, limitando os benefícios do multithreading para tarefas de intensivo de CPU
(&lt;em&gt;CPU-intensivas&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialização de execução&lt;/strong&gt;: Mesmo em sistemas multi-core, apenas um core pode executar
código Python por vez.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contenção&lt;/strong&gt;: Em aplicações com muitas threads, a competição pelo GIL pode causar sobrecarga intensa.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  E quando o GIL é liberado
&lt;/h3&gt;

&lt;p&gt;O GIL é automaticamente liberado em certas situações, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Durante operações de I/O (leitura/escrita de arquivos, requisições de rede)&lt;/li&gt;
&lt;li&gt;Quando executa funções C que explicitamente liberam o GIL&lt;/li&gt;
&lt;li&gt;Em intervalos regulares durante loops longos (aproximadamente a cada 100 instruções)&lt;/li&gt;
&lt;li&gt;Durante operações que podem bloquear (como &lt;code&gt;time.sleep()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Alternativas e soluções
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiprocessos&lt;/strong&gt;: Usar processos separados em vez de threads contorna 
completamente o GIL, já que cada processo tem seu próprio interpretador.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensões C&lt;/strong&gt;: Operações computacionalmente intensivas podem ser implementadas
em C/Cython, que podem liberar o GIL durante a execução.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementações alternativas&lt;/strong&gt;: Uso de diferentes &lt;em&gt;engine&lt;/em&gt; como PyPy, Jython
e IronPython que têm abordagens diferentes para threading, embora nem todas
eliminem completamente o GIL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async/await&lt;/strong&gt;: Para I/O concorrente, a programação assíncrona é 
frequentemente mais eficiente que threading.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O GIL pode ser desativado?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SIMMMmmm&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A implementação da PEP 703 é um projeto de longo prazo que vem ocorrendo em múltiplas etapas ao longo de vários anos, onde o CPython transitará para tornar a versão sem GIL primeiro experimental, opcional, depois suportada, e finalmente a versão padrão.&lt;/p&gt;

&lt;h3&gt;
  
  
  Status Atual - Python 3.13
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;Global Interpreter Lock&lt;/em&gt; pode ser desativado, e isso já é uma realidade desde o Python 3.13!&lt;/p&gt;

&lt;p&gt;O Python-3.13, lançado em outubro de 2024, inclui suporte &lt;strong&gt;experimental&lt;/strong&gt; para desabilitar o GIL através do "&lt;em&gt;free-threaded mode&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;No Fedora Linux, após instalar o pacote &lt;code&gt;python3.13-freethreading&lt;/code&gt;, você pode executar a versão sem GIL usando o comando &lt;code&gt;python3.13t&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  O Futuro - Python 3.14
&lt;/h3&gt;

&lt;p&gt;A Python-3.14, prevista para ser lançada agora em outubro/2025, já implementa a PEP 779 (&lt;em&gt;PEP 779 Free-threaded Python&lt;/em&gt;) que traz suporte oficial sem GIL como recurso &lt;strong&gt;opcional&lt;/strong&gt;. Então, caso queira usar esta versão no Fedora Linux, deve instalar o pacote &lt;code&gt;python3.14-freethreading&lt;/code&gt;, você pode executar a versão sem GIL usando o comando &lt;code&gt;python3.14t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Have fun, pythonista&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>concurrency</category>
      <category>parallelism</category>
    </item>
    <item>
      <title>SGBD - midleware de gerenciamento de banco de dados</title>
      <dc:creator>Adriano Vieira</dc:creator>
      <pubDate>Mon, 08 May 2023 22:44:11 +0000</pubDate>
      <link>https://dev.to/adrianovieira/sgbd-midleware-de-gerenciamento-de-banco-de-dados-7bm</link>
      <guid>https://dev.to/adrianovieira/sgbd-midleware-de-gerenciamento-de-banco-de-dados-7bm</guid>
      <description>&lt;p&gt;&lt;strong&gt;SGBD&lt;/strong&gt; é o Sistema Gerenciador de Banco de Dados - DBMS do inglês - é a propria aplicação (midleware) de banco.&lt;/p&gt;

&lt;p&gt;Alguns termos usados neste domínio são:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;&lt;em&gt;SGBD&lt;/em&gt;&lt;/strong&gt;: o midleware (exemplos: postgresql, mariadb, mongodb etc);&lt;br&gt;
 • &lt;strong&gt;&lt;em&gt;banco de dados&lt;/em&gt;&lt;/strong&gt;: recurso criado no SGBD que guardará as entidades de dados (exemplos: db_myapp, db4api etc);&lt;br&gt;
 • &lt;strong&gt;&lt;em&gt;tabelas&lt;/em&gt;&lt;/strong&gt;: entidades de dados (exemplo: campanha, cupons etc)&lt;br&gt;
 • &lt;strong&gt;&lt;em&gt;estrutura/schema de dados&lt;/em&gt;&lt;/strong&gt;: os atributos ou colunas (exemploi: id, titulo, subtitulo etc),&lt;br&gt;
 • &lt;strong&gt;&lt;em&gt;registros&lt;/em&gt;&lt;/strong&gt;: cada "linha" e os dados existentes (exempo: 1, Ano Novo ...;&lt;/p&gt;

&lt;p&gt;E isso sem entrar no mérito dos diferentes tipos de tecnologias de bancos (exemplo: relacional, nosql, timeseries etc).&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>Pop!_OS Shell on Fedora</title>
      <dc:creator>Adriano Vieira</dc:creator>
      <pubDate>Wed, 26 Apr 2023 22:56:21 +0000</pubDate>
      <link>https://dev.to/adrianovieira/popos-shell-on-fedora-4bpn</link>
      <guid>https://dev.to/adrianovieira/popos-shell-on-fedora-4bpn</guid>
      <description>&lt;p&gt;Pop!_OS&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Shell integrates like a charm on Fedora 38&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, and change de default gnome shell.&lt;/p&gt;

&lt;p&gt;Thanks a lot Pop!_OS Folks!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Pop!_OS Shell, on &lt;a href="https://github.com/pop-os/shell" rel="noopener noreferrer"&gt;https://github.com/pop-os/shell&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Fedora, on &lt;a href="https://getfedora.org" rel="noopener noreferrer"&gt;https://getfedora.org&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>fedora</category>
      <category>productivity</category>
      <category>popshell</category>
    </item>
  </channel>
</rss>
