https://github.com/artdevgame/budgie
Simple budgeting tool
https://github.com/artdevgame/budgie
cqrs ddd event-sourcing graphql nativebase planetscale react-native-web redis sst
Last synced: 5 months ago
JSON representation
Simple budgeting tool
- Host: GitHub
- URL: https://github.com/artdevgame/budgie
- Owner: artdevgame
- License: mit
- Created: 2022-07-05T20:43:56.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2022-10-30T17:09:04.000Z (over 3 years ago)
- Last Synced: 2025-01-13T04:29:59.061Z (about 1 year ago)
- Topics: cqrs, ddd, event-sourcing, graphql, nativebase, planetscale, react-native-web, redis, sst
- Language: TypeScript
- Homepage:
- Size: 8.54 MB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 🐦 Budgie
A simple personal budgeting tool, inspired by [YNAB](https://www.youneedabudget.com/).
> 🚧 👷 🚧
>
> Work is in progress / under construction. This is a hobby project and I'm only working on it occassionally. You're welcome to browse the code and follow along but it won't be complete for a while.
## Why?
I love YNAB and have used the desktop version for years. At some point in the past they moved their business model over to a subscription service. I didn't see the value of switching as I had all the features I required in their original version.
The only 'issue' I had was the data syncing between different devices, which predominantly used Dropbox. I used to have several services using Dropbox, so I didn't think too much about using it, but over time I have migrated away from the platform and it just became another redundant app.
By disconnecting YNAB from Dropbox, I could only use the app on my Windows computer, which is inconvenient as I spend most of my time on other devices nowadays.
With this in mind, and as I was looking to expand my knowledge of serverless & other tech, I thought it was an ideal product to replicate.
## 🧠 Patterns
- Domain Driven Design (DDD)
- Event Sourcing
- Command Query Responsibility Segregation (CQRS)
Here's a [primer video](https://www.youtube.com/watch?v=rolfJR9ERxo) on the theory & practice to get started.
## 🧰 Toolbox
- Serverless via [SST](https://sst.dev) (based on `create-sst`)
- Authentication via [@serverless-stack/lambda](https://github.com/serverless-stack/sst/tree/lambda/packages/lambda)
- MySQL database via [PlanetScale](https://planetscale.com) (used for event storage - "writes")
- ORM via [Kysely](https://koskimas.github.io/kysely)
- Redis caching via [Upstash](https://upstash.com) (used to generate projections - "reads")
- GraphQL (and [Pothos](https://pothos-graphql.dev) for TS schema building) - this is the data access layer from the frontend
- Event bus via [Amazon EventBridge](https://aws.amazon.com/eventbridge), which is used to update projections and to dispatch [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) to help keep the frontend in sync
- Monitoring with [Sentry](https://sentry.io)
- [NativeBase](https://nativebase.io/) for the design system
## 🔧 Environment variables
| Name | Description |
| ---------------- | --------------------------------------------- |
| CACHE_URL | Location of the Redis cache on Upstash |
| DATABASE_URL | Location of the MySQL database on PlanetScale |
| GOOGLE_CLIENT_ID | OIDC key to use Google social login |
| SENTRY_DSN | Location of the error/performance logs |
### 🔌 Running locally
#### Prerequisites
1. Create a database at [PlanetScale](https://planetscale.com) - use [schema.mysql](./schema.mysql)
2. Create a redis cache at [Upstash](https://upstash.com)
3. Create a new OAuth client with [Google](https://console.cloud.google.com/apis/credentials/oauthclient)
4. Create an account with [Sentry](https://sentry.io)
5. Assign the relevant [environment variables](https://github.com/artdevgame/budgie#--environment-variables) based on the above
#### Spinning up
1. Install dependencies with `npm install`
2. Run the database with `npm run db:start`
3. In another shell, run `npm start` - the first time you do this it will take some time as it sets up the various bits of infrastructure.
4. In another shell, run `npm run web` - this will run the website at http://localhost:3000/
### Design system component library
1. Install dependencies with `npm install`
2. Run `npm run storybook` - Visit http://localhost:6006/ in the browser
## 🌐 Domain setup
I have created a domain outside of the AWS ecosystem, my setup looks like this:
```
Namecheap -> Cloudflare -> AWS
```
Namecheap uses Cloudflare as for DNS, and Cloudflare uses a [CNAME entry to point to the urls created by AWS](https://stackoverflow.com/a/61866193/349755).
Cloudflare provide a free SSL certificate via Let's Encrypt, but to make it work with SST I've requested a public certificate through [AWS Certfificate Manager](https://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/list) (AWM) in the `us-east-1` region.
The certificate uses DNS validation to ensure ownership of the domain.
The reason I'm not using Route 53 as recommended by SST is to avoid the monthly $.50 fee. This is something I would probably reconsider if I wasn't building a hobby project.