Skip to content

Latest commit

 

History

History
234 lines (170 loc) · 7.48 KB

File metadata and controls

234 lines (170 loc) · 7.48 KB

Frontend Mentor - Personal Finance App Solution

This is a solution to the Personal Finance App challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.


Table of contents

💸 Personal Finance App

Next.js tRPC Supabase Clerk Drizzle ORM Tailwind CSS TypeScript


🗝️ Test user credentials

email: testAccount@test.com
password: testAccountApplication

✨ Features

  • Custom Authentication: Full sign-up and login flow using Clerk, including email verification and optional test data import during registration.
  • Dashboard: Displays latest transactions, current balance, income, and expenses.
  • Budgets: Create budget limits by category and automatically track expenses against your budgets.
  • Transactions: Add, edit, or delete transactions with icons, colors, and uploaded images.
  • Savings Pots: Allocate funds into pots and manage savings separately.
  • Recurring Payments: Manage recurring transactions with upcoming payment reminders.
  • Fully Type-Safe Backend: tRPC + TypeScript for end-to-end type safety.
  • Smooth UX: React Suspense, Error Boundaries, and Skeleton Loaders for better user experience.

🧱 Tech Stack

Layer Technology
Frontend Next.js 15, React 18, Tailwind CSS, Shadcn/UI
Backend tRPC, TypeScript
ORM Drizzle ORM
Database Supabase (PostgreSQL + Storage)
Auth Clerk
Deployment Vercel

⚙️ Architecture Highlights

  • tRPC provides type-safe client-server communication without REST or GraphQL overhead.
  • HydrateClient + prefetch() enables server-side data preloading and seamless hydration.
  • Suspense + Skeleton + ErrorBoundary improve perceived performance and robust error handling.
return (
  <Suspense fallback={<BalanceSectionSkeleton />}>
    <ErrorBoundary fallback={<p>Error loading data</p>}>
      <BalanceSectionSuspense />
    </ErrorBoundary>
  </Suspense>
);

📷 Screenshots

Desktop

desktop page preview

Tablet

tablet page preview

Mobile

mobile page preview


🔗 Links


🏫 What I Learned

A full-stack personal finance management application, allowing users to manage budgets, transactions, savings pots, and recurring payments. Built using Next.js 15 App Router, tRPC, Clerk, Supabase, Shadcn/UI, and Drizzle ORM.

Pages

  • Main Page — Shows overall balance and latest transactions.
  • Budget Page — Create budgets by category with spending limits; automatically updates as transactions are added.
  • Transaction Page — Full CRUD support for transactions with icons, colors, and image attachments.
  • Pots Page — Manage savings pots, add or withdraw funds with real-time balance updates.
  • Recurring Page — Track recurring transactions with upcoming due dates.

Application Structure

Pages utilize tRPC's prefetch() with HydrateClient for efficient SSR and hydration:

void trpc.pots.getMany.prefetch();
void trpc.balance.getOne.prefetch();
return (
  <HydrateClient>
    <HomeView />
  </HydrateClient>
);

Clerk

Custom sign-up/login with Clerk, including optional test data population on first registration.

Supabase

Supabase Storage is used to host user-uploaded transaction avatars.

tRPC

tRPC ensures fully type-safe client-server communication, streamlining API development and minimizing runtime errors.

Shadcn/UI

Shadcn/UI powered the component library, providing clean, reusable form and UI components.


📚 Useful Resources


👨‍💻 Author


🚀 Getting Started

Clone the repository

git clone https://github.com/kamiliano1/personal-invoice-application.git
cd personal-invoice-application

Install dependencies

pnpm install
# or
npm install
# or
yarn install

Configure environment variables

Create a .env.local file and add your credentials:

# Clerk Auth
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
CLERK_SIGNING_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/

# Database
DATABASE_URL=

# Supabase
SUPABASE_URL=
SUPABASE_URL_CONFIG=
SUPABASE_ANON_KEY=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=

Run development server

pnpm dev
# or
npm run dev
# or
yarn dev