<?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: Thibaut Flat-Patrick</title>
    <description>The latest articles on DEV Community by Thibaut Flat-Patrick (@flattibaut).</description>
    <link>https://dev.to/flattibaut</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%2F3245518%2Ffdca794b-ee39-4b5e-a0f9-4a096ae19f69.png</url>
      <title>DEV Community: Thibaut Flat-Patrick</title>
      <link>https://dev.to/flattibaut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flattibaut"/>
    <language>en</language>
    <item>
      <title>nFolyo Post-MVP - Architecture and Tech Stack Review</title>
      <dc:creator>Thibaut Flat-Patrick</dc:creator>
      <pubDate>Fri, 20 Jun 2025 06:52:15 +0000</pubDate>
      <link>https://dev.to/flattibaut/nfolyo-post-mvp-architecture-and-tech-stack-review-11ep</link>
      <guid>https://dev.to/flattibaut/nfolyo-post-mvp-architecture-and-tech-stack-review-11ep</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.nfolyo.com/posts/03-architecture-review" rel="noopener noreferrer"&gt;nfolyo blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://blog.nfolyo.com/posts/02-mvp-postmortem" rel="noopener noreferrer"&gt;nFolyo MVP Postmortem – What We Learned Building a Portfolio Tracker&lt;/a&gt;, we briefly introduced our tech stack and architecture. This post delves deeper into the technical decisions behind nFolyo, outlining our current architecture and its key limitations. We'll then present our approach for the upcoming v0.5.0 release, where we're restructuring our architecture with scalability and responsiveness in mind.&lt;/p&gt;

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

&lt;p&gt;Before discussing any restructuring, it's crucial to understand how our services and web apps currently interact and their limitations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5xj773v07g6zp2w02n2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5xj773v07g6zp2w02n2.png" alt="nFolyo services and web apps architecture as of v0.4.0" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;nFolyo Client App&lt;/strong&gt; serves as our user-facing frontend. Built with NextJS/TypeScript, it uses a combination of RadixUI and custom-made components. This app performs minimal data calculations, delegating most data processing to our Python services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nFolyo Core&lt;/strong&gt;, built with Flask in Python, is responsible for updating user accounts. It provides importers for various brokers (currently only Interactive Brokers and Freetrade) to import activities such as trades, dividends, fees, cash transactions, and corporate actions. During import, all broker activity undergoes standardization to strip private information, eliminate differences between brokers, and ensure consistent data handling. We'll explore this process in a future post.&lt;/p&gt;

&lt;p&gt;To compute metrics like market value, PnL, and TWRR, nFolyo Core fetches pricing and foreign exchange data from the &lt;strong&gt;nFolyo Finance&lt;/strong&gt; service. nFolyo Finance serves as our price API that fetches, aggregates, and standardizes pricing data from external providers (such as Yahoo Finance), ensuring reliable data and fast retrieval.&lt;/p&gt;

&lt;p&gt;You'll notice the &lt;strong&gt;nFolyo Admin&lt;/strong&gt; web app in the diagram. We've recently moved all admin functionality from the nFolyo Client App to a separate VPN-protected web app. nFolyo Admin, built with Next.js and shadcn/ui, lets us manage beta test users, handle user accounts, and monitor performance through benchmarking data.&lt;/p&gt;

&lt;p&gt;One detail omitted from our diagram for simplicity: both nFolyo Core and Finance services write to the &lt;strong&gt;nFolyo Benchmarker Database&lt;/strong&gt;, which feeds data to the benchmarking tools in our admin web app. The benchmarker is a separate Python module we wrote to help us better understand our performance bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Works, and What Doesn't
&lt;/h2&gt;

&lt;p&gt;Let's be honest: nFolyo is slow. There are two main reasons: we're running on low-tier Azure services, and our architecture doesn't allow for proper task parallelization. Before scaling up our infrastructure, we need to address the fundamental architectural bottlenecks. Otherwise, we'll hit the same issues with larger user volumes and more features built on a shaky foundation, making future refactoring difficult.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dissecting the &lt;code&gt;/update-account&lt;/code&gt; Endpoint
&lt;/h3&gt;

&lt;p&gt;Let's examine the &lt;code&gt;/update-account&lt;/code&gt; endpoint that handles account updates. It's our worst-case scenario, implemented as a monolithic function for quick MVP development.&lt;/p&gt;

&lt;p&gt;It performs these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collects all holding symbols and unique currency pairs from the user's holdings&lt;/li&gt;
&lt;li&gt;Fetches latest price/FX data from nFolyo Finance&lt;/li&gt;
&lt;li&gt;Updates holdings market value, PnL, and other metrics&lt;/li&gt;
&lt;li&gt;Aggregates holding values into themes and account metrics (market value, PnL, etc)&lt;/li&gt;
&lt;li&gt;For each holding:

&lt;ul&gt;
&lt;li&gt;Fetches historical prices and FX data&lt;/li&gt;
&lt;li&gt;Calculates TWRR, market value over time, cash in and outflows&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Aggregates these to themes and the overall account historical charts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdxd1f98j8woceyenvip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdxd1f98j8woceyenvip.png" alt="Sequence diagram of  raw `/update-account` endraw " width="670" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown in the sequence diagram, there are many steps in a single call. During this time, nFolyo Core is blocked from serving other requests while the user's frontend displays the "updating your account" component.&lt;/p&gt;

&lt;p&gt;While we've improved the component in v0.4.0 to provide more information about the current stage of the account update, it remains a long wait. We're not displaying information to the user as it becomes available (e.g., holding, theme account market value, PnL).&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmarking the Bottleneck
&lt;/h3&gt;

&lt;p&gt;In the benchmarker screenshot below, you'll see &lt;code&gt;/update-account&lt;/code&gt; taking 20 minutes to complete! While this example is particularly bad due to concurrent requests at peak CCU, it illustrates the worst-case scenario we need to address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzn94xxh44kmqvruw1nk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzn94xxh44kmqvruw1nk.png" alt=" raw `/update-account` endraw  nFolyo Core benchmarker screenshot" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that &lt;code&gt;getHistoricalData&lt;/code&gt; takes about 1 minute 20 seconds — unacceptable, but not our biggest problem!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;performance.calculateHoldingPerformanceTWRR (111)&lt;/code&gt; is even worse, consuming 80% of the total time! This severely impacts user experience — nobody wants to wait minutes to view their account data. While some delay during initial import might be acceptable, it shouldn't be the norm.&lt;/p&gt;

&lt;p&gt;Several factors contribute to this poor performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We process holdings sequentially, in this case, 111 holdings one after another.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;calculateHoldingPerformanceTWRR()&lt;/code&gt; function itself is inefficient. Pandas struggles with large datasets, especially when combining multiple tables (historical prices, historical FX data, corporate actions) for TWRR calculations.&lt;/li&gt;
&lt;li&gt;Theme and account TWRR calculations must wait for all holdings to complete before they can start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solutions: Task Splitting, Parallelization, and New Price Provider
&lt;/h3&gt;

&lt;p&gt;What are we doing to address these issues?&lt;/p&gt;

&lt;p&gt;First, we'll tackle the 80% bottleneck by parallelizing the TWRR calculations. Instead of using Python threads, we're adopting a more scalable message queue pattern. We'll split or completely convert nFolyo Core into a Celery worker, queueing tasks to Redis or RabbitMQ.&lt;/p&gt;

&lt;p&gt;This approach will allow us to queue all TWRR tasks and scale up workers for faster processing when needed. Even with just two Celery workers running in parallel, we could nearly halve processing time.&lt;/p&gt;

&lt;p&gt;Secondly, we're switching price providers to reduce the 1-minute-20-second historical price retrieval to 10–20 seconds. Combined with scheduled background price and account updates, this should reduce friction between user actions and data visibility.&lt;/p&gt;

&lt;p&gt;We'll optimize TWRR calculation performance by exploring Polars, a performance-focused alternative to Pandas, while improving our TWRR algorithm.&lt;/p&gt;

&lt;p&gt;Finally, we'll split the &lt;code&gt;/update-account&lt;/code&gt; endpoint into smaller tasks (separating quick operations like price updates from slower TWRR calculations). This lets users view current market values while TWRR charts process in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolving the Architecture
&lt;/h2&gt;

&lt;p&gt;Let's examine the suggested architecture diagram below that accommodates these solutions. This diagram omits some services and apps (like admin app, common and benchmarker DBs) to highlight the fundamental architectural changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvscheq2vd1kq4pb087dg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvscheq2vd1kq4pb087dg.png" alt="Suggested architecture for nFolyo v0.5.0" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key improvement is offloading heavy tasks to Python Celery workers. These can scale up and run in the background while keeping the UI responsive and showing data as they become available.&lt;/p&gt;

&lt;p&gt;This architecture coupled with Server-Sent Events should allow us to provide more frequent task status updates, eliminating our current expensive polling approach, the result of fast development for MVP and Azure function limitations (45sec timeout).&lt;/p&gt;

&lt;p&gt;This is a suggested architecture, meaning that things are subject to change as we progress our development. At the moment we believe we'll split out a big chunk of the nFolyo Core business logic to &lt;strong&gt;nFolyo Core Celery Workers&lt;/strong&gt;, starting with the heaviest tasks. nFolyo Core will remain to receive requests and orchestrate the heavier tasks.&lt;/p&gt;

&lt;p&gt;The scheduled jobs will probably end up either queuing tasks directly to the message queue or do it via nFolyo Core endpoints. We're also exploring whether the nFolyo Client App itself should queue tasks directly. Many possibilities are open and we'll be revising our suggested architecture once they become more concrete.&lt;/p&gt;

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

&lt;p&gt;In this post, we examined nFolyo's current architecture and tech stack, identified key bottlenecks, and highlighted the scalability challenges we're facing. We used &lt;code&gt;/update-account&lt;/code&gt; as a case study to demonstrate where and why performance breaks down.&lt;/p&gt;

&lt;p&gt;To address these issues, we're revising our architecture and refactoring critical services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introducing a message queue to enable parallel task execution.&lt;/li&gt;
&lt;li&gt;Offloading heavy computations to Celery workers, with nFolyo Core orchestrating and dispatching tasks.&lt;/li&gt;
&lt;li&gt;Breaking up monolithic functions into smaller, async-friendly tasks, with Server-Sent Events providing updates for a more responsive UI.&lt;/li&gt;
&lt;li&gt;Scheduling background updates to execute heavy calculations ahead of user interaction.&lt;/li&gt;
&lt;li&gt;Switching to a faster, more efficient price provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we roll out v0.5.0, we'll share more learnings and code details. For now, we're focused on making nFolyo faster, smoother, and ready to scale.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>webperf</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>nFolyo MVP Postmortem - What We Learned Building a Portfolio Tracker</title>
      <dc:creator>Thibaut Flat-Patrick</dc:creator>
      <pubDate>Fri, 06 Jun 2025 20:39:09 +0000</pubDate>
      <link>https://dev.to/flattibaut/nfolyo-mvp-postmortem-what-we-learned-building-a-portfolio-tracker-2cg9</link>
      <guid>https://dev.to/flattibaut/nfolyo-mvp-postmortem-what-we-learned-building-a-portfolio-tracker-2cg9</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://blog.nfolyo.com/posts/02-mvp-postmortem/" rel="noopener noreferrer"&gt;nfolyo blog&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We do not learn from experience… we learn from reflecting on experience. — John Dewey&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;nFolyo&lt;/strong&gt; is a portfolio tracking and analysis tool built for long-term investors like us — with global portfolios invested across equities and ETFs, not just limited to US and EU markets.&lt;/p&gt;

&lt;p&gt;It started as a collection of Python scripts and spreadsheets we used to manage our own portfolios. Over time, it evolved into a full-featured tool and became our learning ground for modern web development and microservice architectures.&lt;/p&gt;

&lt;p&gt;We released our MVP in November 2024 after eight months of intense development. After iterating on early user feedback, we released version 0.4.0 in March 2025 with several improvements. Now, we're at a turning point that requires us to rethink our approach and make some difficult decisions.&lt;/p&gt;

&lt;p&gt;To do that well, we need to pause and reflect.&lt;/p&gt;

&lt;p&gt;This postmortem marks the start of the next chapter — a chance to look back on over a year of development, two releases, what worked, what didn't, and where we go from here.&lt;/p&gt;

&lt;h2&gt;
  
  
  History of Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Our Tech Stack
&lt;/h3&gt;

&lt;p&gt;nFolyo is made up of a frontend app (&lt;code&gt;nfolyo-client&lt;/code&gt;) and two backend services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;nfolyo-core&lt;/strong&gt;: handles account and portfolio updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nfolyo-finance&lt;/strong&gt;: responsible for fetching pricing and historical data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll dig into our architecture in a future post, but here's an overview of our current stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt;: For the frontend, we chose Next.js as it's a mature and powerful framework that supports full-stack development and server-side rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python and Flask&lt;/strong&gt;: For the &lt;code&gt;nfolyo-core&lt;/code&gt; and &lt;code&gt;nfolyo-finance&lt;/code&gt; background services, we went with Python and Flask. Flask makes it easy to build APIs quickly, and Python is particularly strong for data processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt;: We selected MongoDB as our database due to its scalability and our prior experience working with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure&lt;/strong&gt;: We're deploying on Azure, using Docker containers and GitHub Actions for continuous deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Road to MVP
&lt;/h3&gt;

&lt;p&gt;We set a minimum feature set before nFolyo was ready to be shared with other investors. Our original roadmap targeted a September 2024 release, but as you can see in our revised roadmap (pointing to October/November 2024), we underestimated the work involved!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcw22dl3mkowzqz3xar3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcw22dl3mkowzqz3xar3.webp" alt="MVP roadmap (target release date Sep 2024)" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9kv8u7ritvfiwon9rvw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9kv8u7ritvfiwon9rvw.webp" alt="Revised MVP Roadmap (target release date Nov 2024)" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MVP Launch, User Feedback &amp;amp; Iteration
&lt;/h3&gt;

&lt;p&gt;We released the MVP in November 2024 to a closed group of beta users. It wasn't polished, and while we extensively tested our broker activity importers (Interactive Brokers and Freetrade), we couldn't guarantee it would parse every user's data.&lt;/p&gt;

&lt;p&gt;We were fortunate to have extremely patient beta testers who not only helped us fix major bugs but also provided crucial feedback to improve our user experience. Their support was invaluable.&lt;/p&gt;

&lt;p&gt;Over the next few months, we focused on the most critical bugs and usability issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed price inaccuracies and broker importer errors.&lt;/li&gt;
&lt;li&gt;Improved TWRR performance calculations.&lt;/li&gt;
&lt;li&gt;Added clearer feedback during statement import and account updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;v0.4.0 launched in March 2025, incorporating those changes. Check out the release notes &lt;a href="https://blog.nfolyo.com/posts/01-release-v0-4-0" rel="noopener noreferrer"&gt;nFolyo v0.4.0 – Improved Import and Account Status Updates&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Are We Now? Pausing and Reflecting
&lt;/h3&gt;

&lt;p&gt;Despite all the progress and great user feedback, we're now at a crossroads. Some of our early tech and architectural decisions, made to speed up MVP development, are starting to catch up with us. It's becoming clear that our current infrastructure won't scale up easily.&lt;/p&gt;

&lt;p&gt;Without a more maintainable foundation, adding new features will only get harder and more expensive over time. We have a long list of ideas that could make nFolyo truly powerful and unique; however, without rethinking and refactoring our core architecture, those ideas risk remaining just ideas.&lt;/p&gt;

&lt;p&gt;So what do we do?&lt;/p&gt;

&lt;p&gt;We decided to pause the closed beta while we focus on the next major release. (You can still sign up to register your interest and we'll notify you as soon as the next version is out). This gives us the freedom to break things without the pressure of maintaining backward compatibility and continuous live operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Good
&lt;/h3&gt;

&lt;p&gt;It's been a great learning experience — diving deep into &lt;strong&gt;Next.js&lt;/strong&gt;, &lt;strong&gt;Python&lt;/strong&gt;, &lt;strong&gt;Flask&lt;/strong&gt;, and &lt;strong&gt;Azure&lt;/strong&gt; with real hands-on challenges.&lt;/p&gt;

&lt;p&gt;We've implemented many features in a short time, all while holding down full-time jobs.&lt;/p&gt;

&lt;p&gt;We've had highly engaged users testing the app, providing valuable feedback, helping us uncover bugs we couldn't have found alone. Their time and support have been invaluable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bad
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Burnout&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Balancing full-time jobs with late nights and weekends on a side project isn't sustainable. Passion keeps things going for a while, but long-term time management and maintaining a healthy work-life(-side-project) balance is essential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Building in Isolation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We didn't engage publicly early enough. No community, no dev blog, no social presence. All these factors slowed down feedback and iteration loops significantly. Building nFolyo in public from day one could have helped us course-correct faster and save development time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Poor UI Component Library Choices, Failure to Explore Alternatives&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We started with &lt;strong&gt;Radix UI&lt;/strong&gt;, but hit limitations when customizing components. We ended up creating many of our own, which introduced styling inconsistencies and duplicated effort (e.g., building an editable/sortable table).&lt;/p&gt;

&lt;p&gt;In hindsight, switching to shadcn/ui early would've saved loads of time and given us more consistent styling out of the box. This decision alone added months of unnecessary frontend work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No Broker API Auto-Sync&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We assumed most users would be fine uploading broker statements manually. But feedback shows otherwise. Around 80% of users (ourselves included) want automatic sync via broker APIs to make their lives easier.&lt;/p&gt;

&lt;p&gt;We avoided this to keep development simple, but going forward we need to support it to stay competitive. The challenge will be balancing automation with privacy. We're hesitant to rely on third-party aggregators like Yodlee or Plaid, but that's something we need to explore more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Underinvesting in a Pricing API&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We chose Yahoo Finance's public API because it was cheap and provided global coverage for equities and ETFs — perfect for proving out the MVP. But it's slow. Really slow. Historical pricing queries in particular introduce major latency, which affects calculations like TWRR performance charts. We've had to build a whole layer of caching and data cleanup just to make it performant enough, costing us weeks of effort. For serious use, we'll need a more robust solution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. No Async/Message Queue Architecture&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To keep things simple early on, we built a monolithic background service that updates a user's account in one big API call. That was fine for launch, but on accounts with long trade histories and many holdings, it now takes up to 10 minutes. The processing isn't parallelized and quickly becomes a bottleneck, affecting the user experience.&lt;/p&gt;

&lt;p&gt;What we really need is an asynchronous, distributed system using a message queue (e.g., &lt;strong&gt;RabbitMQ&lt;/strong&gt; or &lt;strong&gt;Redis&lt;/strong&gt;) and a task processor like &lt;strong&gt;Celery&lt;/strong&gt;. That would let us split jobs into smaller tasks (units of work), process them in parallel, and give real-time progress updates using something like Server-Sent Events (SSE).&lt;/p&gt;

&lt;p&gt;Not doing this is now our &lt;strong&gt;biggest architectural limitation&lt;/strong&gt;. It made sense for the MVP, but it's blocking future progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Azure Deployment Pain Points&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This was our first time deploying such a complex app on Azure. While getting things up and running wasn't too painful, we ran into real performance issues:&lt;/p&gt;

&lt;p&gt;Our Flask services run as &lt;strong&gt;App Services&lt;/strong&gt;; on low-tier plans, performance is poor, while high-tier plans are expensive. Additionally, the lack of async mechanisms means we're paying for idle services much of the time.&lt;/p&gt;

&lt;p&gt;The Next.js frontend is deployed as a &lt;strong&gt;Static Web App&lt;/strong&gt; using &lt;strong&gt;Azure Functions&lt;/strong&gt; for APIs. Cold starts can cause 15 - 30 second delays, and Azure Functions 45-second timeout complicates long-polling and SSE.&lt;/p&gt;

&lt;p&gt;We're rethinking our deployment strategy to better suit the performance demands of a scalable application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learnings
&lt;/h3&gt;

&lt;p&gt;Here are the key takeaways from our journey so far.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Manage your Time Wisely&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It's better to make consistent, small progress than to go all-in, burn out, and need a long break — or worse, lose all motivation and abandon the project. Sustainability &amp;gt; speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Build in Public Early&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Share progress openly and engage users from the start. It might feel like you're moving slower, but early feedback helps you avoid building the wrong things — saving time in the long run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Use Mature, Customizable UI Component Libraries&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don't reinvent the wheel. Component libraries like &lt;strong&gt;shadcn/ui&lt;/strong&gt; are tried and tested and can save you weeks of work. Building our own sortable, editable table from scratch wasn't very wise and cost us precious development time, we should have just used &lt;strong&gt;TanStack Table&lt;/strong&gt;. Don't make the same mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Lay Solid Architectural Foundations (When it Matters)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you're just validating an idea, quick-and-dirty is fine. But if, like us, you know this is something you want to build for the long term, invest early in scalable architecture. It'll save you months of technical debt later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Choose Your APIs Carefully&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don't default to the cheapest solution. While it's fine to start lean, poor APIs can introduce major delays and reliability issues. At the very least, build abstraction layers (e.g., interfaces or base classes) so you can easily swap out the API later without a full rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;To wrap things up, here's a quick overview of what's next for nFolyo. We'll go into more detail — including our roadmap to v0.5.0 — in future posts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. We're Intentionally Slowing Down Development&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This is a marathon, not a sprint. To build something great — for ourselves and our users — we need to manage our time better and avoid burnout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. We're Building in Public and Sharing More&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This blog is a big part of that. Expect more updates, learnings, and technical deep-dives as we go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. We're Refactoring Our Backend for Scalability&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We're migrating to an architecture based on Celery with RabbitMQ (or Redis) for better performance and scalability. We plan to document this process, as most tutorials out there only scratch the surface and rarely cover real-world use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. We're Investing in Better Financial APIs and Exploring Broker API Integrations&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We're currently evaluating APIs like &lt;em&gt;Financial Modeling Prep&lt;/em&gt; and &lt;em&gt;EODHD&lt;/em&gt;, and looking into direct broker integrations for trade syncing. Our goal is to offer automation and convenience — without compromising user privacy or relying on third-party aggregators like Yodlee and Plaid. That said, we're keeping our options open if they offer the best balance of utility and privacy.&lt;/p&gt;

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

&lt;p&gt;Thanks for reading. We hope you found something useful in our journey — whether you're building your own tool, considering a side project, or just curious about the inner workings of portfolio tracking apps.&lt;/p&gt;

&lt;p&gt;Let us know what you think, we'd love to hear from you. You can find us on &lt;a href="https://x.com/NFolyo" rel="noopener noreferrer"&gt;X&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/nFolioApp" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>postmortem</category>
      <category>buildinpublic</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
