Skip to content
This repository has been archived by the owner on Jan 18, 2025. It is now read-only.

πŸš€ Data analytics API for personal finance built using NestJS, GraphQL, and Prisma ORM

Notifications You must be signed in to change notification settings

Lyhour-Archieved/moneyapp-api

Β 
Β 

Repository files navigation

Nest Logo

MoneyApp API

πŸ•΅οΈβ€β™‚οΈ About

Versatile GraphQL API built on top of NestJS framework for ease of use on data-analytics frontends

πŸ“ Purpose

  1. Acting an the API for a finance management app (personal use)
  2. Provide a flexible way for the front-end to interact with data
  3. Learn about NestJS & GraphQL without copying from boring tutorials

πŸ“š Frontend repo: HERE

πŸ› οΈ Technologies used

Purpose Tools
βœ… Language TypeScript
βœ… Framework NestJS
βœ… GraphQL API Apollo Server
βœ… Data source Notion API
βœ… Data modelling Prisma ORM
βœ… Decode JWT jsonwebtoken
βœ… Secure API keys dotenv
βœ… Currency conversion Exchange Rates API

πŸ› οΈ Infrastructure

No. Purpose Tools
1 Databse system PostgresSQL
2 Hosting database Supabase
3 Authentication & Identity management Auth0
4 API hosting Heroku
5 CD/CI CircleCI

πŸ—οΈ Architecture

image

⛰️ Product roadmap

No. Description Status
1. Query any income data by any field βœ…
2. Set limit on query amount on income βœ…
3. Query any expenses data by any field βœ…
4. Set limit on query amount on expenses βœ…
5. Group income by any field and calculate sum & counts with date-range filter βœ…
6. Group income by date with date-range filter so that the data returned also includes dates with $0 income for data-visualisation βœ…
7. Group expenses by any field and calculate sum & counts with date-range filter βœ…
8. Group expenses by date with date-range filter so that the data returned also includes dates with $0 expenses for data-visualisation βœ…
9. Query average daily income with date-range filter βœ…
10. Query average daily expenses with date-range filter βœ…
11. Query total income with date-range filter βœ…
12. Query total expenses with date-range filter βœ…
13. Query net income with date-range filter βœ…
14. Prevent authenticated BUT unauthorised users from accessing ALL endpoints βœ…
14. Automatically add new users into a User table in DB after they signed up the app using Auth0
15. Link up Income and Expense tables with User by introducing association rules
16. Mutation for creating row for Income
17. Mutation for updating row for Income
18. Mutation for creating row for Expense
19. Mutation for updating row for Expense
20. Subscription with pagination for retrieving rows from Income
21. Subscription with pagination for retrieving rows from Expense

⁉️ Challenges & workarounds

No. Problem Solution
1 Rate limit from Notion API + Ugly & Inconsistent response structure from Notion SDK Migrate table to real DB (PostgreSQL)
2 DB data isn't in sync with data from Notion Need Notion webhook to setup triggers but none available, current plan is to manually update DB from time to time
3 There are no out-of-box auth solutions for Nest + GraphQL + Auth0 in RBAC (Role-based access-control) Implemented a custom guard that transforms request context from REST into GraphQL context then authenticate and authorise access based on the permissions field of the decoded jwt token payload.
4 When returning sum from IncomeGroupBy queries, the sum amount does not reflect the differences in currency (NZD and USD) Need to either setup compulsory currency filter in query layer or auto-calculate all USD amount to NZD by real-time exchange rate on return
5 Need to show dates with $0 income for aggregated income queries by dynamic date-range filter for time-series chart display Used dates API to populate empty dates

πŸ›« Running the app

# Installation
$ yarn

# build
$ yarn build

# development
$ yarn start

# watch mode
$ yarn dev

# production mode
$ yarn start:prod


## Test
# unit tests
$ yarn test

# unit tests - auto-update
$ yarn test:watch

# e2e tests
$ yarn test:e2e

# test coverage
$ yarn test:cov

## Database
# database seeding
$ npx prisma db seed

# See DB using prisma studio
$ npx prisma studio

πŸ”­ Sample query & response:

All queries are protected by guards, meaning only authorised users are able to execute the queries (which is me, myself and I)

Query income by payment method and calculate sum of income by payment method

# Note: endDate and dateStartInc are optional.
# When date filters are not provided, the query will return all records`
query {
  incomeGroupBy ( 
  	field: "paymentMethod",
    valueType: "sum"
    endDate: "Sun Nov 21 2021 12:12:28 GMT+1300 (New Zealand Daylight Time)"
    startDate: "Wed Sep 01 2021 12:12:28 GMT+1200 (New Zealand Standard Time)"
  ) {
    incomePaymentMethod
    sum
  }
}
{
  "data": {
    "incomeGroupBy": [
      {
        "incomePaymentMethod": "Cash",
        "sum": 10070.43
      },
      {
        "incomePaymentMethod": "Paypal",
        "sum": 10222.8
      },
      {
        "incomePaymentMethod": "Direct Debit",
        "sum": 32190.28
      }
    ]
  }
}

Query income by payment method and returning the number of times income is received by each payment method

query {
  incomeGroupBy ( 
  	field: "paymentMethod",
    valueType: "count"
  ) {
    incomePaymentMethod
    count
  }
}
{
  "data": {
    "incomeGroupBy": [
      {
        "incomePaymentMethod": "Bitcoin",
        "count": 28
      },
      {
        "incomePaymentMethod": "Polkadot",
        "count": 35
      },
      {
        "incomePaymentMethod": "Ethereum",
        "count": 41
      }
    ]
  }
}

Query income by "paidBy" and returning sum of each person/org who paid

query {
  incomeGroupBy ( 
  	field: "paidBy",
    valueType: "sum"
  ) {
    incomePaidBy
    sum
  }
}
{
  "data": {
    "incomeGroupBy": [
      {
        "incomePaidBy": "Amazon Inc",
        "sum": 332830
      },
      {
        "incomePaidBy": "Google Inc",
        "sum": 312872
      },
      {
        "incomePaidBy": "Salesforce Inc",
        "sum": 3298770
      },
    ]
  }
}

Query income by date and returning accumulated income including days when income is $0

query {
  incomeGroupBy ( 
  	field: "date",
    valueType: "sum"
    startDate: "Sun Nov 21 2021 12:12:28 GMT+1300 (New Zealand Daylight Time)"
    endDate: "Tue Nov 23 2021 13:00:00 GMT+1300 (New Zealand Daylight Time)"
  ) {
    date
    sum
  }
}
{
  "data": {
    "incomeGroupBy": [
      {
        "date": "2021-11-21T23:12:28.000Z",
        "sum": 23443
      },
      {
        "date": "2021-11-22T23:12:28.000Z",
        "sum": 0
      },
      {
        "date": "2021-11-23T00:00:00.000Z",
        "sum": 20000
      },
    ]
  }
}

Query daily average income given a date range, returning the type of average income queried and the value

query {
  averageIncome (
    type: "daily"
    startDate: "Thu Jul 01 2021 12:00:00 GMT+1200 (New Zealand Standard Time)"
    endDate: "Tue Sep 28 2021 13:00:00 GMT+1300 (New Zealand Daylight Time)"
  ) {
    type
    average
  }
}
{
  "data": {
    "averageIncome": [
      {
        "type": "daily",
        "average": 5000
      }
    ]
  }
}

Get total income given a date range

query {
  incomeSum (
    startDate: "Thu Jul 01 2021 12:00:00 GMT+1200 (New Zealand Standard Time)"
    endDate: "Tue Sep 28 2021 13:00:00 GMT+1300 (New Zealand Daylight Time)"
  ) {
    sum
  }
}
{
  "data": {
    "incomeSum": [
      {
        "sum": 152360.76
      }
    ]
  }
}

Get total expenses given a date range

query {
  expenseSum (
    startDate: "Thu Jul 01 2021 12:00:00 GMT+1200 (New Zealand Standard Time)"
    endDate: "Tue Sep 28 2021 13:00:00 GMT+1300 (New Zealand Daylight Time)"
  ) {
    sum
  }
}
{
  "data": {
    "expenseSum": [
      {
        "sum": 7639.89
      }
    ]
  }
}

About

πŸš€ Data analytics API for personal finance built using NestJS, GraphQL, and Prisma ORM

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 97.5%
  • JavaScript 2.1%
  • Other 0.4%