TL;DR: Got laid off from my dev job. Built an AI invoicing for freelancers 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.
The Backstory
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.
Instead of job hunting immediately, I decided to solve the problem that annoyed me most during my freelance years: bookkeeping.
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.
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.
So I built Tally Assistant β an AI bookkeeping tool that accepts whatever you throw at it and figures out the rest. The centerpiece is AI invoicing for freelancers β 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.
The Tech Stack (And Why I Chose Each Piece)
Next.js 16 (App Router)
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.
What I got right: Static generation for all 60+ SEO pages. sitemap auto-generates from content files.
What I'd change: 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.
Prisma + PostgreSQL
Prisma's type-safe queries are a superpower for solo devs. You change the schema, run prisma migrate dev, and TypeScript tells you everywhere that broke. No silent runtime errors from missing columns.
One thing that saved me: Using prisma generate in the postinstall script so Vercel always has the latest client generated at deploy time.
Clerk for Auth
I didn't want to build auth from scratch β it's boring, security-critical, and adds zero product value. Clerk gave me:
- Sign-up/sign-in with Google, GitHub, and email
- Social login in 10 lines of code
- Webhook-based user sync to my Prisma database
- Zero maintenance
The webhook pattern is worth explaining because it's easy to get wrong:
// Clerk webhook β creates or updates user in Prisma
// Runs on user creation, update, and deletion
export async function POST(req: Request) {
const evt = await verifyWebhook(req) // verify Clerk signature
if (evt.type === "user.created") {
await prisma.user.create({
data: { clerkId: evt.data.id, email: evt.data.email_addresses[0]?.email_address },
})
}
}
OpenAI β The Core Engine
The AI does four things, each using a different prompting strategy:
1. CSV parsing: 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 describe the schema, then use deterministic code to parse the rest. This is faster, cheaper, and more reliable.
2. Receipt OCR: 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.
3. AI invoicing for freelancers: 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.
4. Finance chat assistant: RAG-style β the user asks a question, I query their financial data from Prisma, then send the results + question to the model for summarization.
Biggest AI lesson: 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.
Inngest for Background Jobs
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.
export const checkOverdueInvoices = inngest.createFunction(
{ id: "check-overdue-invoices", triggers: [{ cron: "TZ=America/New_York 0 8 * * *" }] },
async ({ step }) => {
const overdue = await step.run("find-overdue", async () => {
return prisma.invoice.findMany({ where: { status: "SENT", dueDate: { lt: new Date() } } })
})
for (const inv of overdue) {
await step.run(`send-reminder-${inv.id}`, async () => {
// AI-generated reminder email via Resend
})
}
}
)
Resend for Email
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 @yourdomain.com addresses β I learned this the hard way when my first batch of reminder emails silently failed.
The SEO Bet That Paid Off
I knew ranking for "Tally Assistant" wouldn't be enough β nobody searches for a product they don't know exists. So I built 60+ static landing pages targeting specific search queries:
- 11 feature pages targeting "AI invoicing for freelancers," "receipt scanner," "CSV import"
- 9 industry pages for "bookkeeping for Shopify sellers," "bookkeeping for photographers"
- 6 comparison pages for "QuickBooks alternative," "Wave alternative"
- 15 glossary terms for "what is accounts receivable," "invoice definition"
- 4 in-depth guides and 6 free template pages
Every page uses:
- JSON-LD structured data (FAQPage, Article, DefinedTerm schemas)
- Semantic HTML with proper heading hierarchy
- Internal linking between related content
- Meta descriptions written as search snippets, not afterthoughts
This compound SEO strategy cost me about 2 weeks of writing and is already generating organic traffic.
Three Mistakes I Made (So You Don't Have To)
1. I built features nobody asked for
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.
Lesson: Talk to users before building. I now post on Reddit r/freelance asking for feedback on every feature before writing code.
2. I launched too quietly
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.
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.
Lesson: Distribution isn't an afterthought. Budget 50% of your time for it.
3. I hardcoded USD as the default currency
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.
Lesson: Don't hardcode assumptions about your users. I'm in China, my users are everywhere.
What's Next
- Direct integrations with Stripe, PayPal, and Wise APIs (currently CSV-based)
- iOS/Android companion app for receipt scanning
- Open sourcing the CSV parser (it's the part I'm proudest of)
Try It or Ask Me Anything
The product is free during launch: tallyassistant.com
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:
- Prompt engineering for structured data extraction
- Prisma schema design for multi-tenant SaaS
- SEO strategy for new products
- The actual economics of a solo SaaS (costs, revenue, burn rate)
Built in Chengdu, China πΌ Β· Next.js + Prisma + OpenAI + Clerk + Inngest + Resend
Top comments (0)