{"id":23658204,"url":"https://github.com/SourasishBasu/ledgerly","last_synced_at":"2025-09-01T11:31:11.894Z","repository":{"id":270157951,"uuid":"908703907","full_name":"SourasishBasu/ledgerly","owner":"SourasishBasu","description":"Self hostable expense tracking platform","archived":false,"fork":false,"pushed_at":"2025-05-15T10:13:32.000Z","size":1048,"stargazers_count":0,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-15T11:28:53.607Z","etag":null,"topics":["api","aws","devops","docker","fastapi","gemini","goaccess","grafana","monitoring","postgresql","prometheus","python","traefik"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SourasishBasu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-26T18:31:41.000Z","updated_at":"2025-05-15T10:13:36.000Z","dependencies_parsed_at":"2025-02-25T13:21:41.305Z","dependency_job_id":"19815c81-9752-493e-8057-3b30602a9152","html_url":"https://github.com/SourasishBasu/ledgerly","commit_stats":null,"previous_names":["sourasishbasu/expense-tracker","sourasishbasu/ledgerly"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/SourasishBasu/ledgerly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SourasishBasu%2Fledgerly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SourasishBasu%2Fledgerly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SourasishBasu%2Fledgerly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SourasishBasu%2Fledgerly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SourasishBasu","download_url":"https://codeload.github.com/SourasishBasu/ledgerly/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SourasishBasu%2Fledgerly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273114746,"owners_count":25048253,"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","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["api","aws","devops","docker","fastapi","gemini","goaccess","grafana","monitoring","postgresql","prometheus","python","traefik"],"created_at":"2024-12-29T00:05:36.558Z","updated_at":"2025-09-01T11:31:11.888Z","avatar_url":"https://github.com/SourasishBasu.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![banner](./assets/banner.png)\n\u003ch1 align=\"center\"\u003eLedgerly\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  An open source, self hostable expense tracking platform built with NextJS, Python\u003cbr\u003e\n  and AWS for the Lambda functions and S3 object storage.\u003cbr\u003eManage and gain insights from your expenses.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#features\"\u003e\u003cstrong\u003eFeatures\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#overview\"\u003e\u003cstrong\u003eOverview\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#aws-setup\"\u003e\u003cstrong\u003eAWS Setup\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#remote-backend-setup\"\u003e\u003cstrong\u003eBackend Setup\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#usage\"\u003e\u003cstrong\u003eUsage\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#monitoring\"\u003e\u003cstrong\u003eMonitoring\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#authors\"\u003e\u003cstrong\u003eAuthors\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\n- **Website**\n  - [NextJS](https://nextjs.org) App Router\n  - [Amazon Web Services](https://docs.aws.amazon.com/) for backend functionality with `EC2`\n  - Support for `S3` File Storage, and `Lambda` Container image based Functions\n  - Edge runtime-ready\n  \n- **AWS Infrastructure**\n  - [Amazon S3/Minio](https://aws.amazon.com/s3) Utilized for image storage.\n  - [AWS Lambda](https://aws.amazon.com/lambda) for processing JSON and filtering required data\n  - [Amazon EC2](https://aws.amazon.com/sns) for provisioning VM instances \n  - [Amazon ECR](https://aws.amazon.com/ecr) for privately hosting container images \n\n- **External**\n  - [Prometheus](https://prometheus.io/docs/introduction/overview/), [Grafana](https://grafana.com/docs/grafana/latest/) and [GoAccess](https://goaccess.io/) for extensive observability and monitoring of resources. \n  - [Gemini API](https://ai.google.dev/gemini-api/docs) for image to text extraction using Vision Model within free tier limits.\n  - [Github Actions](https://github.com/features/actions) CI pipelines to build, test and push application images from Github to various registries.\n  - [Traefik](https://doc.traefik.io/) acts as a dynamic reverse proxy and automatically manages SSL/TLS certificates\n\n### Tech Stack\n![NextJs](https://img.shields.io/badge/Nextjs-black?style=for-the-badge\u0026logo=nextdotjs\u0026logoColor=white)\n![Python](https://img.shields.io/badge/Python-blue?style=for-the-badge\u0026logo=python\u0026logoColor=white)\n![Uvicorn](https://img.shields.io/badge/uvicorn-E6526F.svg?style=for-the-badge\u0026logo=gunicorn\u0026logoColor=white)\n![EC2](https://img.shields.io/badge/ec2-orange?style=for-the-badge\u0026logo=amazon-ec2\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge\u0026logo=docker\u0026logoColor=white)\n![ECR](https://img.shields.io/badge/ecr-f06611.svg?style=for-the-badge\u0026logo=square\u0026logoColor=white)\n![S3](https://img.shields.io/badge/S3-darkgreen?style=for-the-badge\u0026logo=amazon-s3\u0026logoColor=white)\n![Lambda](https://img.shields.io/badge/Lambda-FF9900?style=for-the-badge\u0026logo=aws-lambda\u0026logoColor=white)\n![Gemini](https://img.shields.io/badge/gemini-8E75B2?style=for-the-badge\u0026logo=google%20gemini\u0026logoColor=white)\n![GitHub Actions](https://img.shields.io/badge/github%20actions-%232671E5.svg?style=for-the-badge\u0026logo=githubactions\u0026logoColor=white)\n![Grafana](https://img.shields.io/badge/grafana-%23F46800.svg?style=for-the-badge\u0026logo=grafana\u0026logoColor=white)\n![Traefik](https://img.shields.io/badge/Traefik-%2300ADD8.svg?style=for-the-badge\u0026logo=go\u0026logoColor=white)\n![Ansible](https://img.shields.io/badge/ansible-%231A1918.svg?style=for-the-badge\u0026logo=ansible\u0026logoColor=white)\n![Prometheus](https://img.shields.io/badge/Prometheus-E6522C?style=for-the-badge\u0026logo=Prometheus\u0026logoColor=white)\n![Minio](https://img.shields.io/badge/MinIO-C72E49.svg?style=for-the-badge\u0026logo=MinIO\u0026logoColor=white)\n\n## Overview\n\u003cimg alt=\"AWS Architecture\" src=\"./assets/arch.png\"\u003e\n\n- The **backend** consists of 3 main services being the **Python based REST API** developed using **FastAPI** for serving requests, performing CRUD operations, a **RDS Postgres** database for data storage and retrieval and a **S3 Bucket** for image storage and hosting.\n- The other 5 services consist of **Traefik** as reverse proxy, utilized for automatic SSL provision, log creation and **Prometheus**, **Grafana** for resource usage collection and visualization using custom **log exporters**.\n- All of these services are run using **Docker** containers to ensure availability and performance.\n\n## Project Structure\n\n```\n.\n├── AWS-setup.md\n├── README.md\n├── assets\n├── deployment\n│   ├── ansible\n│   │   ├── inventory\n│   │   ├── playbook.yml\n│   │   └── roles\n│   │       ├── common\n│   │       │   └── tasks\n│   │       │       └── main.yml\n│   │       ├── docker\n│   │       │   └── tasks\n│   │       │       └── main.yml\n│   │       ├── files\n│   │       │   └── tasks\n│   │       │       └── main.yml\n│   │       └── tools\n│   │           └── tasks\n│   │               └── main.yml\n│   ├── docker-compose.cloud.yml\n│   ├── docker-compose.local.yml\n│   ├── grafana\n│   │   └── datasources.yml\n│   ├── ledgerly.sql\n│   └── prometheus\n│       └── prometheus.yml\n├───frontend\n│   └─── ledgerly\n│        ├─── app\n│        │    └─── dashboard\n│        ├─── bun.lock \n│        ├─── components\n│        │    └─── ui\n│        ├─── components.json\n│        ├─── eslint.config.mjs\n│        ├─── hooks\n│        ├─── next.env.d.ts\n│        ├─── next.config.ts\n│        ├─── package.json\n│        ├─── postcss.config.mjs\n│        └─── tsconfig.json\n└── services\n    ├── backend\n    │   ├── Dockerfile\n    │   ├── app\n    │   │   ├── __init__.py\n    │   │   ├── app.py\n    │   │   ├── core\n    │   │   │   ├── __init__.py\n    │   │   │   ├── config.py\n    │   │   │   ├── db.py\n    │   │   │   └── utils.py\n    │   │   ├── db\n    │   │   │   ├── __init__.py\n    │   │   │   └── models.py\n    │   │   ├── main.py\n    │   │   └── routers\n    │   │       ├── __init__.py\n    │   │       ├── auth.py\n    │   │       ├── deps.py\n    │   │       └── receipts.py\n    │   ├── pyproject.toml\n    │   └── uv.lock\n    └── receipt-ocr\n        ├── Dockerfile\n        └── app.py\n```\n\nPrimary Services:\n- `frontend/ledgerly:` This subdirectory contains the frontend for the Ledgerly application dashboard.\n- `services/backend:` This subdirectory consists of the primary backend API for the entire application facilitating user registration, login, image upload and CRUD operations with the database.\n- `services/receipt-ocr:` This subdirectory consists of the helper application which extracts relevant data using an LLM from user submitted receipt images and adds these records into the database.\n- `deployment/:` This folder consists of all configurations required for the deploying the services and monitoring systems.\n\n# AWS Setup\n\n\u003e [!NOTE]  \n\u003e The default architecture is based on AWS services, however all of the services and tooling can be setup within any other cloud platform of choice or self hosted locally as well if required. Please refer to [AWS Setup](./AWS-setup.md) for setup instructions in the AWS cloud.\n\n# Local Setup\n\n1. Clone the repository locally. Add the environment variables as per the `.env.example` into the `.env` file within the `deployment` directory.\n\n    ```bash\n    git clone https://github.com/sourasishbasu/ledgerly.git\n    cd ledgerly/deployment\n    touch .env\n    ```\n\n2. Install [Docker](https://docs.docker.com/desktop/). Run the containers with `Docker Compose`.\n\n    ```\n    docker compose up -f docker-compose.local.yml --build --pull missing -d\n    ```\n3. Install the [Minio Client](https://min.io/docs/minio/linux/reference/minio-mc.html) and add it to PATH. \n\n    - Run the following commands to setup a local S3 compatible object storage bucket named `images`.\n      ```bash\n      mc alias set local http://localhost:9000 minio minio123\n      mc mb local/images\n      ```\n\n    - Configure a Webhook to listen for `s3:ObjectCreated:PUT` events in the bucket and automatically send event notifications to OCR service worker.\n      ```bash\n      mc admin config set local notify_webhook:trigger endpoint=\"http://worker:8000/event\" \u0026\u0026 mc admin config set local notify_webhook:trigger format=json\n      mc admin service restart local\n      mc event add local/images arn:minio:sqs::trigger:webhook --event put --suffix .jpg\n      mc event add local/images arn:minio:sqs::trigger:webhook --event put --suffix .jpeg\n      mc event add local/images arn:minio:sqs::trigger:webhook --event put --suffix .png\n      ```\n\n    - To list images in Minio, run the following command.\n      ```bash\n      mc ls local/images\n      ```\n\n4. Copy the contents of `deployment/ledgerly.sql` into the SQL Query Editor within any database tool after connecting to the postgres database container.\n\n5. Install Node v22 and [Bun](https://bun.sh/docs/installation). Run the development server for the frontend.\n    ```\n    cd ../frontend/ledgerly/frontend\n    bun dev\n    ```\n\n## Expected Result\n\n```bash\n$ docker compose ps\nNAME       IMAGE                        COMMAND                  SERVICE    CREATED          STATUS                    PORTS\napi        ghcr.io/sourasishbasu/expense-tracker-api:latest   \"fastapi run app/mai…\"   api        48 minutes ago   Up 48 minutes (healthy)   0.0.0.0:5000-\u003e5000/tcp\nminio      minio/minio                  \"/usr/bin/docker-ent…\"   minio      2 hours ago      Up 2 hours                0.0.0.0:9000-9001-\u003e9000-9001/tcp\npostgres   postgres:latest              \"docker-entrypoint.s…\"   postgres   2 hours ago      Up 2 hours (healthy)      0.0.0.0:5432-\u003e5432/tcp\nworker     ghcr.io/sourasishbasu/receipt-ocr:latest           \"fastapi run app.py\"     worker     48 minutes ago   Up 48 minutes (healthy)   0.0.0.0:8000-\u003e8000/tcp\n\n```\n\n# Usage\n\n\u003e [!NOTE]\n\u003e Detailed API docs along with examples and template data can be found at [Scalar Docs](https://expense-tracker.apidocumentation.com/).\n\n### Routes\n\nBackend API: `http://localhost:5000`\n\nWeb Dashboard: `http://localhost:3000`\n\nMinio Dashboard: `http://localhost:9001`\n\n## Demo\nhttps://github.com/user-attachments/assets/9e9d73c8-0b6d-4dd6-baee-66e1c0fc3c48\n\u003cp align=\"center\"\u003e\u003cb\u003eLedgerly Demo\u003c/b\u003e\u003c/p\u003e\n\n### Screenshots\n\u003cimg alt=\"Landing Page\" src=\"./assets/landing.png\"\u003e\n\u003cp align=\"middle\"\u003e\u003cstrong\u003eLanding Page\u003c/strong\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cimg alt=\"Dashboard\" src=\"./assets/dash.png\"\u003e\n\u003cp align=\"middle\"\u003e\u003cstrong\u003eDashboard\u003c/strong\u003e\u003c/p\u003e\n\n\n## Authors\n\nThis project was made for Project Wing 2025 by [MLSAKIIT](https://mlsakiit.com/).\n\n- Sourasish Basu ([@SourasishBasu](https://github.com/SourasishBasu)) - [MLSA KIIT](https://mlsakiit.com)\n\n## Version\n| Version | Date          \t\t| Comments        |\n| ------- | ----------------- | --------------- |\n| 1.0     | May 21st, 2025    | Revised release |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSourasishBasu%2Fledgerly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSourasishBasu%2Fledgerly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSourasishBasu%2Fledgerly/lists"}