Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 149 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,168 @@
# sv
# Sinking Funds Manager

Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
A gamified personal finance application built with SvelteKit to help users track spending and manage multiple savings goals through "sinking funds." The application provides clear visibility into where money goes each month and encourages better spending habits through gamification elements like progress achievements, streaks, and celebratory animations.

## Creating a project
## 🎯 What are Sinking Funds?

If you're seeing this, you've probably already done this step. Congrats!
Sinking funds are dedicated savings accounts for specific purposes or expenses. Instead of being surprised by irregular expenses like car repairs or annual subscriptions, you set aside money each month in advance. This application helps you:

```sh
# create a new project in the current directory
npx sv create
- **Track spending** across multiple categories/funds
- **Build up savings** through rollover of unspent balances
- **Stay motivated** with gamification features
- **Plan ahead** for both expected and unexpected expenses

# create a new project in my-app
npx sv create my-app
## ✨ Key Features

- **📁 Multiple Funds Management**: Create and manage multiple sinking funds with custom names, colors, and icons
- **💰 Flexible Allocations**: Set up monthly deposit rules using fixed amounts, percentages, or priority-based allocation
- **📊 Transaction Tracking**: Track expenses, income, and transfers between funds
- **🔄 Monthly Rollover**: Unspent balances automatically roll over to reward underspending
- **🎮 Gamification**: Earn badges for hitting milestones, maintain streaks, and level up your funds
- **🔒 Period Management**: Lock/unlock monthly periods to prevent accidental changes
- **📈 Reporting & Analytics**: View spending patterns and fund performance over time
- **🎨 Customizable Interface**: Choose from various color themes and icons for personalization

## 🛠️ Technology Stack

- **Frontend**: SvelteKit with TypeScript
- **UI Framework**: Skeleton UI components
- **Styling**: Tailwind CSS
- **Database**: SQLite with Prisma ORM
- **Development**: Vite, ESLint, Prettier

## 📋 Prerequisites

- Node.js 18 or later
- npm (comes with Node.js)

## 🚀 Getting Started

### 1. Clone and Install

```bash
git clone https://github.com/dylan-mccarthy/SinkingFundsDemo-CodingAgent.git
cd SinkingFundsDemo-CodingAgent
npm install
```

## Developing
### 2. Database Setup

Initialize the database with Prisma:

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
# Generate Prisma client
npx prisma generate

```sh
# Create database and run migrations
npx prisma migrate dev --name init

# (Optional) Open Prisma Studio to view the database
npx prisma studio
```

### 3. Development Server

Start the development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
# Or start and automatically open in browser
npm run dev -- --open
```

## Building
The application will be available at `http://localhost:5173`

## 🔧 Available Scripts

### Development

```bash
npm run dev # Start development server
npm run dev -- --open # Start dev server and open browser
```

### Building

```bash
npm run build # Build for production
npm run preview # Preview production build locally
```

### Code Quality

```bash
npm run check # Run Svelte/TypeScript checks
npm run check:watch # Run checks in watch mode
npm run lint # Run ESLint and Prettier checks
npm run format # Format code with Prettier
```

### Database Management

```bash
npx prisma studio # Open database browser
npx prisma migrate dev # Create and apply new migration
npx prisma migrate reset # Reset database (⚠️ destroys data)
npx prisma db push # Push schema changes without migration
```

To create a production version of your app:
## 📁 Project Structure

```sh
npm run build
```
src/
├── routes/ # SvelteKit pages and API routes
│ ├── +layout.svelte # Main application layout
│ ├── +page.svelte # Home/Dashboard page
│ ├── api/ # Backend API endpoints
│ ├── funds/ # Fund management pages
│ ├── transactions/ # Transaction tracking pages
│ ├── allocations/ # Monthly allocation setup
│ ├── transfers/ # Fund transfer functionality
│ └── periods/ # Period management
├── lib/ # Shared components and utilities
│ └── components/ # Reusable Svelte components
├── app.html # HTML template
├── app.css # Global styles
└── app.d.ts # TypeScript declarations

prisma/
├── schema.prisma # Database schema
└── migrations/ # Database migration files

static/ # Static assets (images, icons, etc.)
```

## 🎮 How to Use

1. **Create Your First Fund**: Start by creating a sinking fund for a specific purpose (e.g., "Emergency Fund", "Car Maintenance", "Vacation")

2. **Set Up Allocations**: Configure how much money should go into each fund monthly - either fixed amounts or percentages

3. **Track Transactions**: Log expenses against funds and add income when needed

4. **Monthly Process**: At month-end, the system rolls over unspent balances and applies your allocation rules

5. **Monitor Progress**: Watch your funds grow and unlock achievements as you hit savings milestones

## 🏗️ Development Status

This project is currently in active development. The core functionality is implemented but some features may still be in progress. Please refer to the issues for the current development status.

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes following the existing code style
4. Run the code quality checks: `npm run lint && npm run check`
5. Commit your changes (`git commit -m 'Add some amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

## 📄 License

This project is for demonstration purposes. Please check with the repository owner for licensing details.

You can preview the production build with `npm run preview`.
---

> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
**Happy Saving! 💰** Start building your financial future one fund at a time.
17 changes: 13 additions & 4 deletions src/lib/components/GamificationPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@
<div class="text-xs text-gray-600 dark:text-gray-400">Month Streak</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold text-blue-600 dark:text-blue-400">{gamificationData.badges.length}</div>
<div class="text-2xl font-bold text-blue-600 dark:text-blue-400">
{gamificationData.badges.length}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400">Badges Earned</div>
</div>
<div class="text-center">
Expand All @@ -149,8 +151,13 @@

<!-- Badges -->
{#if showBadges}
<div class="mt-4 border-t border-purple-200 dark:border-purple-600 pt-4" transition:fly={{ y: 20, duration: 300 }}>
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">🏆 Badges Earned</h4>
<div
class="mt-4 border-t border-purple-200 dark:border-purple-600 pt-4"
transition:fly={{ y: 20, duration: 300 }}
>
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">
🏆 Badges Earned
</h4>
{#if gamificationData.badges.length === 0}
<div class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
No badges earned yet. Keep saving to unlock achievements!
Expand All @@ -165,7 +172,9 @@
<div class="flex items-center space-x-2">
<span class="text-2xl">{badge.emoji}</span>
<div>
<div class="text-sm font-semibold text-gray-800 dark:text-gray-200">{badge.name}</div>
<div class="text-sm font-semibold text-gray-800 dark:text-gray-200">
{badge.name}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400">{badge.description}</div>
</div>
</div>
Expand Down
26 changes: 18 additions & 8 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@
{:else}
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden">
<table class="w-full">
<thead class="bg-gradient-to-r from-gray-50 to-gray-100 dark:from-gray-700 dark:to-gray-600">
<thead
class="bg-gradient-to-r from-gray-50 to-gray-100 dark:from-gray-700 dark:to-gray-600"
>
<tr>
<th
class="px-6 py-4 text-left text-xs font-semibold text-gray-600 dark:text-gray-300 uppercase tracking-wider"
Expand All @@ -382,7 +384,9 @@
class="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-200"
style="animation-delay: {index * 100}ms;"
>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-200 font-medium">
<td
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-200 font-medium"
>
{new Date(transaction.date).toLocaleDateString()}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-200">
Expand All @@ -398,21 +402,27 @@
<td class="px-6 py-4 text-sm text-gray-900 dark:text-gray-200">
<div>
{#if transaction.payee}
<span class="font-medium text-gray-900 dark:text-gray-200">{transaction.payee}</span>
<span class="font-medium text-gray-900 dark:text-gray-200"
>{transaction.payee}</span
>
{:else}
<span class="text-gray-500 dark:text-gray-400 capitalize"
>{transaction.type.toLowerCase().replace('_', ' ')}</span
>
{/if}
</div>
{#if transaction.note}
<div class="text-gray-500 dark:text-gray-400 text-xs mt-1 leading-relaxed">{transaction.note}</div>
<div class="text-gray-500 dark:text-gray-400 text-xs mt-1 leading-relaxed">
{transaction.note}
</div>
{/if}
</td>
<td
class="px-6 py-4 whitespace-nowrap text-sm font-bold"
>
<div class="flex items-center space-x-1 {getTransactionTypeColor(transaction.type)} {getTransactionTypeDarkColor(transaction.type)}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold">
<div
class="flex items-center space-x-1 {getTransactionTypeColor(
transaction.type
)} {getTransactionTypeDarkColor(transaction.type)}"
>
<span>{formatTransactionAmount(transaction)}</span>
{#if transaction.type === 'TRANSFER_IN' || transaction.type === 'ALLOCATION'}
<span class="text-green-500">↗️</span>
Expand Down
Loading