<?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: Leandro Horas Pereira</title>
    <description>The latest articles on DEV Community by Leandro Horas Pereira (@leorasgg).</description>
    <link>https://dev.to/leorasgg</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%2F3849037%2F41657fe2-c1eb-443f-8cd3-abd4b03d03dd.jpg</url>
      <title>DEV Community: Leandro Horas Pereira</title>
      <link>https://dev.to/leorasgg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leorasgg"/>
    <language>en</language>
    <item>
      <title>From a Login Screen to a Real ERP Flow: Building Navigation and the First Inventory Module</title>
      <dc:creator>Leandro Horas Pereira</dc:creator>
      <pubDate>Wed, 01 Apr 2026 08:16:00 +0000</pubDate>
      <link>https://dev.to/leorasgg/from-a-login-screen-to-a-real-erp-flow-building-navigation-and-the-first-inventory-module-5e8j</link>
      <guid>https://dev.to/leorasgg/from-a-login-screen-to-a-real-erp-flow-building-navigation-and-the-first-inventory-module-5e8j</guid>
      <description>&lt;p&gt;A few days ago, this project was still basically a login screen.&lt;/p&gt;

&lt;p&gt;Now it has a responsive application shell, authenticated navigation, a module-based home screen, and its first real inventory flow connected to Supabase in production.&lt;/p&gt;

&lt;p&gt;This article covers &lt;strong&gt;Sessions 5 and 6&lt;/strong&gt; of my project, &lt;strong&gt;ERP Modular&lt;/strong&gt;, an open source ERP I am building as both a portfolio project and a deliberate way to learn professional software development in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App demo video:&lt;/strong&gt; [Watch the current app running here] &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3cbtb0342nezld3g1bu.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3cbtb0342nezld3g1bu.gif&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqjy3djighzy3vgzbk8r.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqjy3djighzy3vgzbk8r.gif&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these two sessions mattered so much
&lt;/h2&gt;

&lt;p&gt;Up to Session 4, I had already done the architectural planning, set the rules for the project, and implemented authentication. The system could log in and log out, but it still did not feel like an ERP yet.&lt;/p&gt;

&lt;p&gt;Sessions 5 and 6 changed that.&lt;/p&gt;

&lt;p&gt;Session 5 gave the project a real application structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authenticated routing&lt;/li&gt;
&lt;li&gt;responsive navigation&lt;/li&gt;
&lt;li&gt;a reusable app shell&lt;/li&gt;
&lt;li&gt;a module-based home screen&lt;/li&gt;
&lt;li&gt;a standard error/result pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Session 6 delivered the first actual business module end to end:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain&lt;/li&gt;
&lt;li&gt;repository&lt;/li&gt;
&lt;li&gt;notifier&lt;/li&gt;
&lt;li&gt;presentation&lt;/li&gt;
&lt;li&gt;real data from Supabase&lt;/li&gt;
&lt;li&gt;validated Row Level Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination was important because it was the first time the architecture stopped being an intention and started behaving like a system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session 5: from isolated login to real ERP navigation
&lt;/h2&gt;

&lt;p&gt;Session 5 focused on the navigation infrastructure of the app. Instead of continuing to add isolated screens, I built the foundation that defines how a user moves through the ERP.&lt;/p&gt;

&lt;p&gt;The key pieces implemented were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GoRouter&lt;/code&gt; with &lt;code&gt;ShellRoute&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a centralized router file in &lt;code&gt;lib/core/router.dart&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RouterNotifier&lt;/code&gt; to react to authentication changes&lt;/li&gt;
&lt;li&gt;a responsive &lt;code&gt;AppShell&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;HomeScreen&lt;/code&gt; with module cards&lt;/li&gt;
&lt;li&gt;placeholders for routes like dashboard and settings&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt; pattern to standardize failures across layers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was a big shift.&lt;/p&gt;

&lt;p&gt;Before that, the project had a login screen and authentication flow. After Session 5, it had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatic redirects based on authentication&lt;/li&gt;
&lt;li&gt;persistent navigation for authenticated screens&lt;/li&gt;
&lt;li&gt;different navigation behavior for desktop and mobile&lt;/li&gt;
&lt;li&gt;a home screen that already looked like the entry point of a modular ERP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to my session notes, the project moved from “an isolated login screen” to “an application with real navigation — sidebar on desktop, mobile navigation, automatic authentication-based redirect, and a working home screen with module cards.” fileciteturn12file4&lt;/p&gt;

&lt;h3&gt;
  
  
  The responsive AppShell
&lt;/h3&gt;

&lt;p&gt;One of the most important decisions from the previous architecture session was that the ERP should not let each screen invent its own layout. Instead, authenticated screens should live inside a shared shell. That decision became concrete in Session 5. The AppShell adapts navigation based on screen size, using a different structure for mobile, tablet, and desktop. fileciteturn12file4turn12file5&lt;/p&gt;

&lt;p&gt;That matters more than it seems.&lt;/p&gt;

&lt;p&gt;A login screen is just an entry point. A system starts to feel real when the user can move around it consistently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standardizing errors early
&lt;/h3&gt;

&lt;p&gt;The other important addition in Session 5 was &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt;, a sealed class used to standardize how repositories return either success or failure. From this point on, repositories are expected to return &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt; instead of throwing unchecked exceptions directly. The context document explicitly defines this as one of the non-negotiable architectural rules of the project. fileciteturn12file0&lt;/p&gt;

&lt;p&gt;That gave me a cleaner contract between layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repository returns &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;notifier translates the result into state&lt;/li&gt;
&lt;li&gt;widget renders the state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a small pattern, but it removes a lot of ambiguity when the project starts growing.&lt;/p&gt;

&lt;h3&gt;
  
  
  A session with an unexpected security check
&lt;/h3&gt;

&lt;p&gt;Session 5 also had something I did not expect: a security detour.&lt;/p&gt;

&lt;p&gt;Because of a reported RAT issue tied to the JavaScript ecosystem, I paused and verified my machine and other projects for traces of the malicious package. The result was clean, but the process itself was valuable. It reinforced a habit I want to keep: when a security concern appears, verify first and keep going with evidence instead of panic. fileciteturn12file6turn12file13&lt;/p&gt;

&lt;h2&gt;
  
  
  Session 6: the first real module, end to end
&lt;/h2&gt;

&lt;p&gt;If Session 5 made the project feel like an application, Session 6 made it feel like an ERP.&lt;/p&gt;

&lt;p&gt;This was the first real implementation session of the inventory module. In one session, I built the product feature through all layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain&lt;/li&gt;
&lt;li&gt;infrastructure&lt;/li&gt;
&lt;li&gt;state management&lt;/li&gt;
&lt;li&gt;presentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The concrete result was a working stock listing screen connected to Supabase in production, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a rich &lt;code&gt;Produto&lt;/code&gt; domain model&lt;/li&gt;
&lt;li&gt;a repository contract in the domain&lt;/li&gt;
&lt;li&gt;a Supabase repository implementation&lt;/li&gt;
&lt;li&gt;a notifier with sealed states&lt;/li&gt;
&lt;li&gt;search by name and internal code&lt;/li&gt;
&lt;li&gt;soft delete with confirmation&lt;/li&gt;
&lt;li&gt;visual low-stock indicators&lt;/li&gt;
&lt;li&gt;a validated multi-tenant RLS behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diary describes it as the first time a complete module was built “from domain to presentation in a single session,” with the stock module working through a full flow and RLS isolation validated in the database. fileciteturn12file1turn12file3&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;Produto&lt;/code&gt; domain model
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Produto&lt;/code&gt; class became the richest domain entity in the project so far.&lt;/p&gt;

&lt;p&gt;It includes identification, fiscal fields, stock quantities, pricing, location, image URL, reprocessing support, and multiple barcodes. It also includes derived properties like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;estoqueBaixo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ativo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was an important design moment because I wanted the domain object itself to answer business questions.&lt;/p&gt;

&lt;p&gt;For example, the UI should not decide whether stock is low. The product should know that.&lt;/p&gt;

&lt;p&gt;This is one of the parts that made the architecture feel practical rather than theoretical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repository and the result pattern in practice
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;IProdutoRepository&lt;/code&gt; contract was defined in the domain, and &lt;code&gt;SupabaseProdutoRepository&lt;/code&gt; became the only class in the feature that actually knows Supabase.&lt;/p&gt;

&lt;p&gt;That repository returns &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt; for every operation, applies soft delete, and performs the data access logic while keeping the rest of the feature independent from the backend implementation. The session notes also mention that PostgreSQL error codes were classified in the repository, which is exactly the kind of boundary I wanted to establish between infrastructure and the rest of the app. fileciteturn12file1&lt;/p&gt;

&lt;p&gt;Again, the rule stayed the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;widget does not know Supabase&lt;/li&gt;
&lt;li&gt;notifier does not know backend details&lt;/li&gt;
&lt;li&gt;repository knows infrastructure&lt;/li&gt;
&lt;li&gt;domain carries business meaning&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A visual result that actually means something
&lt;/h2&gt;

&lt;p&gt;By the end of Session 6, the stock screen was already showing three test products with meaningful feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a washer below minimum stock with a red indicator&lt;/li&gt;
&lt;li&gt;two other products above minimum stock with green indicators&lt;/li&gt;
&lt;li&gt;a visible product counter&lt;/li&gt;
&lt;li&gt;a working sidebar&lt;/li&gt;
&lt;li&gt;refresh button&lt;/li&gt;
&lt;li&gt;overflow menu&lt;/li&gt;
&lt;li&gt;a floating action button for future product creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly the kind of progress I wanted from this project: not just “data on the screen,” but data rendered with domain meaning. fileciteturn12file1&lt;/p&gt;

&lt;h2&gt;
  
  
  The accidental RLS test
&lt;/h2&gt;

&lt;p&gt;One of the best moments of Session 6 was not planned.&lt;/p&gt;

&lt;p&gt;A test ended up confirming that Row Level Security was working correctly in production. The isolation by &lt;code&gt;empresa_id&lt;/code&gt; was not just documented or assumed; it was observed behaving correctly. The context notes summarize it directly: RLS was validated in production, and data inserted with the wrong &lt;code&gt;empresa_id&lt;/code&gt; stayed invisible to the user. fileciteturn12file0turn12file13&lt;/p&gt;

&lt;p&gt;That was a very meaningful milestone for me.&lt;/p&gt;

&lt;p&gt;Because at that point, the project was no longer just “my architecture idea.” It had already validated one of its most important real-world constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these sessions taught me
&lt;/h2&gt;

&lt;p&gt;Sessions 5 and 6 reinforced something I am starting to understand more clearly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;architecture only starts to prove itself when real features begin to use it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is easy to feel good about clean folders and diagrams. It is harder, and much more valuable, to see those decisions survive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication redirects&lt;/li&gt;
&lt;li&gt;responsive navigation&lt;/li&gt;
&lt;li&gt;state transitions&lt;/li&gt;
&lt;li&gt;repository boundaries&lt;/li&gt;
&lt;li&gt;result handling&lt;/li&gt;
&lt;li&gt;database isolation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These two sessions were the first time I felt that happening consistently in the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;The next step is Session 7: parsing NF-e XML files and starting the fiscal side of the inventory workflow. The current context already defines the next targets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;XmlService&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;fiscal domain classes like &lt;code&gt;DocumentoFiscal&lt;/code&gt;, &lt;code&gt;NotaFiscal&lt;/code&gt;, and &lt;code&gt;ItemNota&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;repository and notifier for invoice import&lt;/li&gt;
&lt;li&gt;a file selection screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notas_fiscais&lt;/code&gt; and &lt;code&gt;nota_itens&lt;/code&gt; tables in Supabase. fileciteturn12file13turn12file17&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is important because inventory without invoice import would still be incomplete for the actual use case I have in mind.&lt;/p&gt;

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

&lt;p&gt;Session 5 gave the ERP a real application structure.&lt;/p&gt;

&lt;p&gt;Session 6 gave it its first real business module.&lt;/p&gt;

&lt;p&gt;Together, they marked the moment when the project stopped feeling like a prototype and started feeling like the beginning of a real system.&lt;/p&gt;

&lt;p&gt;That does not mean it is complete. It is not.&lt;/p&gt;

&lt;p&gt;But it now has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;responsive navigation&lt;/li&gt;
&lt;li&gt;a modular home screen&lt;/li&gt;
&lt;li&gt;a working inventory listing&lt;/li&gt;
&lt;li&gt;search&lt;/li&gt;
&lt;li&gt;soft delete&lt;/li&gt;
&lt;li&gt;standardized error handling&lt;/li&gt;
&lt;li&gt;validated multi-tenant isolation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, that is a meaningful threshold.&lt;/p&gt;

&lt;p&gt;If you are also building a portfolio project and trying to learn architecture through something real instead of toy examples, this has been one of the most rewarding parts of the journey so far.&lt;/p&gt;

&lt;p&gt;I will keep documenting the next steps.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>supabase</category>
      <category>riverpod</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I spent 3 hours writing no code — and it may have saved weeks on my ERP project</title>
      <dc:creator>Leandro Horas Pereira</dc:creator>
      <pubDate>Tue, 31 Mar 2026 09:07:00 +0000</pubDate>
      <link>https://dev.to/leorasgg/i-spent-3-hours-writing-no-code-and-it-may-have-saved-weeks-on-my-erp-project-2mnk</link>
      <guid>https://dev.to/leorasgg/i-spent-3-hours-writing-no-code-and-it-may-have-saved-weeks-on-my-erp-project-2mnk</guid>
      <description>&lt;h2&gt;
  
  
  Why this session mattered
&lt;/h2&gt;

&lt;p&gt;Session 4 of my &lt;strong&gt;ERP Modular&lt;/strong&gt; project had no code at all.&lt;/p&gt;

&lt;p&gt;No UI.&lt;br&gt;
No new repository.&lt;br&gt;
No new feature branch with a working screen.&lt;/p&gt;

&lt;p&gt;And it may still have been one of the most important sessions so far.&lt;/p&gt;

&lt;p&gt;Instead of implementing the next feature immediately, I spent about three hours reviewing the project structure, identifying architectural gaps, and formalizing decisions that would affect every module from this point on.&lt;/p&gt;

&lt;p&gt;That changed the nature of the project.&lt;/p&gt;

&lt;p&gt;It stopped being just a technically planned app and started becoming a &lt;strong&gt;structured product architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;ERP Modular is an open source portfolio project I am building with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flutter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supabase&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riverpod v3&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GoRouter&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current focus is still &lt;strong&gt;Module 1: Warehouse and Inventory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The first three sessions had already covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project planning&lt;/li&gt;
&lt;li&gt;setup and infrastructure&lt;/li&gt;
&lt;li&gt;full authentication with layered architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By Session 4, the codebase already had a foundation. But the architectural review showed that some important questions had not yet been fully decided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should happen right after login?&lt;/li&gt;
&lt;li&gt;How should permissions work beyond a simple &lt;code&gt;role&lt;/code&gt; field?&lt;/li&gt;
&lt;li&gt;Should stock be controlled only per product, or per product &lt;strong&gt;and&lt;/strong&gt; lot?&lt;/li&gt;
&lt;li&gt;How should invoice duplication be handled?&lt;/li&gt;
&lt;li&gt;What conventions should remain stable across future modules?&lt;/li&gt;
&lt;li&gt;How should the system represent errors consistently?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are exactly the kinds of decisions that often get postponed until the code starts hurting.&lt;/p&gt;

&lt;p&gt;I wanted to make them before that happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was defined in Session 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. A real ERP entry point instead of jumping straight into Inventory
&lt;/h3&gt;

&lt;p&gt;One of the first decisions was to stop thinking of the app as “login -&amp;gt; inventory”.&lt;/p&gt;

&lt;p&gt;That would not fit a modular ERP.&lt;/p&gt;

&lt;p&gt;So the post-login entry point became a &lt;strong&gt;general ERP home screen&lt;/strong&gt;, with module cards shown according to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the company has activated&lt;/li&gt;
&lt;li&gt;what the user has permission to access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That seems small, but it changes the entire navigation structure.&lt;/p&gt;

&lt;p&gt;Instead of a feature-first entry point, the app now has a &lt;strong&gt;product-level entry point&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Permissions in three layers
&lt;/h3&gt;

&lt;p&gt;A single &lt;code&gt;role&lt;/code&gt; field would not be enough.&lt;/p&gt;

&lt;p&gt;So the permission model was defined in three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role&lt;/strong&gt; — the user's broad profile (&lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;supervisor&lt;/code&gt;, &lt;code&gt;operator&lt;/code&gt;, &lt;code&gt;sales&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module&lt;/strong&gt; — which modules the company has active&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; — what the user can do inside each module (&lt;code&gt;view&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;approve&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This matters because real systems rarely map cleanly to a single role.&lt;/p&gt;

&lt;p&gt;For example, two users can both be operators while still having different permissions inside Inventory.&lt;/p&gt;

&lt;p&gt;The verification strategy was also defined in three places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GoRouter&lt;/strong&gt; for route-level redirection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;widgets&lt;/strong&gt; for UI visibility and usability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RLS in Supabase&lt;/strong&gt; for actual data protection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last part is important: hiding a button is not security.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Product and stock modeling became much more realistic
&lt;/h2&gt;

&lt;p&gt;The product model was expanded well beyond the original basic structure.&lt;/p&gt;

&lt;p&gt;It now includes concepts such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple barcodes&lt;/li&gt;
&lt;li&gt;NCM and CEST fields&lt;/li&gt;
&lt;li&gt;physical location&lt;/li&gt;
&lt;li&gt;image URL&lt;/li&gt;
&lt;li&gt;cost and sale price&lt;/li&gt;
&lt;li&gt;reprocessing support&lt;/li&gt;
&lt;li&gt;lot control&lt;/li&gt;
&lt;li&gt;expiry date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest modeling decision was this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;stock will be tracked by product and by lot from the beginning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That has a major impact on the domain and database design, but it avoids a very common problem: starting with a simplified stock model and later discovering that the business flow actually needs traceability.&lt;/p&gt;

&lt;p&gt;In this project, traceability matters.&lt;/p&gt;

&lt;p&gt;That means the system needs to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;total stock for a product&lt;/li&gt;
&lt;li&gt;current stock for a specific lot&lt;/li&gt;
&lt;li&gt;lot origin in reprocessing scenarios&lt;/li&gt;
&lt;li&gt;which lot was used in each movement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much better to decide now than to retrofit later.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Invoice duplication is no longer a vague edge case
&lt;/h2&gt;

&lt;p&gt;Another important decision was around duplicate NF-e imports.&lt;/p&gt;

&lt;p&gt;For readers outside Brazil: &lt;strong&gt;NF-e&lt;/strong&gt; (“Nota Fiscal eletrônica”) is the standardized electronic invoice format widely used in the country, and these invoices are often processed through XML files.&lt;/p&gt;

&lt;p&gt;The system now has a defined duplication strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;detect duplicates by the invoice access key&lt;/li&gt;
&lt;li&gt;show the existing record and its current status&lt;/li&gt;
&lt;li&gt;allow navigation to the original note&lt;/li&gt;
&lt;li&gt;allow reimport only with a required reason and supervisor approval&lt;/li&gt;
&lt;li&gt;register the exception separately&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A unique constraint on &lt;code&gt;chave_acesso&lt;/code&gt; in the database was also defined to prevent duplication even if the Flutter logic fails.&lt;/p&gt;

&lt;p&gt;That is one of my favorite types of decision: &lt;strong&gt;protect the flow both in the app and in the database&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Conference is now treated as a real state machine
&lt;/h2&gt;

&lt;p&gt;This was one of the biggest improvements in the session.&lt;/p&gt;

&lt;p&gt;The conference flow is no longer just “open” or “closed”.&lt;/p&gt;

&lt;p&gt;It now has an explicit state machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;criada&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;em_andamento&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pausada&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;divergente&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aguardando_aprovacao&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;concluida&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancelada&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reaberta&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More important than the list of states were the rules around the transitions.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;any operator can pause and resume a conference&lt;/li&gt;
&lt;li&gt;a divergent conference requires supervisor approval with a reason&lt;/li&gt;
&lt;li&gt;reopening a completed conference also requires supervisor approval and a reason&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the kind of business rule that becomes fragile when modeled with booleans.&lt;/p&gt;

&lt;p&gt;A state machine makes it explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Naming conventions and error handling were standardized
&lt;/h2&gt;

&lt;p&gt;Two technical patterns became formal rules during this session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Naming
&lt;/h3&gt;

&lt;p&gt;The project now has a definitive naming convention for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database tables&lt;/li&gt;
&lt;li&gt;Dart classes&lt;/li&gt;
&lt;li&gt;interfaces&lt;/li&gt;
&lt;li&gt;repository implementations&lt;/li&gt;
&lt;li&gt;files and folders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database tables use &lt;strong&gt;plural snake_case&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Dart classes use &lt;strong&gt;singular PascalCase&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;interfaces use the &lt;code&gt;I&lt;/code&gt; prefix&lt;/li&gt;
&lt;li&gt;Supabase implementations use the &lt;code&gt;Supabase&lt;/code&gt; prefix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sounds boring until the project starts growing.&lt;/p&gt;

&lt;p&gt;At that point, inconsistent names become friction everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error handling with &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This was another major decision.&lt;/p&gt;

&lt;p&gt;Repositories will no longer throw raw exceptions to the rest of the app.&lt;/p&gt;

&lt;p&gt;Instead, they return a sealed result type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Sucesso&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Falha&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And failures are classified by a &lt;code&gt;TipoFalha&lt;/code&gt; enum, with cases such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;domain&lt;/li&gt;
&lt;li&gt;permission&lt;/li&gt;
&lt;li&gt;not found&lt;/li&gt;
&lt;li&gt;duplicate&lt;/li&gt;
&lt;li&gt;invalid XML&lt;/li&gt;
&lt;li&gt;network&lt;/li&gt;
&lt;li&gt;server&lt;/li&gt;
&lt;li&gt;unknown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule by layer became:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;repository&lt;/strong&gt; returns &lt;code&gt;Resultado&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;notifier&lt;/strong&gt; translates that into state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;widget&lt;/strong&gt; displays state without knowing the failure type directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is one of the cleanest architectural decisions made so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. A universal module guide was created
&lt;/h2&gt;

&lt;p&gt;The final big outcome of the session was the creation of a &lt;strong&gt;Universal Module Guide&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The point of that document is simple:&lt;/p&gt;

&lt;p&gt;I do not want to re-decide the same architectural rules every time a new module is created.&lt;/p&gt;

&lt;p&gt;So instead of having architecture spread across memory, old chats, and assumptions, the project now has a reusable reference that defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mandatory folder structure&lt;/li&gt;
&lt;li&gt;quality checklist&lt;/li&gt;
&lt;li&gt;rules shared by all modules&lt;/li&gt;
&lt;li&gt;module lifecycle&lt;/li&gt;
&lt;li&gt;things that should never be done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means future modules such as Sales, Technical Support, or Dashboards can start from a defined standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned from a session with no code
&lt;/h2&gt;

&lt;p&gt;This session reinforced something I am starting to value more and more:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;architecture is not a delay before coding. It is one of the ways you avoid writing the wrong code faster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It also reminded me that a good architecture review does not need to happen only inside one tool or from one perspective.&lt;/p&gt;

&lt;p&gt;This session used both Claude and ChatGPT as structured reviewers for the same set of documents.&lt;/p&gt;

&lt;p&gt;The result was surprisingly useful.&lt;/p&gt;

&lt;p&gt;Not because either one “solved the architecture”, but because they pushed the review from different angles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one helped consolidate decisions&lt;/li&gt;
&lt;li&gt;the other helped identify missing points and inconsistencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That process felt very close to a lightweight version of peer review.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;The next session returns to implementation.&lt;/p&gt;

&lt;p&gt;The immediate goal is to replace &lt;code&gt;home: LoginScreen&lt;/code&gt; in &lt;code&gt;main.dart&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GoRouter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ShellRoute&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;a responsive &lt;strong&gt;AppShell&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a general &lt;strong&gt;HomeScreen&lt;/strong&gt; with module cards&lt;/li&gt;
&lt;li&gt;authentication-based redirection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But now that code will be written on top of a much clearer architectural base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;A lot of beginner portfolio projects try to prove skill by showing how many features were shipped quickly.&lt;/p&gt;

&lt;p&gt;I am trying something different.&lt;/p&gt;

&lt;p&gt;I want this project to show that I am learning how to make technical decisions with intention.&lt;/p&gt;

&lt;p&gt;Sometimes that means writing code.&lt;/p&gt;

&lt;p&gt;Sometimes it means spending three hours writing no code at all — and still moving the project forward in a way that matters.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>architecture</category>
      <category>supabase</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building a Modular ERP from Scratch with Flutter, Supabase, and Riverpod — Part 1</title>
      <dc:creator>Leandro Horas Pereira</dc:creator>
      <pubDate>Sun, 29 Mar 2026 10:36:59 +0000</pubDate>
      <link>https://dev.to/leorasgg/building-a-modular-erp-from-scratch-with-flutter-supabase-and-riverpod-part-1-3jck</link>
      <guid>https://dev.to/leorasgg/building-a-modular-erp-from-scratch-with-flutter-supabase-and-riverpod-part-1-3jck</guid>
      <description>&lt;h2&gt;
  
  
  English Version 🇺🇸
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why I started this project
&lt;/h2&gt;

&lt;p&gt;I decided to build a modular ERP as a portfolio project with two goals in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build something real, with actual business value&lt;/li&gt;
&lt;li&gt;learn professional software development in practice instead of studying isolated concepts with no real context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The project is called &lt;strong&gt;ERP Modular&lt;/strong&gt;, and it is aimed at small businesses.&lt;/p&gt;

&lt;p&gt;Right now, the focus is &lt;strong&gt;only on Module 1: Warehouse and Inventory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is not to jump into multiple modules at once. The goal is to build a solid foundation first and expand later with more confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am building
&lt;/h2&gt;

&lt;p&gt;In this first module, I want to support a real operational flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;import NF-e XML files, the XML documents used by Brazil's electronic invoice system&lt;/li&gt;
&lt;li&gt;read barcodes&lt;/li&gt;
&lt;li&gt;check invoice items against scanned products&lt;/li&gt;
&lt;li&gt;manage inventory with movement history&lt;/li&gt;
&lt;li&gt;generate conference PDFs&lt;/li&gt;
&lt;li&gt;support multiple companies with Row Level Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this is not just a pretty UI project. It is a system designed around real business rules.&lt;/p&gt;

&lt;p&gt;For readers outside Brazil: NF-e ("Nota Fiscal eletrônica") is the standardized electronic invoice format widely used in the country.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chosen stack
&lt;/h2&gt;

&lt;p&gt;The stack I chose was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flutter&lt;/strong&gt; for the frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase&lt;/strong&gt; for the backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Riverpod&lt;/strong&gt; for state management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go Router&lt;/strong&gt; for navigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mobile_scanner&lt;/strong&gt; for barcode scanning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xml&lt;/strong&gt; for NF-e parsing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose Flutter because I wanted a single codebase that could eventually run on web, desktop, and mobile.&lt;/p&gt;

&lt;p&gt;I chose Supabase because I wanted a real PostgreSQL database, built-in authentication, storage, and row-level security without having to maintain my own backend from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most important rule of the project
&lt;/h2&gt;

&lt;p&gt;Before writing the first line of code, I defined one rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I did not want to repeat the beginner mistake of coding without direction and accumulating technical debt from the very first commit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because of that, my first session was entirely dedicated to planning.&lt;/p&gt;

&lt;p&gt;I wrote no code at all. And that was intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session 1: planning before implementation
&lt;/h2&gt;

&lt;p&gt;In the first session, I defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the scope of the current module&lt;/li&gt;
&lt;li&gt;the technical stack&lt;/li&gt;
&lt;li&gt;the layered architecture&lt;/li&gt;
&lt;li&gt;the feature-based folder structure&lt;/li&gt;
&lt;li&gt;Git rules&lt;/li&gt;
&lt;li&gt;the initial database model&lt;/li&gt;
&lt;li&gt;the OOP concepts and design patterns I wanted to apply consciously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib/
  features/
    estoque/
      presentation/
      application/
      domain/
      infrastructure/
    notas/
      presentation/
      application/
      domain/
      infrastructure/
    conferencia/
      presentation/
      application/
      domain/
      infrastructure/
  core/
    services/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;presentation&lt;/code&gt; displays&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;application&lt;/code&gt; orchestrates state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domain&lt;/code&gt; defines rules and contracts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;infrastructure&lt;/code&gt; implements external access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also established a few golden rules from the beginning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no widget talks directly to the database&lt;/li&gt;
&lt;li&gt;no provider knows where the data comes from&lt;/li&gt;
&lt;li&gt;complex objects should be created through factory constructors&lt;/li&gt;
&lt;li&gt;commits must follow Conventional Commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That first session mattered because it forced me to think like someone building a real system, not just assembling screens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session 2: setup and infrastructure
&lt;/h2&gt;

&lt;p&gt;In the second session, planning became real structure.&lt;/p&gt;

&lt;p&gt;That was when I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;created the public GitHub repository&lt;/li&gt;
&lt;li&gt;configured the project in Supabase&lt;/li&gt;
&lt;li&gt;generated the Flutter project correctly&lt;/li&gt;
&lt;li&gt;organized the layered folder structure&lt;/li&gt;
&lt;li&gt;added &lt;code&gt;supabase_flutter&lt;/code&gt;, &lt;code&gt;flutter_riverpod&lt;/code&gt;, and &lt;code&gt;go_router&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;initialized Supabase in the app&lt;/li&gt;
&lt;li&gt;ran the application on Linux desktop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One detail that changed my mindset was the fact that the first important commit was not a feature.&lt;/p&gt;

&lt;p&gt;It was &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I protected credentials before almost anything else, including the local Supabase configuration file.&lt;/p&gt;

&lt;p&gt;That may sound small, but it is not.&lt;/p&gt;

&lt;p&gt;It was a technical decision to avoid leaking something sensitive into the repository history right at the beginning.&lt;/p&gt;

&lt;p&gt;Another important part of this session was getting more intentional exposure to terminal commands and Git.&lt;/p&gt;

&lt;p&gt;I had used Git before, but this was the moment when I started to better understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;staging&lt;/li&gt;
&lt;li&gt;the difference between local and remote&lt;/li&gt;
&lt;li&gt;commit organization&lt;/li&gt;
&lt;li&gt;the value of small commits&lt;/li&gt;
&lt;li&gt;commit history visualization in VS Code Source Control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seeing Supabase initialized and the app running for the first time was a simple milestone, but a very meaningful one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session 3: full authentication and the first real engineering moment
&lt;/h2&gt;

&lt;p&gt;The third session was the most intense one so far.&lt;/p&gt;

&lt;p&gt;In about two hours, I implemented the complete authentication feature while respecting the project's layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;domain&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;infrastructure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;presentation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final result was a real login flow with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email and password authentication&lt;/li&gt;
&lt;li&gt;form validation&lt;/li&gt;
&lt;li&gt;loading and error states&lt;/li&gt;
&lt;li&gt;display of the authenticated user's name and role&lt;/li&gt;
&lt;li&gt;working logout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the most important part was not that the login worked.&lt;/p&gt;

&lt;p&gt;It was &lt;strong&gt;how it was built&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The &lt;code&gt;Usuario&lt;/code&gt; domain class
&lt;/h3&gt;

&lt;p&gt;This was the first real domain entity in the project.&lt;/p&gt;

&lt;p&gt;I consciously applied:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;final&lt;/code&gt; fields&lt;/li&gt;
&lt;li&gt;a constructor with required named parameters&lt;/li&gt;
&lt;li&gt;&lt;code&gt;factory Usuario.fromMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;equality and &lt;code&gt;hashCode&lt;/code&gt; overrides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was the moment when some OOP concepts finally started to make sense in practice.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;immutability&lt;/strong&gt;: an authenticated user should not suddenly become a different user during execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;encapsulation&lt;/strong&gt;: the object controls its own state and its own creation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;IAuthRepository&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of letting the UI or the state layer talk directly to the backend, I defined an abstract contract with the main authentication methods.&lt;/p&gt;

&lt;p&gt;In other words, anything that depends on this repository knows &lt;strong&gt;what it does&lt;/strong&gt;, but not &lt;strong&gt;how it does it&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;SupabaseAuthRepository&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This class isolated the concrete Supabase implementation.&lt;/p&gt;

&lt;p&gt;That taught me an important distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supabase Auth handles credentials&lt;/li&gt;
&lt;li&gt;business-related user data lives in the &lt;code&gt;usuarios&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the flow was not just “log in.”&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;authenticate with Supabase Auth&lt;/li&gt;
&lt;li&gt;fetch the user's name, role, and company data&lt;/li&gt;
&lt;li&gt;transform that raw data into a valid domain object&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That was one of those moments when architecture stopped being a diagram and became code with clear responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;AuthState&lt;/code&gt; and &lt;code&gt;AuthNotifier&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For state management, I modeled the authentication scenarios explicitly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;initial&lt;/li&gt;
&lt;li&gt;loading&lt;/li&gt;
&lt;li&gt;authenticated&lt;/li&gt;
&lt;li&gt;unauthenticated&lt;/li&gt;
&lt;li&gt;error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That helped me understand why explicit state modeling avoids invalid combinations and makes UI logic simpler.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;code&gt;LoginScreen&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The screen became responsible for observing state and displaying what made sense for each scenario.&lt;/p&gt;

&lt;p&gt;No database logic.&lt;br&gt;&lt;br&gt;
No infrastructure logic.&lt;br&gt;&lt;br&gt;
No improper coupling.&lt;/p&gt;

&lt;p&gt;That was exactly the kind of separation I wanted to practice in this project.&lt;/p&gt;
&lt;h2&gt;
  
  
  The mistake that taught me the most so far
&lt;/h2&gt;

&lt;p&gt;Not everything worked on the first try.&lt;/p&gt;

&lt;p&gt;In Session 3, I started implementing the authentication state using a &lt;strong&gt;Riverpod v2&lt;/strong&gt; pattern, but the project was already using &lt;strong&gt;Riverpod v3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The result was a lot of errors at once in the editor.&lt;/p&gt;

&lt;p&gt;It was frustrating for a few minutes, but it turned into one of the best lessons so far.&lt;/p&gt;

&lt;p&gt;Because the problem was not simply “the code is broken.”&lt;/p&gt;

&lt;p&gt;The problem was more professional than that:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I was using an outdated pattern for a different version of the library.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fixing it required rewriting the implementation using &lt;code&gt;Notifier&lt;/code&gt; and &lt;code&gt;NotifierProvider&lt;/code&gt;, and that made the concept much clearer than if everything had worked immediately.&lt;/p&gt;

&lt;p&gt;Another small but useful mistake also happened: I committed an empty interface file because I forgot to save it before running &lt;code&gt;git add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I fixed it with a &lt;code&gt;fix&lt;/code&gt; commit and enabled autosave to prevent it from happening again.&lt;/p&gt;
&lt;h2&gt;
  
  
  What this project is actually teaching me
&lt;/h2&gt;

&lt;p&gt;So far, the biggest gain is not only technical.&lt;/p&gt;

&lt;p&gt;It is mindset.&lt;/p&gt;

&lt;p&gt;I am starting to understand more clearly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;why architecture is not bureaucracy&lt;/li&gt;
&lt;li&gt;why separating responsibilities reduces confusion&lt;/li&gt;
&lt;li&gt;why small commits improve the way I think&lt;/li&gt;
&lt;li&gt;why patterns make sense when they emerge as solutions to real problems&lt;/li&gt;
&lt;li&gt;why documenting blockers is just as valuable as documenting wins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am also seeing something important in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;good code does not appear ready-made.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It improves as the foundation, criteria, and understanding improve.&lt;/p&gt;
&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;The next focus of the project is to keep expanding the Warehouse and Inventory module according to the roadmap, moving toward product listing screens, product modeling, XML import, barcode-based checking, stock movements, and reports.&lt;/p&gt;

&lt;p&gt;But the priority remains the same:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;grow with consistency, not in a hurry.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project is my way of studying software development more honestly.&lt;/p&gt;

&lt;p&gt;Instead of only consuming theory, I am trying to build something real and use every step to better understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OOP&lt;/li&gt;
&lt;li&gt;layered architecture&lt;/li&gt;
&lt;li&gt;design patterns&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;domain modeling&lt;/li&gt;
&lt;li&gt;backend integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is still the beginning.&lt;/p&gt;

&lt;p&gt;But it is the most solid beginning I have managed to build so far.&lt;/p&gt;

&lt;p&gt;If you are also studying architecture, Flutter, or building a portfolio project with more intention than urgency, I will keep documenting this journey.&lt;/p&gt;


&lt;h2&gt;
  
  
  Versão em Português 🇧🇷
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Por que comecei este projeto
&lt;/h2&gt;

&lt;p&gt;Decidi construir um ERP modular como projeto de portfólio com dois objetivos em mente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;construir algo real, com valor de negócio de verdade&lt;/li&gt;
&lt;li&gt;aprender desenvolvimento de software de forma prática, em vez de estudar conceitos isolados sem contexto real&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O projeto se chama &lt;strong&gt;ERP Modular&lt;/strong&gt; e é voltado para pequenos negócios.&lt;/p&gt;

&lt;p&gt;Neste momento, o foco está &lt;strong&gt;somente no Módulo 1: Almoxarifado e Estoque&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A ideia não é sair construindo vários módulos de uma vez. A prioridade é criar uma base sólida primeiro e expandir depois com mais confiança.&lt;/p&gt;
&lt;h2&gt;
  
  
  O que estou construindo
&lt;/h2&gt;

&lt;p&gt;Neste primeiro módulo, quero atender um fluxo operacional real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;importar arquivos XML de NF-e&lt;/li&gt;
&lt;li&gt;ler códigos de barras&lt;/li&gt;
&lt;li&gt;conferir itens da nota com os produtos escaneados&lt;/li&gt;
&lt;li&gt;controlar o estoque com histórico de movimentações&lt;/li&gt;
&lt;li&gt;gerar PDFs de conferência&lt;/li&gt;
&lt;li&gt;suportar múltiplas empresas com Row Level Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ou seja, este não é apenas um projeto com uma interface bonita. É um sistema pensado em torno de regras de negócio reais.&lt;/p&gt;
&lt;h2&gt;
  
  
  Stack escolhida
&lt;/h2&gt;

&lt;p&gt;A stack que defini foi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flutter&lt;/strong&gt; no frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase&lt;/strong&gt; no backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Riverpod&lt;/strong&gt; para gerenciamento de estado&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go Router&lt;/strong&gt; para navegação&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mobile_scanner&lt;/strong&gt; para leitura de códigos de barras&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xml&lt;/strong&gt; para parse de NF-e&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Escolhi Flutter porque queria um único codebase com potencial para rodar em web, desktop e mobile.&lt;/p&gt;

&lt;p&gt;Escolhi Supabase porque queria um banco PostgreSQL real, autenticação pronta, storage e segurança em nível de linha sem precisar manter um backend próprio desde o primeiro dia.&lt;/p&gt;
&lt;h2&gt;
  
  
  A regra mais importante do projeto
&lt;/h2&gt;

&lt;p&gt;Antes de escrever a primeira linha de código, defini uma regra:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;eu não queria repetir o erro de iniciante de sair codando sem direção e acumular dívida técnica desde o primeiro commit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Por isso, minha primeira sessão foi inteiramente dedicada ao planejamento.&lt;/p&gt;

&lt;p&gt;Eu não escrevi nenhuma linha de código. E isso foi intencional.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sessão 1: planejamento antes da implementação
&lt;/h2&gt;

&lt;p&gt;Na primeira sessão, defini:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;o escopo do módulo atual&lt;/li&gt;
&lt;li&gt;a stack técnica&lt;/li&gt;
&lt;li&gt;a arquitetura em camadas&lt;/li&gt;
&lt;li&gt;a estrutura de pastas por feature&lt;/li&gt;
&lt;li&gt;as regras de Git&lt;/li&gt;
&lt;li&gt;a modelagem inicial do banco&lt;/li&gt;
&lt;li&gt;os conceitos de POO e os design patterns que eu queria aplicar conscientemente&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A arquitetura ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib/
  features/
    estoque/
      presentation/
      application/
      domain/
      infrastructure/
    notas/
      presentation/
      application/
      domain/
      infrastructure/
    conferencia/
      presentation/
      application/
      domain/
      infrastructure/
  core/
    services/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lógica era simples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;presentation&lt;/code&gt; exibe&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;application&lt;/code&gt; orquestra estado&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domain&lt;/code&gt; define regras e contratos&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;infrastructure&lt;/code&gt; implementa o acesso externo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Também estabeleci algumas regras de ouro desde o começo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nenhum widget fala diretamente com o banco de dados&lt;/li&gt;
&lt;li&gt;nenhum provider sabe de onde os dados vêm&lt;/li&gt;
&lt;li&gt;objetos complexos devem ser criados por factory constructors&lt;/li&gt;
&lt;li&gt;os commits precisam seguir Conventional Commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa primeira sessão foi importante porque me obrigou a pensar como alguém que está construindo um sistema real, e não apenas juntando telas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sessão 2: setup e infraestrutura
&lt;/h2&gt;

&lt;p&gt;Na segunda sessão, o planejamento virou estrutura real.&lt;/p&gt;

&lt;p&gt;Foi quando eu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;criei o repositório público no GitHub&lt;/li&gt;
&lt;li&gt;configurei o projeto no Supabase&lt;/li&gt;
&lt;li&gt;gerei o projeto Flutter corretamente&lt;/li&gt;
&lt;li&gt;organizei a estrutura de pastas da arquitetura&lt;/li&gt;
&lt;li&gt;adicionei &lt;code&gt;supabase_flutter&lt;/code&gt;, &lt;code&gt;flutter_riverpod&lt;/code&gt; e &lt;code&gt;go_router&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;inicializei o Supabase no app&lt;/li&gt;
&lt;li&gt;rodei a aplicação no Linux desktop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um detalhe que mudou minha forma de pensar foi o fato de o primeiro commit importante não ter sido uma feature.&lt;/p&gt;

&lt;p&gt;Foi o &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Eu protegi as credenciais antes de quase qualquer outra coisa, incluindo o arquivo local de configuração do Supabase.&lt;/p&gt;

&lt;p&gt;Isso pode parecer pequeno, mas não é.&lt;/p&gt;

&lt;p&gt;Foi uma decisão técnica para evitar que algo sensível vazasse para o histórico do repositório logo no começo.&lt;/p&gt;

&lt;p&gt;Outra parte importante dessa sessão foi ter um contato mais intencional com comandos de terminal e com Git.&lt;/p&gt;

&lt;p&gt;Eu já tinha usado Git antes, mas esse foi o momento em que comecei a entender melhor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;staging&lt;/li&gt;
&lt;li&gt;a diferença entre local e remoto&lt;/li&gt;
&lt;li&gt;a organização dos commits&lt;/li&gt;
&lt;li&gt;o valor de commits pequenos&lt;/li&gt;
&lt;li&gt;a visualização do histórico de commits no Source Control do VS Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ver o Supabase inicializado e o app rodando pela primeira vez foi um marco simples, mas muito significativo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sessão 3: autenticação completa e o primeiro momento real de engenharia de software
&lt;/h2&gt;

&lt;p&gt;A terceira sessão foi a mais intensa até agora.&lt;/p&gt;

&lt;p&gt;Em cerca de duas horas, implementei a feature completa de autenticação respeitando as camadas do projeto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;domain&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;infrastructure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;presentation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O resultado final foi um fluxo de login real com:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;autenticação por e-mail e senha&lt;/li&gt;
&lt;li&gt;validação de formulário&lt;/li&gt;
&lt;li&gt;estados de carregamento e erro&lt;/li&gt;
&lt;li&gt;exibição do nome e do papel do usuário autenticado&lt;/li&gt;
&lt;li&gt;logout funcionando&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mas a parte mais importante não foi apenas o login funcionar.&lt;/p&gt;

&lt;p&gt;Foi &lt;strong&gt;como ele foi construído&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. A classe de domínio &lt;code&gt;Usuario&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Essa foi a primeira entidade de domínio real do projeto.&lt;/p&gt;

&lt;p&gt;Nela, apliquei conscientemente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;campos &lt;code&gt;final&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;construtor com parâmetros nomeados obrigatórios&lt;/li&gt;
&lt;li&gt;&lt;code&gt;factory Usuario.fromMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;sobrescrita de igualdade e &lt;code&gt;hashCode&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse foi o momento em que alguns conceitos de POO finalmente começaram a fazer sentido na prática.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;imutabilidade&lt;/strong&gt;: um usuário autenticado não deve simplesmente virar outro durante a execução&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;encapsulamento&lt;/strong&gt;: o objeto controla o próprio estado e a própria criação&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;IAuthRepository&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Em vez de deixar a UI ou a camada de estado falarem diretamente com o backend, defini um contrato abstrato com os principais métodos de autenticação.&lt;/p&gt;

&lt;p&gt;Em outras palavras, qualquer parte que dependa desse repositório sabe &lt;strong&gt;o que ele faz&lt;/strong&gt;, mas não &lt;strong&gt;como ele faz&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;SupabaseAuthRepository&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Essa classe isolou a implementação concreta com Supabase.&lt;/p&gt;

&lt;p&gt;Isso me ensinou uma distinção importante:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;o Supabase Auth cuida das credenciais&lt;/li&gt;
&lt;li&gt;os dados de negócio do usuário ficam na tabela &lt;code&gt;usuarios&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então o fluxo não era apenas “fazer login”.&lt;/p&gt;

&lt;p&gt;Era:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;autenticar com o Supabase Auth&lt;/li&gt;
&lt;li&gt;buscar nome, papel e dados da empresa do usuário&lt;/li&gt;
&lt;li&gt;transformar esses dados brutos em um objeto de domínio válido&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esse foi um daqueles momentos em que a arquitetura deixou de ser um diagrama e virou código com responsabilidades claras.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;AuthState&lt;/code&gt; e &lt;code&gt;AuthNotifier&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;No gerenciamento de estado, modelei explicitamente os cenários da autenticação:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inicial&lt;/li&gt;
&lt;li&gt;carregando&lt;/li&gt;
&lt;li&gt;autenticado&lt;/li&gt;
&lt;li&gt;não autenticado&lt;/li&gt;
&lt;li&gt;erro&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso me ajudou a entender por que uma modelagem explícita de estados evita combinações inválidas e simplifica a lógica da UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;code&gt;LoginScreen&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A tela passou a ser responsável por observar o estado e exibir o que fazia sentido em cada cenário.&lt;/p&gt;

&lt;p&gt;Sem lógica de banco de dados.&lt;br&gt;&lt;br&gt;
Sem lógica de infraestrutura.&lt;br&gt;&lt;br&gt;
Sem acoplamento indevido.&lt;/p&gt;

&lt;p&gt;Esse era exatamente o tipo de separação que eu queria praticar neste projeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  O erro que mais me ensinou até agora
&lt;/h2&gt;

&lt;p&gt;Nem tudo funcionou de primeira.&lt;/p&gt;

&lt;p&gt;Na Sessão 3, comecei implementando o estado da autenticação com um padrão de &lt;strong&gt;Riverpod v2&lt;/strong&gt;, mas o projeto já estava usando &lt;strong&gt;Riverpod v3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O resultado foi uma grande quantidade de erros de uma vez no editor.&lt;/p&gt;

&lt;p&gt;Foi frustrante por alguns minutos, mas acabou se tornando uma das melhores lições até aqui.&lt;/p&gt;

&lt;p&gt;Porque o problema não era simplesmente “o código está quebrado”.&lt;/p&gt;

&lt;p&gt;O problema era mais profissional do que isso:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;eu estava usando um padrão desatualizado para uma versão diferente da biblioteca.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Corrigir isso exigiu reescrever a implementação usando &lt;code&gt;Notifier&lt;/code&gt; e &lt;code&gt;NotifierProvider&lt;/code&gt;, e isso deixou o conceito muito mais claro do que se tudo tivesse funcionado de primeira.&lt;/p&gt;

&lt;p&gt;Outro erro pequeno, mas útil, também aconteceu: comitei um arquivo de interface vazio porque esqueci de salvá-lo antes de executar &lt;code&gt;git add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Corrigi com um commit de &lt;code&gt;fix&lt;/code&gt; e ativei o autosave para evitar que isso aconteça de novo.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que este projeto está realmente me ensinando
&lt;/h2&gt;

&lt;p&gt;Até aqui, o maior ganho não é apenas técnico.&lt;/p&gt;

&lt;p&gt;É mentalidade.&lt;/p&gt;

&lt;p&gt;Estou começando a entender com mais clareza:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;por que arquitetura não é burocracia&lt;/li&gt;
&lt;li&gt;por que separar responsabilidades reduz confusão&lt;/li&gt;
&lt;li&gt;por que commits pequenos melhoram a forma como eu penso&lt;/li&gt;
&lt;li&gt;por que patterns fazem sentido quando surgem como solução para problemas reais&lt;/li&gt;
&lt;li&gt;por que documentar travamentos é tão valioso quanto documentar acertos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Também estou vendo algo importante na prática:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;código bom não aparece pronto.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Ele melhora à medida que a base, os critérios e o entendimento evoluem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Próximos passos
&lt;/h2&gt;

&lt;p&gt;O próximo foco do projeto é continuar expandindo o módulo de Almoxarifado e Estoque de acordo com o cronograma, avançando para telas de listagem de produtos, modelagem de produto, importação de XML, conferência por código de barras, movimentações de estoque e relatórios.&lt;/p&gt;

&lt;p&gt;Mas a prioridade continua a mesma:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;crescer com consistência, não com pressa.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Este projeto é a minha forma de estudar desenvolvimento de software de maneira mais honesta.&lt;/p&gt;

&lt;p&gt;Em vez de apenas consumir teoria, estou tentando construir algo real e usar cada etapa para entender melhor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POO&lt;/li&gt;
&lt;li&gt;arquitetura em camadas&lt;/li&gt;
&lt;li&gt;design patterns&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;modelagem de domínio&lt;/li&gt;
&lt;li&gt;integração com backend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ainda é só o começo.&lt;/p&gt;

&lt;p&gt;Mas é o começo mais sólido que já consegui construir até aqui.&lt;/p&gt;

&lt;p&gt;Se você também está estudando arquitetura, Flutter ou construindo um projeto de portfólio com mais intenção do que urgência, eu vou continuar documentando essa jornada.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>supabase</category>
      <category>dart</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
