<?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>Forem: Jay P</title>
    <description>The latest articles on Forem by Jay P (@jaypa).</description>
    <link>https://forem.com/jaypa</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%2F3143423%2F4a789afa-1075-4dac-b7e8-8cbd8236f9a9.jpg</url>
      <title>Forem: Jay P</title>
      <link>https://forem.com/jaypa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jaypa"/>
    <language>en</language>
    <item>
      <title>Lessons from Building a Full Invoice App for the Price of a Netflix Subscription</title>
      <dc:creator>Jay P</dc:creator>
      <pubDate>Fri, 09 May 2025 20:59:47 +0000</pubDate>
      <link>https://forem.com/jaypa/lessons-from-building-a-full-invoice-app-for-the-price-of-a-netflix-subscription-jbb</link>
      <guid>https://forem.com/jaypa/lessons-from-building-a-full-invoice-app-for-the-price-of-a-netflix-subscription-jbb</guid>
      <description>&lt;p&gt;Like a lot of devs, I built a side project that scratched a personal itch: an invoice generator. But instead of going full SaaS startup mode, I treated it as a challenge—build something clean, useful, and fast, with a real login system, server-side PDF generation, and as little overhead as possible.&lt;/p&gt;

&lt;p&gt;The result is &lt;a href="https://invoiceden.com" rel="noopener noreferrer"&gt;InvoiceDen&lt;/a&gt;, a React-based web app hosted on Cloudflare Pages, with backend functionality on an EC2 instance, all for about $8/month.&lt;/p&gt;

&lt;p&gt;Here’s what I learned architecting it on a shoestring budget — and how you can do something similar without spinning up Kubernetes or draining your wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ The Stack
&lt;/h2&gt;

&lt;p&gt;The app is split into a classic frontend + backend setup, but optimized for cost and simplicity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; React app hosted on Cloudflare Pages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static deploys, global CDN, zero dollars&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; Small server on a tiny EC2 instance&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles login, PDF generation, and basic routing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Auth:&lt;/strong&gt; Email/password login using bcrypt + sessions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Firebase, no OAuth maze&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;PDFs:&lt;/strong&gt; Generated on the server using pdfkit&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outputs a clean PDF based on user inputs and invoice state&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Despite being a “small project,” it touches almost every part of a typical web stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Why I Didn’t Go Full Serverless
&lt;/h2&gt;

&lt;p&gt;I considered doing everything client-side (including PDF generation), but it had some real downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDFs from the browser&lt;/strong&gt; can be inconsistent across devices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Email/password auth&lt;/strong&gt; is still easier to reason about with a session-based backend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some features (like saving draft invoices) were easier to build with a traditional API&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;EC2 gave me just enough flexibility to do what I needed—without pulling in a full Firebase/Serverless/PostgreSQL setup. It’s old-school, but reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  💸 The Actual Cost
&lt;/h2&gt;

&lt;p&gt;Here’s the real breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare Pages&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EC2 (t3.micro)&lt;/td&gt;
&lt;td&gt;~$8/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain name&lt;/td&gt;
&lt;td&gt;Already owned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB/Storage&lt;/td&gt;
&lt;td&gt;Handled on EC2 (tiny volume)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Could I go cheaper? Yes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ditch EC2 and use Cloudflare Workers or Vercel Edge Functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move auth to Clerk/Auth0 (free tiers available)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use client-side PDF generation with html2pdf.js or jsPDF (with quality tradeoffs)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But EC2 kept me in full control and let me skip learning yet another platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗️ Lessons from the Build
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Start static, scale dynamic
&lt;/h3&gt;

&lt;p&gt;I built the entire frontend as a static React app before wiring up any backend. Cloudflare Pages made it stupidly easy to deploy and test changes. Even with backend features now, the frontend still deploys independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. PDF generation is trickier than it looks
&lt;/h3&gt;

&lt;p&gt;Client-side libraries are great for MVPs, but if you want consistency across browsers and control over page layout, server-side tools like pdfkit are worth the effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Auth doesn’t need to be fancy
&lt;/h3&gt;

&lt;p&gt;I skipped magic links, OAuth, and social login. Just bcrypt-hashed passwords + sessions. Boring, secure, and works across devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. React is overkill until it’s not
&lt;/h3&gt;

&lt;p&gt;This could’ve been built with vanilla JS… until I added features like draft saving, invoice previews, and quick item inputs. At that point, React’s state model and component abstraction saved a ton of time.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Minimal doesn’t mean messy
&lt;/h3&gt;

&lt;p&gt;The app has no tracking, no upsells, and no bloat. But it still feels polished thanks to small UX touches: instant preview, one-click PDF, simple item entry. You don’t need 100 features to feel "complete."&lt;/p&gt;

&lt;h2&gt;
  
  
  🧰 Tools That Made Life Easier
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React + Vite&lt;/strong&gt; for dev speed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloudflare Pages&lt;/strong&gt; for dead-simple deploys&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EC2&lt;/strong&gt; for backend logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pdfkit&lt;/strong&gt; for clean PDF rendering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plain CSS + minimal color&lt;/strong&gt; for fast load and print-friendly design&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✅ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This wasn’t a startup idea, it was a technical exercise:&lt;br&gt;
&lt;strong&gt;How far can you push a modern stack while keeping it lean, low-cost, and useful?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’m still iterating on it, but building InvoiceDen reminded me that you don’t need a whole platform or team to make something real.&lt;/p&gt;

&lt;p&gt;If you’ve been sitting on a tool you’ve wanted to build, I say skip the boilerplate and just get something working. Then polish it until it’s fun.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
