Building Catspense - From Idea to Architecture
Just one day after publishing my first blog post, I'm already diving headfirst into my next project. Meet Catspense - a zen-inspired, open-source expense tracker that I'm building with community contribution in mind.
The Vision: More Than Just Another Expense Tracker
Let me be honest - there are tons of expense trackers out there. But here's what I want to build differently:
Plugin-First Architecture: Instead of trying to support every bank and financial service myself, I'm building a system where developers can easily create email parser plugins for their local banks. Imagine having parsers for Jenius, Mandiri, Wise, and eventually banks from every country - all community-contributed.
Built for Open Source: This isn't just about building something for myself. I want Catspense to become the go-to platform where developers worldwide can contribute and benefit from each other's work.
International by Design: Starting with Indonesian banks (since that's what I use), but architected to handle any currency, any country, any banking system.
Why "Catspense"?
Cat + Expense = Catspense. It's playful enough to be memorable but professional enough for actual use. Plus, who doesn't like a subtle cat theme? š±
The tagline: "Smart expense tracking with a purr-fect touch"
Tech Stack Decisions
After researching and considering various options, here's what I've settled on:
Monorepo Architecture
- pnpm workspaces for package management
- Turborepo for build orchestration
- Clean separation between apps, packages, and plugins
Frontend Stack
- Next.js 15 with App Router for the web app
- Tamagui for the design system (planning mobile later)
- TypeScript throughout (non-negotiable for me)
- Tailwind CSS for utility-first styling
Backend & Data
- tRPC for type-safe APIs
- Supabase for database and auth
- Zod for validation schemas
The Plugin System Architecture
This is the core innovation I'm most excited about. Here's how it works:
interface EmailParser {
name: string;
version: string;
parseEmail: (emailContent: string) => Transaction[];
validateEmail: (emailContent: string) => boolean;
}
Each plugin is a self-contained package that knows how to:
- Identify if an email is from their target bank
- Extract transaction data from that email
- Return standardized transaction objects
Planned Official Plugins
- @catspense/plugin-jenius - Jenius SMBC email parser (my primary bank)
- @catspense/plugin-mandiri - Mandiri bank emails (my secondary bank)
- @catspense/plugin-template - Boilerplate for new parsers
I'm starting with these two because they're the banks I actually use daily. Once the system is proven with real data I have access to, I can open source it and let the community add parsers for banks worldwide - including international services like Wise.
Repository Structure
I'm going with a monorepo structure that looks like this:
catspense/
āāā apps/
ā āāā web/ # Next.js web app
ā āāā mobile/ # React Native (future)
āāā packages/
ā āāā ui/ # Tamagui design system
ā āāā shared/ # Business logic
ā āāā database/ # Supabase schemas
ā āāā plugin-system/ # Core plugin architecture
ā āāā plugins/ # Official email parsers
ā āāā config/ # Shared configurations
āāā docs/ # Documentation
āāā [standard files]
Multi-Currency Support
Since I'm building this for international use, multi-currency support is built into the foundation:
- IDR (Indonesian Rupiah) - my primary currency
- USD, SGD, MYR - common regional currencies
- Extensible system for adding more currencies
- Proper formatting and display for each currency
What's Next?
Today I'm focusing on:
- Setting up the monorepo structure - Getting pnpm workspaces and Turborepo configured
- Building the plugin system foundation - Core interfaces and registration system
- Creating the design system - Tamagui setup with the Zen-inspired theme
- Initial web app scaffold - Basic Next.js setup with routing
Tomorrow I'll start on:
- First email parser plugin (probably Jenius since that's my main bank)
- Transaction dashboard UI
- Plugin management interface
Tech Stack Deep Dive
Let me walk you through why I chose each part of this stack:
Monorepo with pnpm + Turborepo
Why monorepo? With a plugin architecture, I need to manage multiple related packages that share dependencies and types. A monorepo keeps everything in sync and makes development much smoother.
Why pnpm over npm/yarn? Faster installs, better disk space efficiency, and stricter dependency resolution. Since I'm building for open source contributors, I want the setup process to be as fast as possible.
Why Turborepo? Incremental builds and smart caching. When I change the core plugin system, I only want to rebuild affected packages, not everything.
Next.js 15 with App Router
Why Next.js? I need server-side rendering for better SEO (important for open source project discoverability), and the App Router gives me a clean way to organize the dashboard, plugin management, and documentation pages.
Why not Vite/React SPA? I want the marketing pages and documentation to load fast and be SEO-friendly. Plus, tRPC integrates beautifully with Next.js API routes.
Tamagui for Design System
Why Tamagui over Tailwind components? Planning for mobile later. Tamagui gives me React Native compatibility out of the box, so I can share components between web and mobile apps.
Why not just Tailwind? I love Tailwind, but I want a more opinionated design system with consistent theming and built-in dark mode. Tamagui gives me that structure.
tRPC + Supabase
Why tRPC? End-to-end type safety from database to frontend. When I change a database schema, TypeScript will catch breaking changes across the entire stack.
Why Supabase over traditional backend? I want to focus on the plugin system, not building auth and database infrastructure. Supabase gives me PostgreSQL, real-time subscriptions, and auth out of the box.
Why not Prisma + custom backend? Time to MVP. Supabase's auto-generated types and real-time features mean I can build faster and focus on what makes Catspense unique.
TypeScript Everywhere
Non-negotiable. With a plugin system, type safety is critical. Plugin developers need clear interfaces, and I need confidence that plugins won't break the core system.
Open Source Strategy
While the repository is currently private as I build the initial MVP, I'm designing everything with open source in mind from day one. The architecture, documentation structure, and plugin system are all built to welcome contributors.
Once I have a working proof of concept with my two bank parsers functioning reliably, I'll open source the entire project with:
- Clear contribution guidelines
- Plugin development documentation
- Issue templates for bug reports and feature requests
- Welcoming community guidelines
Why wait for MVP? I want contributors to see a working system they can build upon, rather than empty folders and TODO comments. First impressions matter in open source - I'd rather launch with something functional that demonstrates the vision.
Why This Approach Excites Me
Building Catspense as an open-source, plugin-based system means:
- Collective Impact: Every parser someone contributes helps users worldwide
- Local Expertise: Developers who use specific banks can build the best parsers for them
- Sustainable Growth: The community can maintain and improve parsers over time
- Learning Opportunity: Great way to explore monorepo architecture, plugin systems, and open source maintainership
Following Along
I'll be documenting everything as I build - the wins, the roadblocks, the "why did I think this was a good idea?" moments. If you're interested in monorepo architecture, plugin systems, or just want to see how an open-source project grows from zero, stick around!
The repository is currently private while I work on getting a solid proof of concept together. Once I have the core plugin system working and at least one email parser functional, I'll open source it for the community.
Next post will probably be about setting up the initial monorepo structure and getting the first plugin working. Or maybe about the inevitable configuration hell I'm about to dive into š
Ready to build something with a purr-fect touch! š
This is post #2 in my development journey. I'll share the GitHub link once the POC is ready - stay tuned for updates!