{"id":20102892,"url":"https://github.com/artdevgame/budgie","last_synced_at":"2025-10-25T21:11:18.321Z","repository":{"id":48009769,"uuid":"510888543","full_name":"artdevgame/budgie","owner":"artdevgame","description":"Simple budgeting tool","archived":false,"fork":false,"pushed_at":"2022-10-30T17:09:04.000Z","size":8950,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-13T04:29:59.061Z","etag":null,"topics":["cqrs","ddd","event-sourcing","graphql","nativebase","planetscale","react-native-web","redis","sst"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artdevgame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-05T20:43:56.000Z","updated_at":"2024-06-09T09:20:02.000Z","dependencies_parsed_at":"2023-01-20T10:47:50.695Z","dependency_job_id":null,"html_url":"https://github.com/artdevgame/budgie","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artdevgame%2Fbudgie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artdevgame%2Fbudgie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artdevgame%2Fbudgie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artdevgame%2Fbudgie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artdevgame","download_url":"https://codeload.github.com/artdevgame/budgie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241542230,"owners_count":19979278,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqrs","ddd","event-sourcing","graphql","nativebase","planetscale","react-native-web","redis","sst"],"created_at":"2024-11-13T17:33:24.976Z","updated_at":"2025-10-25T21:11:18.262Z","avatar_url":"https://github.com/artdevgame.png","language":"TypeScript","readme":"# 🐦 Budgie\n\nA simple personal budgeting tool, inspired by [YNAB](https://www.youneedabudget.com/).\n\n\u003e 🚧 \u0026nbsp; 👷 \u0026nbsp; 🚧 \u0026nbsp;\n\u003e\n\u003e 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.\n\n## Why?\n\nI 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.\n\nThe 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.\n\nBy 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.\n\nWith this in mind, and as I was looking to expand my knowledge of serverless \u0026 other tech, I thought it was an ideal product to replicate.\n\n## 🧠 Patterns\n\n- Domain Driven Design (DDD)\n- Event Sourcing\n- Command Query Responsibility Segregation (CQRS)\n\nHere's a [primer video](https://www.youtube.com/watch?v=rolfJR9ERxo) on the theory \u0026 practice to get started.\n\n## 🧰 Toolbox\n\n- Serverless via [SST](https://sst.dev) (based on `create-sst`)\n- Authentication via [@serverless-stack/lambda](https://github.com/serverless-stack/sst/tree/lambda/packages/lambda)\n- MySQL database via [PlanetScale](https://planetscale.com) (used for event storage - \"writes\")\n- ORM via [Kysely](https://koskimas.github.io/kysely)\n- Redis caching via [Upstash](https://upstash.com) (used to generate projections - \"reads\")\n- GraphQL (and [Pothos](https://pothos-graphql.dev) for TS schema building) - this is the data access layer from the frontend\n- 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\n- Monitoring with [Sentry](https://sentry.io)\n- [NativeBase](https://nativebase.io/) for the design system\n\n## 🔧 Environment variables\n\n| Name             | Description                                   |\n| ---------------- | --------------------------------------------- |\n| CACHE_URL        | Location of the Redis cache on Upstash        |\n| DATABASE_URL     | Location of the MySQL database on PlanetScale |\n| GOOGLE_CLIENT_ID | OIDC key to use Google social login           |\n| SENTRY_DSN       | Location of the error/performance logs        |\n\n### 🔌 Running locally\n\n#### Prerequisites\n\n1. Create a database at [PlanetScale](https://planetscale.com) - use [schema.mysql](./schema.mysql)\n2. Create a redis cache at [Upstash](https://upstash.com)\n3. Create a new OAuth client with [Google](https://console.cloud.google.com/apis/credentials/oauthclient)\n4. Create an account with [Sentry](https://sentry.io)\n5. Assign the relevant [environment variables](https://github.com/artdevgame/budgie#--environment-variables) based on the above\n\n#### Spinning up\n\n1. Install dependencies with `npm install`\n2. Run the database with `npm run db:start`\n3. 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.\n4. In another shell, run `npm run web` - this will run the website at http://localhost:3000/\n\n### Design system component library\n\n1. Install dependencies with `npm install`\n2. Run `npm run storybook` - Visit http://localhost:6006/ in the browser\n\n## 🌐 Domain setup\n\nI have created a domain outside of the AWS ecosystem, my setup looks like this:\n\n```\nNamecheap -\u003e Cloudflare -\u003e AWS\n```\n\nNamecheap 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).\n\nCloudflare 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.\n\nThe certificate uses DNS validation to ensure ownership of the domain.\n\nThe 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.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartdevgame%2Fbudgie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartdevgame%2Fbudgie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartdevgame%2Fbudgie/lists"}