데이터메이커 구성원이 사용하는 간식 주문 App 을 위한 Backend API Server
해당 프로젝트는 Poetry 를 사용하여 패키징 되었다. 하기 Docker Container 에서도 poetry 를 그대로 사용한다. 모든 세팅은 pyproject.toml
에 기록되어 있으며 poetry 로 initialize 할 수 있다.
> poetry install
또한 별도 가상환경을 사용하지 않고 poetry 가 제공하는 가상환경을 사용하게 되는데 activate
방법은 아래와 같다.
> poetry shell
Python 을 통해 실행하는 모든 명령어는 가상환경을 activate 하지 않아도 아래와 같이 사용 가능하다.
> poetry run pytest --pdb
아래의 과정을 통해 로컬 환경을 세팅합니다.
.env.docker-compose.template
파일을 복사해 .env.docker-compose
파일을 생성한 후 아래 내용을 작성합니다.
DB_VERSION=16.1
DB_DATABASE_NAME=snack
DB_USERNAME=snack
DB_PASSWORD=
DB_DIR=
- DB_DIR: postgres 컨테이너를 사용 시 컨테이너를 삭제하면 DB 내용이 삭제됩니다. 이에 local volume 과 연결하여 데이터 파일을 별도 저장하면 컨테이너가 삭제 되더라도 데이터를 유지할 수 있습니다.
개발환경은 Docker 및 Docker Compose 를 이용해 구성했습니다. 아래의 과정을 통해 이미지를 빌드하고 Docker container 를 실행합니다. 자세한 내용은 Makefile 을 살펴보면 조회할 수 있습니다.
최초 실행 혹은 requirements 에 패키지가 추가된 경우 재빌드 합니다.
> make build
> make logs
보통의 경우 컨테이너를 단순 실행하여 개발서버를 구동합니다.
> make up
> make logs
컨테이너 재실행이 필요한 경우 아래와 같이 수행합니다. 전체 컨테이너 재실행이 필요한 경우 아래와 같습니다.
> make down
> make up
특정 컨테이너만 재실행 할 경우 아래와 같습니다.
> make restart CONTAINER=snack-server
RESTful 개념은 이미 논문 제시된 개념이며, 이를 해석하여 Convention 들이 제시되고 있다. 그 중 아래의 Best Practice 를 참고할까 한다.
REST API 의 Best Practice 는 프로젝트 마다 다양하게 변형될 수 있으며, 원 창안자가 제시한 개념을 단일 Best Practice 가 모두 담기도 어렵다.
- 활발하게 discussion 및 revise 가 이루어 지고 있으며
- 반응이 비교적 좋은 Practice 라고 판단되는 아래 내용을 참조하려 한다.
- Lokesh Gupta's Convention
Do not use trailing slash
같은 rule 은 Django 에 적용할 수 없으니 무시한다.- 모든 API 는 Endpoint 까지만 정의하고 나머지는 drf-spectacular 의 문서를 활용한다.
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "davidattenborough", "password": "boatymcboatface"}' \
http://localhost:8000/auth/token/
...
{
"access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU",
"refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"
}
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"}' \
http://localhost:8000/auth/token/refresh/
...
{"access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNTY3LCJqdGkiOiJjNzE4ZTVkNjgzZWQ0NTQyYTU0NWJkM2VmMGI0ZGQ0ZSJ9.ekxRxgb9OKmHkfy-zs1Ro_xs1eMLXiR17dIDBVxeT-w"}
간식 주문 관련 APIs
GET /orders/
GET /order/<str:order_uid>/
POST /order/
간식 관련 APIs
GET /snacks/
시스템 사용자의 권한을 설정하고 역할 별 제한사항을 설정합니다.
Permission 구성 요소는 아래와 같습니다. 등급 별 권한이 상이합니다.
- 일반회원 (member)
- 관리자 (admin)
- 선택 가능한 간식 목록 조회
- 주문 목록 조회
- 간식 주문
- member 의 모든 권한
- 주문 상태 변경
- Python==3.11.7
- Django==4.2.9
- Postgres==16.1
- Vue3
- DRF 를 사용해 RESTAPI 를 제공한다.
- drf-spectacular 를 이용해 OpenAPI format 과 SwaggerUI 로 API 문서를 제공한다.
- 회원가입할 때
이메일(아이디), 비밀번호, 이름
만 받습니다 . - 회원은 일반 회원과 관리자로 나뉩니다.
- 관리자가 회원을 관리하는 목록이 존재하고, 회원을 관리자로 변경이 가능합니다.
- 회원 탈퇴가 가능하고, 가입할 때 탈퇴한 회원의 이메일로는 가입할 수 없습니다.
- Sign up
- Sign in
- User list
이름, 이미지, 구매 URL, 설명
을 입력할 수 있는 게시판- 목록만 에서 모든 필드와 상태 확인 가능
- 관리자는 게시판에서 주문상태 변경
- 주문상태 변경할 시 예상 사용 일시 입력해야 함 (어떤 예상 사용 일시? 실제 소비할 수 있는 날자?)
- 월별 별도 목록 필요
- 한번 등록된 간식은 추후 선택 가능 (간식 요청 모델과 간식 모델의 관계 지정을 통한 구현 필요)
- 대기중 일 때만 수정 가능 - 배송 대기중? 주문 대기중? 생성 후 주문 전 (before status ordered)
- 같은 간식을 중복 신청할 수 없다. - 기준은? 한번 주문할 때
- 신청된 간식에 좋아요/싫어요를 선택 가능
- 좋아요/싫어요 비율에 따라 우선순위 조정
- 싫어요가 좋아요보다 많으면, 간식신청의 주문상태를 주문완료로 바꿀 수 없다.
간식을 구별하는 유일값은 간식의 이름이다.
- Order list
- Snack list
- Order snack
본 프로젝트에서 사용되는 Business Processes 를 정의합니다.
- 회원 가입 페이지
- 로그인 페이지
- 주문 목록 페이지
- 간식 목록 페이지
- 관리자는 간식 상태 변경
- 통계 페이지
---
title: 프로젝트 Business Process Flow
---
flowchart TD
signup[회원 가입 페이지]
login[로그인 페이지]
orderlist[주문 목록 페이지]
signup --> |가입 성공| login
signup --> |가입 실패| signup
login --> |로그인 성공| orderlist
orderlist --> |로그아웃 성공| login
---
title: 프로젝트 Business Process Flow
---
flowchart TD
orderlist[주문 목록 페이지]
snacklist[간식 목록 페이지]
registersnack[간식 등록 페이지 or 모달]
registerprocess{간식 등록 프로세스 실행}
orderlist --> |등록된 간식 목록 조회| snacklist
snacklist --> |주문 목록 조회| orderlist
snacklist --> |신규 간식 등록|registersnack
registersnack --> |간식 정보 submit|registerprocess
registerprocess --> |등록 성공| snacklist
registerprocess --> |등록 실패| registersnack
---
title: 프로젝트 Business Process Flow
---
flowchart TD
orderlist[주문 목록 페이지]
orderdetail[주문 상세 페이지]
ordersnack[간식 주문 페이지 or 모달]
orderprocess{간식 주문 프로세스 실행}
orderlist --> |특정 주문 상세정보 확인| orderdetail
orderdetail --> |주문 목록 조회| orderlist
orderlist --> |간식 주문 버튼 클릭| ordersnack
ordersnack --> |원하는 간식 및 수량 등을 선택 후 주문| orderprocess
orderprocess --> |주문 성공| orderdetail
orderprocess --> |주문 실패| ordersnack
- 사용자는 시스템을 탈퇴할 수 있다.
- 탈퇴 버튼 위치는 sign-out 우측이다.
- 탈퇴 시 정말 탈퇴할지 한번 더 확인한다.
- 탈퇴에 성공하게 되면 시스템의 store.auth 를 비운다.
- 탈퇴 시 서버에서는 사용자 정보를 지우지 않고 is_deleted flag 만 True 처리 한다.
- 이후 재가입 시도 시 탈퇴한 사용자는 재가입이 불가능하다고 안내한다.
- 시스템에 ADMIN 이 본인 1명밖에 없으면 탈퇴할 수 없다.
주문 상태의 구성과 플로우는 아래와 같다.
- created:생성됨
- ordered:주문 완료
- canceled:취소됨
- approved:승인됨
- shipping:배송중
- completed:완료
---
title: 주문 상태 Flow
---
flowchart TD
created[created]
ordered[ordered]
canceled[canceled]
approved[approved]
shipping[shipping]
completed[completed]
approved --> |주문 작성 완료 및 주문| ordered
created --> |간식 승인| approved
ordered --> |배송 시작 처리, 예상 도착 일시 입력| shipping
shipping--> |간식 배송 완료| completed
created --> |주문 취소| canceled
approved --> |주문 취소| canceled
- 주문 대기중 상태에서만 주문 수정 가능
- 아직 주문되지 않은 간식 중 신청된 간식이 있는 경우 중복 신청 할 수 없다.
싫어요가 좋아요보다 많으면, 간식신청의 주문상태를 주문완료로 바꿀 수 없다.
-> 이 항목은 아래와 같이 유의 해석함.- like_ratio < 1
- 관리자가 해당 주문을 승인하고 주문함
- 따라서 승인 시점에 좋아요/싫어요 비율을 측정하는 것이
선호도가 낮은 간식은 주문하지 않는다
라는 전제를 가장 만족한다고 본다. - 승인 이후 주문됨, 배송중, 완료 시점에는 이미 되돌릴 수 없기 때문이다.
말그대로 Flow 는 단계를 건너뛰거나 다음 단계로 갈 수 없는 등 오류가 없어야 한다. 더 적은 코드로 적은 오류를 발생시키고 고가용성을 발휘하도록 상태 흐름을 구현한다.
- Order models 의 Mixin 을 별도로 추가하고 상태를 변경하는 메소드를 지원한다.
- 이외
직접 업데이트
등의 방법으로 상태 변경을 금지한다.
- 예상 도착 일시는 ordered, shipping 에서만 필요하며 업데이트 된다.
- created -> approved, approved -> ordered 변경 시 주문에 포함된 간식 중
hate > like
인 간식이 한개라도 있다면 변경 실패처리 한다. - 현재 신청하려는 간식 중 아직 주문 (배송중 이상) 되지 않은 간식이 있다면 신청할 수 없다.
- Order List Page 에서 상태를 변경하도록 한다. -> 필드를 추가하고 status dropdown, arrive_estimate_date 를 위한 input 도 추가한다.
- 변경 시 예상 도착일 (예상 사용일) 을 같이 입력하도록 UI 를 구성한다.
- 개별 Snack model 은 ForeignKey 연결된 SnackReaction Model 에 like, hate 반응을 기록한다.
- 사용자는 단일 Snack 에 1개의 reaction 을 남길 수 있다.
- 1번 사용자는 A 스낵에 like 를 남길 수 있다.
- 1번 사용자는 A 스낵에 like 과 hate 를 동시에 남길 수 없다.
- 사용자는 자신이 남긴 reaction 을 취소할 수 있다.
- 1번 사용자는 A 스낵에 남긴 hate 를 남긴 후 like 로 변경하고자 한다.
- 이때 1번 사용자가 A 스낵의 hate 를 누르면 "중복해서 reaction 을 남길 수 없다." 는 메시지를 보게 된다.
- 1번 사용자는 A 스낵의 like 를 누른다.
- snack, user 에 대응하는 reation 을 get_or_create 하여 get 인 경우 해당 type 으로 업데이트 한다.
- Front 에서 업데이트 할 수 있도록 수량을 제공한다.
- 간식 별 수량 집계가 수월해야 한다.
- type 별 수량
- type 간 비율
- 수량 및 비율 집계는 SQL Query 집계 시 온전한 성능을 발휘하기 어렵다.
- 최대한 즉각 반영 되면서 중복문제가 없도록 구현 필요
- 수량, 비율 등 집계 지표로 정렬이 가능해야 한다.
- 1차: Celery 연동으로 통계용 필드 업데이트 담당(Order 의 통계용 필드들), 즉각 response 해야하는 부분은 바로 db 참조 (SnackReaction)
- 2차: Redis cache 를 사용하여 업데이트 -> 속도 증가 차원
- 간식 목록은 좋아요/싫어요 비율이 정렬의 기준이 된다. 해설하면 아래와 같다.
- 전제: 싫어요 대비 좋아요 비율을 기준으로 상위 노출되어야 한다.
- 좋아요/싫어요 개수가 7/3 인 간식 A와
- 60/40 인 간식 B가 있을 때
- A 의 비율은 7/3 = 2.3333
- B 의 비율은 60/40 = 1.5
- 이므로 A 가 B 보다 상위노출 되어야 한다.
---
title: Reaction 집계 Flow with One2Many Table
---
flowchart TD
user[User]
reaction_api[Reaction API]
reaction_db[Reaction Table]
user --> |좋아요 클릭| reaction_api
reaction_api --> |Reaction 기록 get and update or create| reaction_db
reaction_api --> |Reaction 반영 결과 제공| user
---
title: Reaction 집계 Flow with Celery Worker
---
flowchart TD
user[User]
reaction_api[Reaction API]
snack_api[Snack API]
statistics_api[Statistics API]
statistics_db[Order Table Statistics Field]
reaction_db[Reaction Table]
celery_task[Celery Reaction Task]
celery_redis[Celery Worker with Redis]
user --> |좋아요 클릭| reaction_api
reaction_api --> |통계 테이블 업데이트 요청| celery_task
celery_task --> |큐를 거쳐 통계 수치 계산| celery_redis
celery_redis --> |통계 수치 업데이트| statistics_db
user --> |통계 수치 요청| statistics_api
statistics_api --> |통계 수치 쿼리| statistics_db
statistics_db --> |통계 수치 제공| statistics_api
statistics_api --> |통계 수치 응답| user
snack_api --> |통계 수치 쿼리| statistics_db
statistics_db --> |통계 수치 제공| snack_api
user --> |간식 정보 요청| snack_api
snack_api --> |통계 수치 포함된 간식 정보 응답| user
현재 Order 에 속한 Snacks (주문에 포함된 간식) 의 Reaction, 수량 등 다양한 수치가 존재한다. Order 와 연관되어 관리해야하는 로직이 다양하게 발생할 수 있다. 관련된 정책은 아래와 같다.
- 현재 신청하려는 간식 중
기존 주문 중
아직 주문 (배송중 이상) 되지 않은 간식이 있다면 신청할 수 없다.
이를 원활하게 처리하기위해 아래의 방안을 고려한다.
- Order 에 담긴 Snacks 처리 용 Model Mixin
- Order 에 담긴 Snacks 필터링 용 Model Queryset(Manager)
- Order 별 Snack 을 별도 API 로 제공
- Create Order API Request
- not_delivered order 에 속한 간식 탐색
- 현재 신청한 간식 중 위와 중복되는 간식이 존재한다면
- 주문 반려
---
title: 간식 주문 시 중복 간식 검사 시퀀스
---
sequenceDiagram
participant U as User
participant COA as Create Order API View
participant S as Order Write Serializer
participant DB as Database
U->>COA: 신청할 간식 uid, quantity 와 함께 주문
COA->>S: 신청한 간식 목록 데이터 전달
S->>DB: 아직 주문이 완료되지 않은 주문(not_delivered) 에 속한 간식 목록 쿼리
DB-->>S: not_delivered 주문에 속한 간식 목록 응답
S-->>S: 신청 간식 목록과 기 존재 간식 목록 비교
Note over S,DB: 중복 주문된 간식이 존재하지 않도록 벨리데이션
S->>DB: 주문(Order) 생성 및 간식 주문 데이터(Purchase) 생성 쿼리
S-->>COA: 주문 생성 완료 처리
COA-->>U: 주문 완료 Response
주문, 간식 관련 다양한 통계를 제공할 수 있다. 아래의 지표를 통계로 제공한다.
- 상세 목록
- 주기별 주문 목록
- 주기별 간식 목록
- 지표별 수치
- 주기별 주문 수량
- 주기별 간식 수량
- 주기별 주문 금액
- 주기는 연, 월, 일 단위로 제공한다.
- 일 단위 range 형태로 필터링 할 수 있다.
- 2024-1-1 ~ 2024-1-14
- 특정 주기는 별도 인터페이스 를 제공할 수 있다.
- 2024년 1월 1번째주
- 2023년 3월
Order List 를 주기별로 가져올 수 있어야 한다.
- DatetimeField 에 대한 filtering 으로 주기별 목록을 필터링 할 수 있지만, 프론트에서 연동이 복잡해진다.
- EX: Front 에서 지난 2023년 3월 을 지정해 불러오고자 할 때 2023-03-01T00:00:00, 2023-04-01T00:00:00 을 계산하 range 처리해야 한다.
- 백엔드에서 주문 혹은 간식을 등록할 때 year, month, day 값을 별도 field 로 저장 후 filter 에 활용할 수 있다.
- ?year=2023&month=3
- 후자가 활용 면에서 좋고 Read performance 가 좋지만
- 전자는 3개의 필드가 추가되어 데이터가 방대한 경우 많은 손해를 볼 수 있다.
Order 와 연결된 Snack List 를 주기별로 가져올 수 있어야 한다.
- 신청한 간식은 Order 와 연결되어 있으며 Order 의 created_at 을 기준으로 가져오도록 한다.
Cache 는 하드디스크, 메모리 등 빠른 I/O 를 이용한 DB 혹은 시스템에 저장 후 활용하는 방식으로 용도에 맞게 사용하면 성능 및 리소스 효율성을 극대화 할 수 있다.
- 아래와 같이 구성하였으나 Redis Cache 는 메모리 기반 key, valud DB 로 데이터가 휘발성 이기 때문에 Cache 만 사용해서는 오차가 발생할 가능성이 크다.
- Cache 에 해당 간식의 reaction 수치가 존재하지 않으면 DB 를 참조하는 것으로 변경
- 위와 같은 조치로 사실상 cache 사용이 큰 성능상 이득을 가져다 주지는 않을것으로 예상되어 더 나은 대안이 필요하다고 생각됨
---
title: Redis 를 이용한 통계 계산 시퀀스
---
sequenceDiagram
participant U as User
participant TRA as Toggle Reaction API
participant STA as Statistics API
participant S as Toggle Reaction Serializer
participant DB as Database
participant CC as Redis Cache
participant SCHD as Celery Scheduler
U->>TRA: 특정 간식에 좋아요 클릭하여 API 요청
TRA->>S: 좋아요 클릭한 간식 uid, reaction_type 전달
S->>CC: snack_uid 정보 기반으로 캐싱
S->>CC: 현재 기준 리액션 수량 요청
CC-->>S: 현재 기준 리액션 수량 제공
Note over S,CC: 리액션 반영 정보 (snack_uid -> INCR like_count, DECR hate_count)
S-->>TRA: 리액션 반영 완료 처리
TRA-->>U: 리액션 반영 완료 Response
SCHD->>CC: 일정 기간에 업데이트 된 리액션 수량 요청
CC-->>SCHD: 일정 기간에 업데이트 된 리액션 수량 제공
SCHD->>DB: 일정 기간에 업데이트 된 리액션 수량 업데이트
Note over SCHD,DB: 일정 기간 업데이트된 리액션 수량을 DB 에 반영
U->>STA: 통계 수치 요청
STA->>DB: 통계 수치 쿼리
DB-->>STA: 통계 수치 제공
STA-->>U: 통계 수치 Response
Note over U,STA: Scheduler 에 의해 합산된 통계를 프론트에서 활용
- 실시간 트래픽이 굉장히 많은 사이트를 가정해볼 경우 좋아요가 1초에 몇만개 이상 발생할 가능성이 있다.
- 트래픽 발생 시 마다 RDS row 의 값을 update 하는 일은 DB 에 직접적인 영향을 끼친다.
- 또한 단순 개수만이 아닌 누가 눌렀는지도 파악할 수 있어야 한다.
- 이럴 때 Redis 의 Set 을 통해 간단히 구현할 수 있다고 함.
- 댓글 id 를 기준으로 (여기서는 간식 id 일듯) 좋아요를 누른 사용자의 id 를 set에 저장하면 중복 없이 데이터 저장 가능
- 간식 12544 좋아요를 누른 사용자는 345, 25, 967 이다.
---
title: Redis Set 을 이용한 Reaction 구성
---
flowchart LR
key1[snack:like:12544]
key2[snack:like:19967]
subgraph one
345
25
967
end
subgraph two
508
86
167
816
end
key1-->one
key2-->two
SADD snack-like:12544 967
- 각 간식 별로 좋아요를 누른 수는 SCARD 커맨드로 확인할 수 있다.
SCARD snack-like:12544
(integer) 3
- 본 시스템 에서는 좋아요, 싫어요가 존재하며 개별 간식 당 가지는 Redis Set 은 아래와 같다.
snack:like:<snack_id>
snack:hate:<snack_id>
- 단일 사용자가 동일 간식에 동일 리액션을 여러번 남기지 못해야 한다.
- 단일 사용자는 동일 간식에 1개의 리액션만 남길 수 있으며, 좋아요, 싫어요 간 토글이 가능해야 한다.
- 위 두가지 조건을 아래로 해결한다.
- like, hate 모든 리액션 삭제 후 재등록
SREM snack:like:<snack_id> <user_id>
SREM snack:hate:<snack_id> <user_id>
SADD snack:hate:<snack_id> <user_id>
- 등록되어 있지 않아도 삭제하는 낭비가 발생하고 있으나, 검사하는 비용 보다는 덜 들것으로 보임
- 하지만 설계 해 본다.
# 좋아요 체크하는 경우
SISMEMBER snack:like:<snack_id> <user_id>
# 1 이 리턴되면 프로세스 종료
# 0 이 리턴되면
SADD snack:like:<snack_id> <user_id>
SREM snack:hate:<snack_id> <user_id>
# 싫어요 체크하는 경우
SISMEMBER snack:hate:<snack_id> <user_id>
# 1 이 리턴되면 프로세스 종료
# 0 이 리턴되면
SADD snack:hate:<snack_id> <user_id>
SREM snack:like:<snack_id> <user_id>
- 첫번째, 두번째 방법 모두 -> 3번 커맨드
SREM
은 Set 의 크기에 영향을 받을 가능성이 크기 때문에SISMEMBER
를 사용하는 방향으로 하자.
from django_redis import get_redis_connection
redis_con = get_redis_connection('default')
snack_id = snack.id
user_id = user.id
reaction_type = request.data.get('type')
like_key = f'snack:like:{snack_id}'
hate_key = f'snack:hate:{snack_id}'
if reaction_type == ReactionType.LIKE:
if not redis_con.sismember(like_key, user_id):
redis_con.sadd(like_key, user_id)
redis_con.srem(hate_key, user_id)
if reaction_type == ReactionType.HATE:
if not redis_con.sismember(hate_key, user_id):
redis_con.sadd(hate_key, user_id)
redis_con.srem(like_key, user_id)
from django_redis import get_redis_connection
redis_con = get_redis_connection('default')
snack_id = snack.id
like_key = f'snack:like:{snack_id}'
hate_key = f'snack:hate:{snack_id}'
like_count = redis_con.scard(like_key)
hate_count = redis_con.scard(hate_key)
아래의 ERD 는 초기 설계용 이며, 개발이 진행되면서 추가 혹은 삭제되는 요소가 있을 수 있습니다.
---
title: 간식창고 ERD
---
erDiagram
USER ||--o{ ORDER : places
ORDER ||--|{ PURCHASE: contains
SNACK }|--|{ PURCHASE: include
SNACK ||--o{ SNACKREACTION: include
USER {
int id PK
string name
enum type
boolean is_deleted
}
ORDER {
int id PK
int user_id FK
}
PURCHASE {
int id PK
int order_id FK
int snack_id FK
int quantity
}
SNACK {
int id PK
string name
string url
text desc
file image
enum currency
float price
}
SNACKREACTION {
int id PK
int snack_id FK
int user_id FK
enum type
}
.
├── snack
│ ├── core
│ └── order
└── tests
- 사용자 인증 관련 기능
- 서버의 필수 기능 (middleware 등)
- 유틸리티(ex: response json 처리 유틸리티 등)
- 간식 주문 관련 기능
- 간식 관리 기능