<?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: Dominic li</title>
    <description>The latest articles on DEV Community by Dominic li (@tallyassistant).</description>
    <link>https://dev.to/tallyassistant</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4019871%2F0e735219-46ae-4d29-88a4-75970c5edbfc.png</url>
      <title>DEV Community: Dominic li</title>
      <link>https://dev.to/tallyassistant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tallyassistant"/>
    <language>en</language>
    <item>
      <title>I Built an AI Bookkeeping Tool Because I Hated Doing It Manually</title>
      <dc:creator>Dominic li</dc:creator>
      <pubDate>Thu, 16 Jul 2026 14:15:59 +0000</pubDate>
      <link>https://dev.to/tallyassistant/i-built-an-ai-bookkeeping-tool-because-i-hated-doing-it-manually-13e8</link>
      <guid>https://dev.to/tallyassistant/i-built-an-ai-bookkeeping-tool-because-i-hated-doing-it-manually-13e8</guid>
      <description>&lt;p&gt;I'm a solo developer. Two months ago I launched &lt;a href="https://tallyassistant.com" rel="noopener noreferrer"&gt;Tally Assistant&lt;/a&gt; — an AI-powered bookkeeping tool. Here's why I built it, what I learned, and the tech stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: CSVs from hell
&lt;/h2&gt;

&lt;p&gt;Every month I'd download bank statements from PayPal, Stripe, Wise, and my traditional bank. Four completely different CSV formats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;&lt;span class="nv"&gt;Stripe:&lt;/span&gt;  &lt;span class="s2"&gt;"2026-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Payment from acct_123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;1500.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;John&lt;/span&gt; &lt;span class="k"&gt;Doe&lt;/span&gt;
&lt;span class="nv"&gt;PayPal:&lt;/span&gt;  &lt;span class="s2"&gt;"7/11/2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"14:30:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"PDT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Alice Johnson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"850.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"-24.65"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"825.35"&lt;/span&gt;
&lt;span class="k"&gt;German&lt;/span&gt; &lt;span class="nv"&gt;bank:&lt;/span&gt; &lt;span class="s2"&gt;"11.07.2026"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;"Cloudflare Inc"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;"-10,46"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;
&lt;span class="k"&gt;UK&lt;/span&gt; &lt;span class="nv"&gt;bank:&lt;/span&gt;  &lt;span class="s2"&gt;"11/07/2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"NOTION LABS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"10.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"£1,234.56"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different date formats. Different delimiters. Different decimal separators. Different currency columns. Manual reconciliation took 2-3 hours every month. I tried QuickBooks (US-centric, no AI), Wave (free but multi-currency is broken), and FreshBooks (decent invoicing, no AI). Nothing fit.&lt;/p&gt;

&lt;p&gt;So I built what I needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Upload any bank CSV&lt;/strong&gt; → AI auto-detects delimiter, date format, decimal separator, currency column. 200+ bank formats supported. No reformatting, no template setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snap a payment screenshot&lt;/strong&gt; → AI OCR extracts merchant, amount, currency, and date in 50+ languages. Original image saved as tax documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate an invoice from one sentence&lt;/strong&gt; → "Logo design $300, landing page $700 for Acme Corp, 6% VAT" → AI builds the invoice with line items, tax, PDF, and PayPal link. 5 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto payment reminders&lt;/strong&gt; → Escalating: friendly nudge Day 1, professional follow-up Day 7, firm final notice Day 21. AI-written, auto-sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-currency&lt;/strong&gt; → 30+ currencies with daily exchange rates. Each transaction keeps its original currency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Finance Chat&lt;/strong&gt; → "How much profit did I make in Q2?" — gets answered from your actual transaction data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt; (App Router) on Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; on Supabase + Prisma ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clerk&lt;/strong&gt; for auth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt; (GPT-5.4-mini) for CSV parsing, receipt OCR, invoice generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resend&lt;/strong&gt; for email delivery and payment reminders&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind&lt;/strong&gt; + shadcn/ui for the frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total hosting cost: $0/month. Every service is on a free tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CSV parsing: how it actually works
&lt;/h2&gt;

&lt;p&gt;The CSV import is the feature I'm most proud of. Here's the architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Programmatic delimiter detection&lt;/strong&gt; — scans the first 5 rows, counts field consistency for each candidate delimiter (&lt;code&gt;,&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt;, &lt;code&gt;\t&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;), picks the most consistent one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date format detection&lt;/strong&gt; — if any date has a value &amp;gt; 12 in position 1 → DD/MM/YYYY. If any has &amp;gt;12 in position 2 → MM/DD/YYYY. If all ≤ 12 in both → check currency/language heuristics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI column mapping&lt;/strong&gt; — the raw CSV (with detected delimiter + date format passed as hints) goes to GPT-5.4-mini. The AI maps columns by semantic meaning, not position. It handles headers in any language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client auto-matching&lt;/strong&gt; — the AI compares transaction descriptions against existing client names. New clients are auto-created.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote more about this in &lt;a href="https://tallyassistant.com/blog/why-every-bank-csv-is-different" rel="noopener noreferrer"&gt;Why Every Bank's CSV Is Different&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Launch earlier.&lt;/strong&gt; I spent 3 weeks on features before showing anyone. Should have launched after week 1 with just CSV import + invoicing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution is harder than building.&lt;/strong&gt; I spent 3 weeks coding, 5 weeks trying to get anyone to see it. The ratio should be closer to 1:1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Free" positioning is a double-edged sword.&lt;/strong&gt; It removes friction for users, but some people assume "free = low quality." I'm still figuring out how to communicate "it's free during launch because I want feedback, not because it's bad."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reddit &amp;gt; HN for my niche.&lt;/strong&gt; My HN posts got zero traction. My Reddit replies to people &lt;em&gt;actively complaining about bookkeeping&lt;/em&gt; got clicks and signups. Go where the pain is being discussed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Recurring invoices, Stripe payment links, a mobile app. And getting to the first 100 users. Currently at single digits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, roast it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tallyassistant.com" rel="noopener noreferrer"&gt;tallyassistant.com&lt;/a&gt; — completely free through September 2026. No credit card. If something about the CSV import or invoicing flow breaks on your specific use case, tell me. I fix bugs faster than big companies do.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>nextjs</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>The Ultimate Guide to AI Bookkeeping for Freelancers (2026)</title>
      <dc:creator>Dominic li</dc:creator>
      <pubDate>Mon, 13 Jul 2026 12:07:35 +0000</pubDate>
      <link>https://dev.to/tallyassistant/the-ultimate-guide-to-ai-bookkeeping-for-freelancers-2026-16mo</link>
      <guid>https://dev.to/tallyassistant/the-ultimate-guide-to-ai-bookkeeping-for-freelancers-2026-16mo</guid>
      <description>&lt;h2&gt;
  
  
  Why Freelancers Need a New Approach to Bookkeeping
&lt;/h2&gt;

&lt;p&gt;If you're a freelancer on Upwork, Fiverr, or Toptal, you know the drill. Every month you download bank statements, PayPal CSVs, and Stripe exports — each in a different format. You manually copy transaction details into a spreadsheet. You chase clients for overdue payments. You dig through camera rolls for receipt photos.&lt;/p&gt;

&lt;p&gt;Most freelancers start with spreadsheets. Then they move to basic accounting tools like QuickBooks or Wave. But none of them are built for how modern freelancers actually work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple payment platforms&lt;/strong&gt; — PayPal, Stripe, Wise, bank transfers, Venmo, Alipay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;International clients&lt;/strong&gt; — USD, EUR, GBP, CNY, JPY all in the same week&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screenshot-based records&lt;/strong&gt; — payment confirmations from apps, not formal receipts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV chaos&lt;/strong&gt; — every bank and platform exports differently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI-powered bookkeeping changes this entirely. Instead of spending hours manually categorizing transactions, you upload your bank CSV or snap a payment screenshot, and the AI does the rest — parsing amounts, detecting currencies, matching clients, and suggesting categories.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 5 Biggest Time Wastes in Freelance Bookkeeping
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Manual Data Entry (30–60 seconds per transaction)
&lt;/h3&gt;

&lt;p&gt;Every transaction you type by hand takes at least half a minute. With 100 transactions per month, that's over an hour of copying and pasting — every single month. Over a year, that's 12+ hours spent on data entry alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI fixes it:&lt;/strong&gt; Upload your bank CSV file. The AI parses every row automatically — extracting the date, amount, currency, description, category, and even client name. No reformatting required.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CSV Format Headaches
&lt;/h3&gt;

&lt;p&gt;Stripe CSVs look nothing like PayPal CSVs. A German bank uses DD.MM.YYYY and commas for decimals. A US bank uses MM/DD/YYYY and periods. Normalizing these manually is tedious and error-prone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI fixes it:&lt;/strong&gt; A universal AI CSV parser automatically detects the format of any file — date order, decimal separator, currency column — and normalizes everything into clean, categorized transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Multi-Currency Confusion
&lt;/h3&gt;

&lt;p&gt;You bill a UK client in GBP, pay for hosting in USD, and subscribe to a German SaaS tool in EUR. Manually tracking exchange rates and converting everything is time-consuming and mistake-prone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI fixes it:&lt;/strong&gt; When you snap a payment screenshot or import a CSV, the AI detects the currency symbol (€, $, £, ¥) per transaction — not just per file. The system automatically converts all amounts to your configured base currency at daily exchange rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Chasing Late Payments
&lt;/h3&gt;

&lt;p&gt;Following up on overdue invoices is awkward. You don't want to seem pushy, but you also need to get paid. Most freelancers either avoid sending reminders entirely or spend mental energy drafting them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI fixes it:&lt;/strong&gt; The system tracks invoice due dates and sends automated payment reminders. The tone escalates automatically — friendly in week one, professional in weeks two and three, and firm after 21 days. You configure it once and forget it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Dedicated to invoicing?&lt;/strong&gt; If AI invoicing is what you need most, see our &lt;a href="https://www.tallyassistant.com/features/ai-invoice-generator" rel="noopener noreferrer"&gt;AI invoicing for freelancers&lt;/a&gt; feature — type "Logo design $300, landing page $700 for Acme Corp" and get a complete invoice with tax and PayPal link in 60 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Receipt and Screenshot Management
&lt;/h3&gt;

&lt;p&gt;Paper receipts get lost. Screenshots pile up in your camera roll. When tax season arrives, you waste hours digging through folders to find proof of expenses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI fixes it:&lt;/strong&gt; Snap a photo or screenshot of any payment confirmation — bank transfer, PayPal receipt, Stripe dashboard, or WeChat Pay. The AI reads the amount, merchant name, currency, and date, then creates a categorized expense record. The original image is saved as supporting documentation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Workflow: A Freelance Designer's Week with AI Bookkeeping
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Monday morning:&lt;/strong&gt; Download the weekly bank CSV → upload to the dashboard → AI parses 23 transactions in under 10 seconds. Categories are auto-assigned (Cloudflare → Infrastructure, Notion → Tools &amp;amp; Software, client payment → Project Income). Two new clients are auto-detected and created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wednesday afternoon:&lt;/strong&gt; Receive a PayPal payment confirmation on your phone → screenshot → upload to AI Recognize → system extracts $850 from "Acme Corp" and creates an income record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Friday:&lt;/strong&gt; Create an invoice for a completed project. The form auto-fills client details. Add line items with AI assistance. The invoice includes a PayPal payment link. Send with one click. The client gets a professional PDF and a "Pay with PayPal" button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three weeks later:&lt;/strong&gt; The invoice is overdue. The system has already sent two polite reminders. The client pays. You mark it as paid. Done.&lt;/p&gt;




&lt;h2&gt;
  
  
  Spreadsheets vs. Basic Tools vs. AI Bookkeeping
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Spreadsheets&lt;/th&gt;
&lt;th&gt;QuickBooks / Wave&lt;/th&gt;
&lt;th&gt;Tally Assistant (AI-Powered)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CSV import&lt;/td&gt;
&lt;td&gt;Manual reformatting&lt;/td&gt;
&lt;td&gt;Limited formats&lt;/td&gt;
&lt;td&gt;Any format, auto-detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receipt capture&lt;/td&gt;
&lt;td&gt;Photo + manual entry&lt;/td&gt;
&lt;td&gt;Photo + manual match&lt;/td&gt;
&lt;td&gt;AI reads &amp;amp; extracts automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-currency&lt;/td&gt;
&lt;td&gt;Manual conversion&lt;/td&gt;
&lt;td&gt;Manual rate entry&lt;/td&gt;
&lt;td&gt;Auto-detect per item + daily rates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invoicing&lt;/td&gt;
&lt;td&gt;Manual creation&lt;/td&gt;
&lt;td&gt;Templates&lt;/td&gt;
&lt;td&gt;AI-assisted + PayPal payment link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment reminders&lt;/td&gt;
&lt;td&gt;You write them&lt;/td&gt;
&lt;td&gt;Basic automation&lt;/td&gt;
&lt;td&gt;AI-generated, tone-escalating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client matching&lt;/td&gt;
&lt;td&gt;Manual lookup&lt;/td&gt;
&lt;td&gt;Separate CRM&lt;/td&gt;
&lt;td&gt;Auto-detected from transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50 transactions&lt;/td&gt;
&lt;td&gt;~1 hour&lt;/td&gt;
&lt;td&gt;~30 minutes&lt;/td&gt;
&lt;td&gt;~2 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  I spend hours every month copying bank transactions into a spreadsheet. How much time can I actually save?
&lt;/h3&gt;

&lt;p&gt;Most freelancers processing 50–100 transactions per month save 8–12 hours monthly by switching to AI-powered CSV import. The AI detects column formats automatically — no pre-cleaning, no reformatting. You drag and drop the file and the system handles the rest: dates, amounts, currencies, descriptions, categories, and client matching.&lt;/p&gt;

&lt;h3&gt;
  
  
  I work with clients in the US, UK, and Europe. Can it handle multiple currencies in one file or screenshot?
&lt;/h3&gt;

&lt;p&gt;Yes. The AI detects currency symbols (€, $, £, ¥) per individual transaction, not just per file. A bank statement showing $10.46 for Cloudflare, €7.89 for Tello, and £15.00 for a UK contractor is parsed with each amount preserving its original currency. All transactions are also converted to your configured base currency for dashboard totals and tax reporting.&lt;/p&gt;

&lt;h3&gt;
  
  
  I lose track of which client paid what. Does it help with client matching?
&lt;/h3&gt;

&lt;p&gt;Yes. When you import transactions or recognize screenshots, the AI extracts sender and merchant names and automatically matches them to existing clients in your database. It can also auto-create new client profiles when it detects a new name. Every transaction is linked to a client, giving you a complete payment history per client.&lt;/p&gt;

&lt;h3&gt;
  
  
  My invoices get ignored and I hate chasing payments. What does the reminder system do?
&lt;/h3&gt;

&lt;p&gt;Once an invoice is sent, the system tracks its due date. If it becomes overdue, automated reminders are sent on a schedule. The tone escalates: friendly in the first week (assuming they forgot), professional in weeks 2–3, and firm after 21 days. You can choose between friendly, professional, and urgent tones. Each reminder is AI-generated and personalized with the client's name, invoice number, and amount.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is my financial data secure?
&lt;/h3&gt;

&lt;p&gt;Yes. All data is encrypted in transit (SSL) and at rest. Authentication is handled by Clerk with production-grade security. The database is hosted on Supabase. You can delete your account at any time — your data is retained for 90 days (allowing you to change your mind), then permanently deleted. See our &lt;a href="https://www.tallyassistant.com/privacy" rel="noopener noreferrer"&gt;Privacy Policy&lt;/a&gt; for full details.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if I enter the wrong PayPal email for receiving payments?
&lt;/h3&gt;

&lt;p&gt;The app validates email format when you save settings, and a warning badge appears next to the PayPal button on invoices. You are responsible for ensuring your payment details are correct — see our &lt;a href="https://www.tallyassistant.com/privacy" rel="noopener noreferrer"&gt;Terms of Service&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The best time to automate your bookkeeping was when you started freelancing. The second best time is today. &lt;a href="https://www.tallyassistant.com" rel="noopener noreferrer"&gt;Try Tally Assistant free →&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aiaccounting</category>
      <category>paymentreminders</category>
      <category>bookkeeping</category>
    </item>
    <item>
      <title>How I Built an AI Bookkeeping SaaS as a Solo Developer (And What I'd Do Differently)</title>
      <dc:creator>Dominic li</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:56:59 +0000</pubDate>
      <link>https://dev.to/tallyassistant/how-i-built-an-ai-bookkeeping-saas-as-a-solo-developer-and-what-id-do-differently-je9</link>
      <guid>https://dev.to/tallyassistant/how-i-built-an-ai-bookkeeping-saas-as-a-solo-developer-and-what-id-do-differently-je9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Got laid off from my dev job. Built an &lt;a href="https://tallyassistant.com/features/ai-invoice-generator" rel="noopener noreferrer"&gt;AI invoicing for freelancers&lt;/a&gt; tool plus full bookkeeping in 4 months. Tech stack: Next.js 16, Prisma, OpenAI, Clerk, Inngest. Launched on Product Hunt. Here's the architecture, the mistakes, and the one decision that saved me months.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Backstory
&lt;/h2&gt;

&lt;p&gt;I'm Dominic, a full-stack developer from Chengdu, China 🇨🇳. I spent years freelancing for international clients before taking a full-time programming job. Then I got laid off.&lt;/p&gt;

&lt;p&gt;Instead of job hunting immediately, I decided to solve the problem that annoyed me most during my freelance years: &lt;strong&gt;bookkeeping.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every month, I'd download CSVs from Stripe, PayPal, Wise, and my Chinese bank — each in a completely different format. I'd spend hours reformatting dates, converting European commas, matching currencies, and manually creating invoices. Then I'd awkwardly chase clients who were late on payments.&lt;/p&gt;

&lt;p&gt;I looked at existing tools. QuickBooks and Xero felt like they were built for accountants, not freelancers. They expected clean, standardized data. Real freelancer data is messy — different column headers, different date formats, different languages.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Tally Assistant&lt;/strong&gt; — an AI bookkeeping tool that accepts whatever you throw at it and figures out the rest. The centerpiece is &lt;a href="https://tallyassistant.com/features/ai-invoice-generator" rel="noopener noreferrer"&gt;AI invoicing for freelancers&lt;/a&gt; — describe your work in one sentence and the AI builds the invoice with line items, tax, and a PayPal payment link in under 60 seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech Stack (And Why I Chose Each Piece)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Next.js 16 (App Router)
&lt;/h3&gt;

&lt;p&gt;I picked Next.js because I wanted SSR for SEO and the App Router for clean file-based routing. The landing page, blog, features pages, comparison pages — all statically generated at build time. Zero client-side JS on the marketing pages means fast Core Web Vitals and happy Google rankings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I got right:&lt;/strong&gt; Static generation for all 60+ SEO pages. sitemap auto-generates from content files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd change:&lt;/strong&gt; I'd set up ISR (Incremental Static Regeneration) sooner for the blog page so I don't need a full redeploy for every new post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prisma + PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Prisma's type-safe queries are a superpower for solo devs. You change the schema, run &lt;code&gt;prisma migrate dev&lt;/code&gt;, and TypeScript tells you everywhere that broke. No silent runtime errors from missing columns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One thing that saved me:&lt;/strong&gt; Using &lt;code&gt;prisma generate&lt;/code&gt; in the &lt;code&gt;postinstall&lt;/code&gt; script so Vercel always has the latest client generated at deploy time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clerk for Auth
&lt;/h3&gt;

&lt;p&gt;I didn't want to build auth from scratch — it's boring, security-critical, and adds zero product value. Clerk gave me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign-up/sign-in with Google, GitHub, and email&lt;/li&gt;
&lt;li&gt;Social login in 10 lines of code&lt;/li&gt;
&lt;li&gt;Webhook-based user sync to my Prisma database&lt;/li&gt;
&lt;li&gt;Zero maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The webhook pattern is worth explaining because it's easy to get wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Clerk webhook → creates or updates user in Prisma&lt;/span&gt;
&lt;span class="c1"&gt;// Runs on user creation, update, and deletion&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// verify Clerk signature&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user.created&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clerkId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email_addresses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;email_address&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  OpenAI — The Core Engine
&lt;/h3&gt;

&lt;p&gt;The AI does four things, each using a different prompting strategy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. CSV parsing:&lt;/strong&gt; I send the first 20 rows of the CSV as raw text, and GPT-4o returns a JSON map of column types with date format detection and currency identification. The key insight: I don't ask the AI to parse every row — I ask it to &lt;em&gt;describe the schema&lt;/em&gt;, then use deterministic code to parse the rest. This is faster, cheaper, and more reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Receipt OCR:&lt;/strong&gt; I use GPT-4V (vision) to read payment screenshots. The prompt explicitly asks for structured JSON output with merchant, amount, currency, and date fields. Multiple transactions in one image are detected by asking the model to return an array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;a href="https://tallyassistant.com/features/ai-invoice-generator" rel="noopener noreferrer"&gt;AI invoicing for freelancers&lt;/a&gt;:&lt;/strong&gt; Natural language → structured invoice. Type "Logo design $300, landing page $700 for Acme Corp, 6% VAT" and the AI extracts line items, matches the client, calculates tax, and generates a professional PDF with a PayPal payment link. The prompt converts free-text descriptions into structured invoice data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Finance chat assistant:&lt;/strong&gt; RAG-style — the user asks a question, I query their financial data from Prisma, then send the results + question to the model for summarization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biggest AI lesson:&lt;/strong&gt; The quality of your prompt matters more than the model version. I spent more time iterating on prompt design than on any other part of the AI pipeline. A well-structured system prompt with explicit output format instructions beats a bigger model with a vague prompt every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inngest for Background Jobs
&lt;/h3&gt;

&lt;p&gt;I needed two cron jobs: daily overdue invoice checking and sending reminder emails. Inngest handles both with step functions — each step is individually retryable and visible in the dashboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkOverdueInvoices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inngest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check-overdue-invoices&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TZ=America/New_York 0 8 * * *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;overdue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;find-overdue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SENT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inv&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;overdue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`send-reminder-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// AI-generated reminder email via Resend&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resend for Email
&lt;/h3&gt;

&lt;p&gt;Transactional email for invoices and payment reminders. Simple REST API, no SMTP config, excellent deliverability. One gotcha: you need to verify your domain in Resend before sending from &lt;code&gt;@yourdomain.com&lt;/code&gt; addresses — I learned this the hard way when my first batch of reminder emails silently failed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The SEO Bet That Paid Off
&lt;/h2&gt;

&lt;p&gt;I knew ranking for "Tally Assistant" wouldn't be enough — nobody searches for a product they don't know exists. So I built &lt;strong&gt;60+ static landing pages&lt;/strong&gt; targeting specific search queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;11 feature pages&lt;/strong&gt; targeting "&lt;a href="https://tallyassistant.com/features/ai-invoice-generator" rel="noopener noreferrer"&gt;AI invoicing for freelancers&lt;/a&gt;," "receipt scanner," "CSV import"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9 industry pages&lt;/strong&gt; for "bookkeeping for Shopify sellers," "bookkeeping for photographers"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 comparison pages&lt;/strong&gt; for "QuickBooks alternative," "Wave alternative"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15 glossary terms&lt;/strong&gt; for "what is accounts receivable," "invoice definition"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 in-depth guides&lt;/strong&gt; and &lt;strong&gt;6 free template pages&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every page uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON-LD structured data (FAQPage, Article, DefinedTerm schemas)&lt;/li&gt;
&lt;li&gt;Semantic HTML with proper heading hierarchy&lt;/li&gt;
&lt;li&gt;Internal linking between related content&lt;/li&gt;
&lt;li&gt;Meta descriptions written as search snippets, not afterthoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This compound SEO strategy cost me about 2 weeks of writing and is already generating organic traffic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three Mistakes I Made (So You Don't Have To)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. I built features nobody asked for
&lt;/h3&gt;

&lt;p&gt;I spent 3 weeks on a PDF receipt designer with drag-and-drop logo placement and custom color pickers. Beautiful. Useless. Nobody asked for it. When I finally talked to actual freelancers, they said: "Just make the CSV import work with my bank." I deleted the designer and spent that time on universal CSV parsing instead — which became the #1 feature users mention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Talk to users before building. I now post on Reddit r/freelance asking for feedback on every feature before writing code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. I launched too quietly
&lt;/h3&gt;

&lt;p&gt;I spent 4 months building and 0 minutes thinking about distribution. My first launch was tweeting "I built a thing" to my 12 followers. Crickets.&lt;/p&gt;

&lt;p&gt;What actually worked: Product Hunt (scheduled for a Tuesday midnight PST), Reddit posts asking for feedback (not promoting), X replies to people complaining about bookkeeping (offering help, not links), and these SEO pages that keep bringing traffic regardless of whether I'm posting that day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Distribution isn't an afterthought. Budget 50% of your time for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. I hardcoded USD as the default currency
&lt;/h3&gt;

&lt;p&gt;I built the entire multi-currency system but defaulted the base currency to USD in the reporting. A user in Germany asked: "Why is everything in dollars? I'm in Berlin." Embarrassing but easy fix — now the base currency is whatever the user configures in settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Don't hardcode assumptions about your users. I'm in China, my users are everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Direct integrations with Stripe, PayPal, and Wise APIs (currently CSV-based)&lt;/li&gt;
&lt;li&gt;iOS/Android companion app for receipt scanning&lt;/li&gt;
&lt;li&gt;Open sourcing the CSV parser (it's the part I'm proudest of)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It or Ask Me Anything
&lt;/h2&gt;

&lt;p&gt;The product is free during launch: &lt;strong&gt;&lt;a href="https://tallyassistant.com" rel="noopener noreferrer"&gt;tallyassistant.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building a SaaS as a solo dev — or thinking about it — ask me anything in the comments. I'll respond to every question. Especially happy to talk about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompt engineering for structured data extraction&lt;/li&gt;
&lt;li&gt;Prisma schema design for multi-tenant SaaS&lt;/li&gt;
&lt;li&gt;SEO strategy for new products&lt;/li&gt;
&lt;li&gt;The actual economics of a solo SaaS (costs, revenue, burn rate)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built in Chengdu, China 🐼 · Next.js + Prisma + OpenAI + Clerk + Inngest + Resend&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
