TechnologyApril 5, 2024 • 13 min read

Behind the Scenes: Building FinKitty (A Developer's Journey)

Go behind the scenes of building FinKitty, from the initial idea to launching a financial management platform. Learn about our technology choices, challenges, and lessons learned.

Alex Thompson

Alex Thompson

Co-founder and CTO of FinKitty, full-stack developer with 8+ years building fintech applications

Developer working late night on code with multiple monitors showing FinKitty interface

The journey from concept to launch: building a fintech platform from the ground up

"We should build something to help small businesses understand their cash flow better."

That casual conversation over coffee in early 2023 led to 14 months of intense development, countless late nights, and the creation of FinKitty. As the technical co-founder, I want to share the real story behind building a financial management platform from scratch—the wins, the failures, and everything in between.

This isn't a polished marketing story. It's an honest account of what it takes to build fintech software in 2024, complete with the technical decisions, regulatory hurdles, and 3 AM debugging sessions that don't make it into the press releases.

The Spark: Why FinKitty Exists

The Problem We Witnessed

My co-founder Sarah ran a marketing agency and constantly struggled with cash flow visibility. Despite being profitable, she never knew if she could afford to hire someone, invest in equipment, or take on a big project. She spent hours every week updating spreadsheets and still felt like she was flying blind.

After talking to dozens of other small business owners, we realized this wasn't unique. The existing solutions were either:

  • Too expensive (£200+/month enterprise software)
  • Too complex (designed for CFOs, not business owners)
  • Too basic (glorified expense trackers)
  • Too disconnected (required manual data entry)

We saw an opportunity to build something specifically for small businesses that would be powerful yet accessible, automated yet affordable.

The Initial Vision

Our original concept was deceptively simple:

  1. Connect to bank accounts automatically
  2. Categorize transactions intelligently
  3. Show real-time cash flow
  4. Predict future cash positions
  5. Help with scenario planning

Simple in concept, incredibly complex in execution.

Choosing the Technology Stack

Frontend: Nuxt 3 + Vue.js

Why We Chose It:

  • Developer experience: Vue's learning curve is gentler than React
  • Performance: Nuxt 3's hybrid rendering gives us the best of SSR and SPA
  • SEO: Critical for a business targeting small business owners through content
  • TypeScript support: Essential for financial software where type safety matters

The Reality: Nuxt 3 was still relatively new when we started, which meant dealing with:

  • Limited third-party modules
  • Frequent breaking changes in early versions
  • Having to build many utilities from scratch

Would we choose it again? Absolutely. The developer experience and performance gains have been worth the early adoption pains.

Backend: Node.js + Supabase

Why We Chose Supabase:

  • Rapid development: Real-time subscriptions out of the box
  • Security: Row Level Security (RLS) perfect for multi-tenant financial data
  • Scaling: PostgreSQL can handle our current and projected data volumes
  • Cost: Significantly cheaper than AWS for our use case

The Financial Data Challenge: Financial data has unique requirements:

  • Precision: No floating-point math (we use decimal types for all money)
  • Immutability: Transactions should never be modified, only appended
  • Audit trails: Every change needs to be tracked for regulatory compliance
  • Performance: Real-time updates across thousands of transactions

Our Schema Design:

-- Core tables designed for financial data integrity
CREATE TABLE bank_accounts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  institution_name TEXT NOT NULL,
  account_type TEXT NOT NULL,
  balance DECIMAL(12,2) NOT NULL,
  currency CHAR(3) NOT NULL DEFAULT 'GBP',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE bank_transactions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  account_id UUID REFERENCES bank_accounts(id),
  amount DECIMAL(12,2) NOT NULL,
  description TEXT NOT NULL,
  category TEXT,
  transaction_date DATE NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Open Banking Integration: GoCardless API

The Challenge: Open Banking in the UK requires PSD2 compliance, which means:

  • Regulated authorization: We needed FCA approval as a Third Party Provider
  • Secure authentication: OAuth 2.0 flows with bank-grade security
  • Real-time data: Transaction updates within minutes of occurrence
  • Multi-bank support: 500+ institutions with different API quirks

Why GoCardless:

  • Compliance handled: They deal with FCA regulation and bank relationships
  • Unified API: One interface for 500+ banks
  • Reliability: 99.9% uptime with automatic failover
  • Support: Actual humans who understand fintech challenges

Implementation Challenges:

// Bank connection flow - looks simple, incredibly complex under the hood
async function connectBankAccount(userId, institutionId) {
  try {
    // Create requisition with GoCardless
    const requisition = await gocardless.createRequisition({
      institution_id: institutionId,
      redirect: `${process.env.APP_URL}/auth/callback`,
      user_language: 'EN'
    });
    
    // This simple call handles:
    // - OAuth 2.0 flow with the bank
    // - Strong Customer Authentication (SCA)
    // - Token management and refresh
    // - Consent management
    return requisition;
  } catch (error) {
    // Banks return different error formats
    // Some return HTTP 500 for user errors
    // Error handling is 50% of the code
    throw new BankConnectionError(error);
  }
}

AI/ML: Python + scikit-learn

The Forecasting Challenge: Predicting cash flow accurately requires:

  • Seasonal pattern detection: Most businesses have cycles
  • Trend analysis: Growth, decline, or stability patterns
  • Outlier handling: One-time events shouldn't skew predictions
  • Confidence intervals: Users need to know prediction reliability

Our Approach:

# Simplified version of our forecasting algorithm
def forecast_cash_flow(transactions, days_ahead=90):
    # Convert to time series
    ts = create_time_series(transactions)
    
    # Seasonal decomposition
    seasonal = seasonal_decompose(ts, model='additive')
    
    # Fit polynomial regression with seasonal components
    model = make_pipeline(
        PolynomialFeatures(degree=2),
        LinearRegression()
    )
    
    # Add Fourier features for seasonality
    X_seasonal = add_fourier_features(X, period=365.25/12)
    
    model.fit(X_seasonal, y)
    
    # Generate predictions with confidence intervals
    predictions = model.predict(future_X)
    confidence = calculate_confidence_intervals(model, future_X)
    
    return predictions, confidence

Accuracy Results:

  • 30-day forecasts: 92% accuracy on average
  • 90-day forecasts: 87% accuracy on average
  • Seasonal businesses: 94% accuracy during stable periods

The Regulatory Journey

FCA Authorization Process

Timeline: 8 months from application to approval

Requirements:

  • Business plan: 47-page document detailing everything
  • Risk assessment: Comprehensive analysis of all possible risks
  • Compliance procedures: Detailed processes for data protection, fraud prevention, AML
  • Technical documentation: Security assessments, architecture reviews
  • Financial projections: 3-year forecasts with stress testing

The Reality: The FCA approval process is thorough but fair. They're not trying to block innovation—they're ensuring consumer protection. The hardest part was documenting everything we did instinctively.

GDPR Compliance

Data Minimization: We only request and store data necessary for our service:

  • Transaction data for categorization and forecasting
  • Account balances for cash flow calculation
  • No personal identifiable information beyond what's required

User Rights:

  • Data export: Complete data download in JSON format
  • Account deletion: Permanent removal within 30 days
  • Consent management: Granular control over data usage

Technical Implementation:

// GDPR deletion process
async function deleteUserData(userId: string) {
  // Anonymize rather than delete financial records
  // (required for audit trails)
  await db.transaction(async (trx) => {
    await trx('bank_transactions')
      .where('user_id', userId)
      .update({
        description: 'ANONYMIZED',
        user_id: null,
        anonymized_at: new Date()
      });
    
    // Actually delete user profile and auth data
    await trx('user_profiles').where('id', userId).del();
    await supabase.auth.admin.deleteUser(userId);
  });
}

The Design Philosophy: Retro-Modern Fintech

Why the Pixelated Aesthetic?

Financial software is notoriously boring and intimidating. We wanted to create something that felt:

  • Approachable: Less intimidating than traditional banking interfaces
  • Memorable: Standing out in a sea of blue and white fintech apps
  • Trustworthy: Retro aesthetics suggest stability and reliability

The Technical Challenge

Making pixelated designs work in modern browsers required custom CSS:

.pixel-perfect {
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.pixel-button {
  box-shadow: 4px 4px 0px #391E1B;
  transition: all 0.1s ease;
}

.pixel-button:hover {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0px #391E1B;
}

User Testing Results

Our design philosophy tested well:

  • First impressions: 87% positive reaction to visual design
  • Approachability: Users felt less intimidated by financial features
  • Memorability: 94% brand recall after one week
  • Trust: Surprisingly, the playful design increased trust scores

Major Technical Challenges

Challenge 1: Real-Time Data Synchronization

The Problem: Users expect bank data to update immediately, but Open Banking APIs have rate limits and varying update frequencies.

Our Solution:

  • Intelligent polling: Different update frequencies based on account activity
  • Webhook integration: Real-time updates where supported
  • User feedback: Clear indicators of last update time
  • Background sync: Updates happen transparently
// Simplified sync strategy
async function syncBankAccount(accountId: string) {
  const account = await getAccountById(accountId);
  const timeSinceLastSync = Date.now() - account.lastSynced;
  
  // High-activity accounts sync more frequently
  const syncInterval = account.transactionCount > 100 
    ? 2 * 60 * 1000  // 2 minutes
    : 15 * 60 * 1000; // 15 minutes
  
  if (timeSinceLastSync > syncInterval) {
    await fetchLatestTransactions(accountId);
  }
}

Challenge 2: Transaction Categorization

The Problem: Bank transaction descriptions are messy and inconsistent:

  • "PAYPAL *AMAZONGB LUX" (Amazon purchase via PayPal)
  • "TFL TRAVEL CH TFL.GOV.UK" (London Transport)
  • "FASTER PMTS RECEIVED FROM ACME LTD" (Client payment)

Our Solution: Machine learning model trained on 100,000+ manually categorized transactions:

# Transaction categorization pipeline
def categorize_transaction(description, amount, merchant_name=None):
    # Clean and normalize description
    clean_desc = clean_description(description)
    
    # Extract features
    features = {
        'description_tokens': tokenize(clean_desc),
        'amount_bucket': get_amount_bucket(amount),
        'merchant_category': get_merchant_category(merchant_name),
        'day_of_week': get_day_of_week(),
        'is_recurring': is_recurring_payment(description, amount)
    }
    
    # Predict category
    category = model.predict(features)
    confidence = model.predict_proba(features).max()
    
    return category, confidence

Results:

  • 95% accuracy on common transaction types
  • 87% accuracy on unusual or first-time transactions
  • Continuous learning from user corrections

Challenge 3: Performance at Scale

The Problem: Financial queries can be expensive:

  • Calculating running balances across thousands of transactions
  • Real-time aggregations for dashboard views
  • Complex forecasting calculations

Our Solutions:

Database Optimization:

-- Materialized views for expensive calculations
CREATE MATERIALIZED VIEW monthly_cash_flow AS
SELECT 
  account_id,
  DATE_TRUNC('month', transaction_date) as month,
  SUM(amount) as net_flow,
  SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as inflow,
  SUM(CASE WHEN amount < 0 THEN amount ELSE 0 END) as outflow
FROM bank_transactions
GROUP BY account_id, DATE_TRUNC('month', transaction_date);

-- Refresh automatically
SELECT cron.schedule('refresh-cash-flow', '0 1 * * *', 
  'REFRESH MATERIALIZED VIEW monthly_cash_flow;');

Caching Strategy:

  • Redis: Hot data (current balances, recent transactions)
  • CDN: Static assets and API responses
  • Application cache: Expensive calculations cached for 15 minutes

Security: Protecting Financial Data

Encryption at Every Layer

In Transit:

  • TLS 1.3 for all communications
  • Certificate pinning in mobile apps
  • API request signing to prevent tampering

At Rest:

  • AES-256 encryption for sensitive database fields
  • Separate encryption keys per user
  • Regular key rotation

In Memory:

  • Sensitive data cleared immediately after use
  • No financial data in application logs
  • Secure memory allocation for cryptographic operations

Access Controls

Row Level Security (RLS):

-- Users can only see their own data
CREATE POLICY user_data_isolation ON bank_transactions
  FOR ALL USING (
    account_id IN (
      SELECT id FROM bank_accounts 
      WHERE user_id = auth.uid()
    )
  );

API Authentication:

  • JWT tokens with short expiration
  • Refresh token rotation
  • Rate limiting per user and IP
  • Anomaly detection for unusual access patterns

Audit Logging

Every action is logged for security and compliance:

async function auditLog(userId: string, action: string, details: any) {
  await db('audit_logs').insert({
    user_id: userId,
    action,
    details: JSON.stringify(details),
    ip_address: getClientIP(),
    user_agent: getUserAgent(),
    timestamp: new Date()
  });
}

Lessons Learned

Technical Lessons

1. Start with Security Don't bolt on security later. Design it in from day one. Financial data requires a security-first mindset throughout development.

2. Embrace Third-Party Services We initially tried to build everything ourselves. Using services like GoCardless, Supabase, and Stripe let us focus on our core value proposition.

3. Plan for Scale Early Database design decisions made on day one still affect us today. Think about how your schema will perform with 10x, 100x more data.

4. Testing is Critical Financial software bugs aren't just annoying—they're dangerous. We have:

  • Unit tests for all business logic
  • Integration tests for external APIs
  • End-to-end tests for critical user flows
  • Automated security scanning

Business Lessons

1. Regulatory Compliance Takes Time Factor regulatory approval into your timeline. It's not optional for fintech, and it can't be rushed.

2. User Research Never Ends Our assumptions about what users wanted were often wrong. Regular user interviews and testing are essential.

3. Design Matters More Than You Think In fintech especially, users need to trust your product. Good design builds trust.

4. Focus on Core Value We've resisted the urge to add every feature users request. Staying focused on cash flow management has been key to our success.

The Numbers: 14 Months Later

Technical Metrics

  • Lines of code: ~47,000 (including tests)
  • API endpoints: 127
  • Database tables: 34
  • External integrations: 8
  • Automated tests: 1,247
  • Deployment time: 3 minutes
  • Average response time: 180ms
  • Uptime: 99.94%

Business Metrics

  • Active users: 1,200+
  • Connected bank accounts: 3,800+
  • Transactions processed: 2.1 million+
  • Forecasts generated: 45,000+
  • Customer satisfaction: 4.7/5

Team Growth

  • Started with: 2 co-founders
  • Current team: 8 people
  • Roles added: Frontend dev, designer, customer success, compliance officer
  • Remote work: 100% distributed team

What's Next: The Roadmap

Short-term (Next 6 Months)

  • Mobile app: Native iOS and Android apps
  • Advanced reporting: Profit & loss, cash flow statements
  • Team features: Multi-user accounts for growing businesses
  • API access: Let power users export their data

Medium-term (6-18 Months)

  • AI insights: Proactive recommendations for cash flow optimization
  • Industry benchmarking: Compare your metrics to similar businesses
  • Lending integration: Connect cash flow data to financing options
  • Accountant portal: Tools for accountants to help their clients

Long-term (18+ Months)

  • International expansion: Support for US and EU markets
  • Advanced AI: Predictive analytics for business planning
  • Marketplace: Connect businesses with relevant financial services
  • Enterprise features: Advanced controls for larger businesses

For Fellow Developers

Open Source Contributions

We believe in giving back to the community. We've open-sourced several components:

  • Bank API wrapper: Simplified GoCardless integration
  • Financial calculations library: Accurate money math in JavaScript
  • Nuxt security headers: OWASP-compliant security headers for Nuxt 3

Tech Stack Recommendations

For Fintech Startups:

  • Don't build auth yourself: Use Auth0, Supabase Auth, or Firebase Auth
  • Use decimal types: Never use floating-point for money
  • Invest in monitoring: Financial bugs are expensive
  • Plan for compliance: GDPR, PSD2, and other regulations from day one

For Any Startup:

  • Choose boring technology: Your innovation should be in your product, not your tech stack
  • Automate deployment: You'll deploy hundreds of times
  • Monitor everything: You can't fix what you can't measure
  • Write tests: Your future self will thank you

The Human Side

Work-Life Balance

Building a startup is intense, but burning out helps no one. Our strategies:

  • No work on Sundays: Everyone needs a complete break
  • Flexible hours: People have different peak productivity times
  • Regular breaks: The Pomodoro Technique works for teams too
  • Celebrate wins: Take time to acknowledge progress

Dealing with Setbacks

Not everything went smoothly:

  • GoCardless outage: Took down our service for 4 hours
  • Major bug: Incorrect balance calculations for 200+ users
  • Regulatory delay: FCA approval took 3 months longer than expected
  • Team conflicts: Disagreements about product direction

What helped:

  • Transparent communication: Keep everyone informed
  • Learn from mistakes: Every setback teaches something
  • Support each other: Building a startup is a team sport
  • Maintain perspective: Most problems aren't as bad as they initially seem

Building a Remote Team

We've been remote-first from day one:

What works:

  • Daily standups: 15 minutes, camera on, focus on blockers
  • Async communication: Not everything needs a meeting
  • Clear documentation: If it's not written down, it doesn't exist
  • Regular social time: Virtual coffee chats and game nights

What doesn't:

  • Long video calls: Zoom fatigue is real
  • Unclear responsibilities: Remote work requires clear ownership
  • No boundaries: Working from home can mean always working

Final Thoughts

Building FinKitty has been the most challenging and rewarding project of my career. We've created something that genuinely helps small business owners sleep better at night by taking the uncertainty out of cash flow management.

The technology stack, regulatory requirements, and design challenges were all solvable problems. The harder challenge has been building a product that people love and trust with their financial data.

We're still early in our journey. There are features to build, bugs to fix, and users to help. But seeing a small business owner check their cash flow dashboard and feel confident about their financial future makes every late night debugging session worth it.

For Aspiring Fintech Founders

Do:

  • Start with a real problem you've experienced personally
  • Talk to users constantly—your assumptions will be wrong
  • Plan for regulatory compliance from day one
  • Focus on trust and security above all else
  • Build a diverse team with different perspectives

Don't:

  • Underestimate the complexity of financial data
  • Try to build everything yourself
  • Ignore regulatory requirements
  • Compromise on security for speed
  • Assume you know what users want

Remember: Building fintech software is hard, but it's incredibly rewarding when you get it right. Focus on solving real problems for real people, and the technology will follow.


Interested in our technology or want to contribute? Check out our open source projects on GitHub or join our developer community.

Questions about our tech stack or building fintech software? Reach out to our team - we love talking with fellow developers about the challenges and solutions in financial technology.

🏷️ Tags

developmentstartup journeyfintechtechnology stackopen banking
Alex Thompson

About Alex Thompson

Co-founder and CTO of FinKitty, full-stack developer with 8+ years building fintech applications

📧 Enjoyed this post?

Get more cash flow tips and business insights delivered to your inbox.