I-deul-of-zoo / jinsoo-budget-management

예산 관리 어플리케이션
0 stars 1 forks source link

Budget manager

목차

개요

유저히스토리

요구사항 및 구현사항

1. 유저

사용자 회원가입(API)

사용자 로그인(API)

2. 예산설정 및 설계

카테고리 목록(API)

예산 설정(API)

예산 설계 (=추천) (API)

3.## 지출 기록

지출

지출 CRUD (API)

4. 지출 컨설팅

오늘 지출 추천(API)

오늘 지출 안내(API)

5. 지출 통계

Dummy 데이터 생성

지출 통계 (API)

개발환경세팅

가상환경: venv

언어 및 프레임워크: Python DjangoREST

데이터 베이스: MySQL Redis

Installation & Run

MySQL DB 세팅

환경 세팅

2️ 애플리케이션의 실행 방법 (엔드포인트 호출 방법 포함)

(전제) python >= 3.11mysql >= 8.0 은 설치되어 있습니다.

1. python venv로 가상환경 생성 및 활성화.

  1. 가상환경을 만드는 명령어
    python -m venv venv
  2. 가상환경 활성화
    source venv/Scripts/activate

2. 패키지 설치

pip install -r requirements.txt

3. manage.py 가 있는 위치에서 모델 migration을 해줍니다.

python manage.py migrate

[참고]

4. manage.py 가 있는 위치에서 서버를 실행합니다.

python manage.py runserver 

초기 설정 : 데이터

ER-Diagram

erd_image


API Documentation

api_doc

1. 회원가입 API

Request

  POST /api/auth/signup
Body Parameter Type Description
username string Required.
password string Required.
EX)
{
    "username": "user1",
    "password": "devpassword1"
}

Response

HTTP 201 Created
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "username": "user1"
}

2. JWT로그인 API

Request

  POST /api/auth/jwt-login
Body Parameter Type Description
username string Required.
password string Required.
EX)
{
    "username": "user1",
    "password": "devpassword1"
}

Response

HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "username": "user1",
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpVXCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjk5NDM2NTA3LCJpYXQiOjE2OTk0MzI5MDcsImp0aSI6Ijc4Y2E1NzI3NDZkMDQzYzA4ZWZlNWM3NGNjMDFkNDNiIiwidXNlcl9pZCI6MX0.W-z5wAg0zNJWlaLA6mb0xEMPeEdOqenKeKrCsenWCNs"
}

3. 카테고리 목록 API

Request

  GET /api/budgets/

Rquest Header

Parameter Type Description
Authorization string Required. 'Bearer eyJhbGciOiJIU...'
Content-Type string Required. application/json

Response

{
    "message": "get categories",
    "data": [
        {
            "id": 1,
            "name": "undefined"
        },
        {
            "id": 2,
            "name": "쇼핑"
        },
        {
            "id": 3,
            "name": "교통"
        },
        {
            "id": 4,
            "name": "주거비"
        },
        {
            "id": 5,
            "name": "취미"
        },
        {
            "id": 6,
            "name": "교육"
        },
        {
            "id": 7,
            "name": "병원"
        },
        {
            "id": 8,
            "name": "식비"
        },
        {
            "id": 9,
            "name": "저축/투자"
        }
    ]
}

4. 예산설정 및 설계 - 예산설정 API: 예산생성

Request

  POST /api/budgets/

Request Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Body content

Body Parameter Type Description
category integer Required.
amount integer Required.

Response

{
    "message": "budget create success!",
    "setup_user": 2,
    "setup_user_total": 100,
    "data": [
        10,
        11,
        12
    ]
}

5. 예산설정 및 설계 - 예산설정 API: 예산수정

1개의 레코드만 수정합니다.

Request

  PATCH /api/budgets/

Request Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Body content

Body Parameter Type Description
category integer Required.
amount integer Required.

Body example

{
    "category": 2,
    "amount": 30
}

Response

{
    "message": "success!",
    "data": "Budget[1] - category쇼핑 is changed.(30)"
}

6. 예산설정 및 설계 - 추천 API:스타일 목룍

Request

  GET /api/budgets/rec/

Request Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "recommend styles",
    "data": [
        "식비위주",
        "쇼핑위주",
        "취미위주",
        "저축/투자위주"
    ]
}

7. 예산설정 및 설계 - 추천 API:예산생성

Request

  POST /api/budgets/rec/

Request Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Body content

Body Parameter Type Description
total integer Required.
style string Required.

Response

{
    "message": "suceess!",
    "setup_user": 2,
    "setup_user_total": 1200000,
    "data": [
        41,
        42,
        43,
        44,
        45
    ]
}

8. 예산설정 및 설계 - 추천 API:예산수정

예산 수정 스타일 지정 변경이기 때문에 해당되지 않는 카테고리는 0으로 수정하고, 없었던 budget 카테고리 행은 생성합니다.

Request

  PATCH /api/budgets/rec/

Request Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Body content

Body Parameter Type Description
total integer Required.
style string Required.

Response

{
    "message": "style change success",
    "data": "쇼핑위주"
}

9. 지출 기록 - 지출 CRUD API:List조회

유저가 소비한 항목들에 대한 모든 정보와 전체/카테고리별 소비금액 정보를 반환

Request

  GET /api/expenditures/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "success!",
    "data": [
        {
            "id": 1,
            "amount": 22000,
            "appropriate_amount": 10000,
            "memo": "어디어디서 썼습니다",
            "is_exept": false,
            "created_at": "2023-11-15T09:39:37.523988",
            "updated_at": "2023-11-15T10:23:46.735049",
            "user": 2,
            "category": 3
        },
        {
            "id": 2,
            "amount": 25000,
            "appropriate_amount": 10000,
            "memo": "어디어sdfsdfsdf디서 썼습니다",
            "is_exept": false,
            "created_at": "2023-11-15T09:39:52.412771",
            "updated_at": "2023-11-15T09:39:52.412771",
            "user": 2,
            "category": 4
        },
        {
            "id": 3,
            "amount": 68000,
            "appropriate_amount": 10000,
            "memo": "간만에 뭘좀 샀는데 뭘샀을까?",
            "is_exept": false,
            "created_at": "2023-11-15T10:30:42.755083",
            "updated_at": "2023-11-15T10:30:42.755083",
            "user": 2,
            "category": 5
        },
        {
            "id": 4,
            "amount": 68000,
            "appropriate_amount": 10000,
            "memo": "간만에 뭘좀 샀는데 뭘샀을까?",
            "is_exept": false,
            "created_at": "2023-11-16T04:30:05.493767",
            "updated_at": "2023-11-16T04:30:05.494782",
            "user": 2,
            "category": 5
        },
        {
            "id": 5,
            "amount": 68000,
            "appropriate_amount": 10000,
            "memo": "간만에 뭘좀 샀는데 뭘샀을까?",
            "is_exept": false,
            "created_at": "2023-11-16T04:30:30.164717",
            "updated_at": "2023-11-16T04:30:30.165718",
            "user": 2,
            "category": 5
        },
        {
            "id": 6,
            "amount": 15000,
            "appropriate_amount": 10000,
            "memo": "호롤로",
            "is_exept": false,
            "created_at": "2023-11-16T06:01:07.085904",
            "updated_at": "2023-11-16T06:01:07.085904",
            "user": 2,
            "category": 2
        },
        {
            "id": 7,
            "amount": 27000,
            "appropriate_amount": 10000,
            "memo": "호롤로2",
            "is_exept": false,
            "created_at": "2023-11-16T06:01:18.473358",
            "updated_at": "2023-11-16T06:01:18.473358",
            "user": 2,
            "category": 2
        },
        {
            "id": 8,
            "amount": 33300,
            "appropriate_amount": 10000,
            "memo": "33호호호홓ㅎㅎ3332",
            "is_exept": false,
            "created_at": "2023-11-16T06:01:31.638764",
            "updated_at": "2023-11-16T06:01:31.638764",
            "user": 2,
            "category": 3
        },
        {
            "id": 9,
            "amount": 2300,
            "appropriate_amount": 10000,
            "memo": "기타소비1",
            "is_exept": false,
            "created_at": "2023-11-19T16:23:22.261079",
            "updated_at": "2023-11-19T16:23:22.261079",
            "user": 2,
            "category": 1
        },
        {
            "id": 10,
            "amount": 4400,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리2",
            "is_exept": false,
            "created_at": "2023-11-19T16:23:40.198193",
            "updated_at": "2023-11-19T16:23:40.198193",
            "user": 2,
            "category": 2
        },
        {
            "id": 11,
            "amount": 12000,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리2",
            "is_exept": false,
            "created_at": "2023-11-19T16:23:50.713640",
            "updated_at": "2023-11-19T16:23:50.713640",
            "user": 2,
            "category": 2
        },
        {
            "id": 12,
            "amount": 52000,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리2",
            "is_exept": false,
            "created_at": "2023-11-19T16:23:55.347926",
            "updated_at": "2023-11-19T16:23:55.348941",
            "user": 2,
            "category": 2
        },
        {
            "id": 13,
            "amount": 24000,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리3",
            "is_exept": false,
            "created_at": "2023-11-19T16:24:05.103259",
            "updated_at": "2023-11-19T16:24:05.104258",
            "user": 2,
            "category": 3
        },
        {
            "id": 14,
            "amount": 28900,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리5",
            "is_exept": false,
            "created_at": "2023-11-19T16:24:23.814410",
            "updated_at": "2023-11-19T16:24:23.814410",
            "user": 2,
            "category": 5
        },
        {
            "id": 15,
            "amount": 37580,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리5",
            "is_exept": false,
            "created_at": "2023-11-19T16:24:34.861078",
            "updated_at": "2023-11-19T16:24:34.861078",
            "user": 2,
            "category": 7
        },
        {
            "id": 16,
            "amount": 4600,
            "appropriate_amount": 10000,
            "memo": "오늘의소비 카테고리5",
            "is_exept": false,
            "created_at": "2023-11-19T16:24:44.307684",
            "updated_at": "2023-11-19T16:24:44.307684",
            "user": 2,
            "category": 5
        }
    ],
    "static_data": {
        "category_group": [
            {
                "undefined": {
                    "count": 1,
                    "sum": 2300
                }
            },
            {
                "쇼핑": {
                    "count": 5,
                    "sum": 110400
                }
            },
            {
                "교통": {
                    "count": 3,
                    "sum": 79300
                }
            },
            {
                "주거비": {
                    "count": 1,
                    "sum": 25000
                }
            },
            {
                "취미": {
                    "count": 5,
                    "sum": 237500
                }
            },
            {
                "교육": {
                    "count": 0,
                    "sum": 0
                }
            },
            {
                "병원": {
                    "count": 1,
                    "sum": 37580
                }
            },
            {
                "식비": {
                    "count": 0,
                    "sum": 0
                }
            },
            {
                "저축/투자": {
                    "count": 0,
                    "sum": 0
                }
            }
        ],
        "total_sum": 492080
    }
}

10. 지출 기록 - 지출 CRUD API:생성

Request

  POST /api/expenditures/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Request Body

Body Parameter Type Description
category integer Required.
amount integer Required.
memo string Required.

Response

{
    "message": "success!",
    "data": {
        "category": 3,
        "amount": 200,
        "memo": "카테고리덧ㄷ러ㅣㄴ소비소빗",
        "user": 2,
        "appropriate_amount": 10000
    }
}

11. 지출 기록 - 지출 CRUD API:조회 상세보기

1개 지출에 대한 모든 내용을 확인하는 API

Request

  GET /api/expenditures/<int:expenditure_id>/
  GET /api/expenditures/15/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "get sucess!",
    "data": {
        "id": 15,
        "amount": 37580,
        "appropriate_amount": 10000,
        "memo": "오늘의소비 카테고리5",
        "is_exept": false,
        "created_at": "2023-11-19T16:24:34.861078",
        "updated_at": "2023-11-19T16:24:34.861078",
        "user": 2,
        "category": 7
    }
}

11. 지출 기록 - 지출 CRUD API:수정

Request

  PATCH /api/expenditures/<int:expenditure_id>/
  GET /api/expenditures/15/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Request Body

Body Parameter Type Description
category integer Required.
amount integer Required.
memo string Required.

Response

{
    "message": "update sucess!"
}

12. 지출 기록 - 지출 CRUD API:삭제

Request

  DELETE /api/expenditures/<int:expenditure_id>/
  DELETE /api/expenditures/15/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "delete sucess!",
    "data": {
        "id": 15,
        "amount": 22000,
        "appropriate_amount": 10000,
        "memo": "어디어디서 썼습니다",
        "is_exept": false,
        "created_at": "2023-11-19T16:24:34.861078",
        "updated_at": "2023-11-19T23:38:12.157585",
        "user": 2,
        "category": 3
    }
}

13. 지출 컨설팅 - 오늘 지출 추천 API

이번 달 지출과 예산 내용을 조합해서 오늘 지출 내용을 추천해줍니다.

Request

  GET /api/expenditures/rec/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "today(2023-11-19)'s message: you have to save your money!",
    "data": {
        "today_recommand": 168530,
        "period": "2023-11-01 00:00:00 ~ 2023-11-19 00:00:00",
        "쇼핑": 25600,
        "교통": 3700,
        "주거비": 14500,
        "취미": 3330,
        "식비": 20800,
        "저축/투자": 0
    }
}

14. 지출 컨설팅 - 오늘 지출 안내 API

소비 내용에 대한 비율과 카테고리별 소비 비용을 알려줍니다. 예산에 없는 범위에 소비 내용이 있을 경우 -1로 처리했습니다.

  GET /api/expenditures/noti/

Rquest Header

Parameter Type Description
Authorization string Required. Bearer eyJhbGciOiJIU...
Content-Type string Required. application/json

Response

{
    "message": "success!",
    "data": {
        "total": 76,
        "undefined": -1,
        "쇼핑": 267,
        "교통": 654,
        "주거비": 0,
        "취미": 1006,
        "교육": -1,
        "병원": -1,
        "식비": 0,
        "저축/투자": -1,
        "unit": "percent"
    },
    "recommend_data": {
        "today_recommand": 168530,
        "period": "2023-11-01 00:00:00 ~ 2023-11-19 00:00:00",
        "쇼핑": 25600,
        "교통": 3700,
        "주거비": 14500,
        "취미": 3330,
        "식비": 20800,
        "저축/투자": 0
    }
}

Scheduler 기능

프로젝트 진행 및 이슈 관리


구현과정(설계 및 의도)

  1. RESTful API 설계

    • 리소스 간 계층 구조를 나타내는 URI로 구현했습니다.
    • 각 API의 Response에 맞는 HTTP status code를 적절하게 사용하였고, 발생할 수 있는 에러 상황에 대한 예외처리를 진행하였습니다.
  2. 모델링

    • 예산이나 지출 관련하여 시작 기준일총예산은 지속적으로 확인해야 하고 고정적인 값이기 때문에 User 모델에 필드를 추가하여 확인하도록 결정했습니다.
    • 추가적으로 추천 예산에 대해서는 테이블을 하나 추가로 추가하여 매일 자정이 지나면 자동으로 수정하는 기능을 추가하는 것도 좋은 방법으로 생각됩니다. 이 방법으로 개선할 경우, 함수로 모듈화를 진행한 부분을 스케쥴러 부분으로 옮겨지고, 계산 대신 DB에서 조회해오면 되기 때문에 views의 코드가 매우 가독성 높아집니다.
  3. 서비스 사용자 관점에서

    • 서비스 사용자 관점에서 다른 유저들의 소비 형태보다 나에게 맞는 비율을 추천해주는 것이 훨씬 편리하다고 생각했습니다.
    • 왜냐하면 사람마다 스타일이 매우 다르기 때문에 평균을 내어 추천하는 것이 의미가 크지 않다고 생각했습니다.
    • 또한, 내 소비 스타일(쇼핑, 저축 등)만 고르면 바로 편리하게 설정이 되고, 나머지는 예산 생성/수정 기능을 활용하는 방식이 좋다고 생각했습니다.
  4. Scheduler 설계

    • 주기적인 실행이 필요한 지출 추천 및 지출 알림 기능을 구현 위해 APscheduler를 사용하고자 하였습니다.
    • APScheduler만 적용한 상태이고 아직 연동 및 테스트 전입니다.


Authors

이름 github주소
유진수 https://github.com/YuJinsoo