Hariable는 매장 운영자들이 AI비서를 통해 매장 운영에 관련한 정보들을 대화 형식으로 확인하여 쉽게 매장을 관리할 수 있는 간단한 웹 애플리케이션입니다. 이 프로젝트는 Django 프레임워크를 기반으로 개발되었습니다.
- Hairable은 자영업자들이 24시간 AI 매장 관리 전문가와 소통하며 매장 운영을 더욱 효율적으로 할 수 있도록 지원하는 서비스입니다.
- 프로젝트의 특화 포인트는 GPT 기반 AI 챗봇 기술을 통해 자영업자들이 매장 관리에 관한 문의를 할 때마다 전문적인 답변을 받을 수 있도록 하는 것입니다.
- 기존 유사 서비스와 차별점은 Hairable 챗봇을 통해 실시간 대화 형식으로 매장 관리에 대한 데이터를 얻을 수 있고 알림을 받을 수 있습니다.
- 팀장 : 나지수
- 팀원 : 유정원, 강지석, 조도흠
- 담당튜터 : 신동현
- 최근 인구 감소로 인해 자영업자들이 매장을 운영할 직원을 구하기가 어려워 매장 관리에 어려움을 겪고 있습니다.
- 또한 매장 관리에 필요한 정보들이 많아 매장 관리에 어려움을 겪고 있습니다.
- 이러한 문제를 해결하기 위해 매장 관리를 위한 웹 애플리케이션을 개발하게 되었습니다.
-
재고 관리
- 제품 카테고리 관리
- 재고 아이템 추가, 수정, 삭제
- 재고 수량 및 가치 자동 계산
-
서비스 관리
- 서비스 카테고리 관리
- 서비스 항목 추가, 수정, 삭제
- 서비스별 필요 재고 아이템 관리
-
매장 및 직원 관리
- 매장 정보 관리
- 직원 정보 및 역할 관리
- 직원별 가능 서비스 관리
-
고객 관리
- 고객 정보 관리
- 고객 예약 내역 관리
- 멤버십 상태 관리
-
매출 보고서
- 기간별 매출 보고서 생성
- 수익, 비용, 순이익 계산
- 2024년 9월 23일(월) ~ 2024년 10월 24일(목)
- 프로그래밍 언어: Python
- 프레임워크: Django REST Framework(DRF)
- 데이터베이스 관리 시스템: MySQL
- AI 통합: GPT API를 활용한 지능형 챗봇 기능
- 통합 개발 환경(IDE): Visual Studio Code(VSCode)
- 협업 도구:
- 버전 관리: Git
- 프로젝트 관리: Notion
- 엔드포인트:
/accounts/signup/ - 메소드: POST
- 설명: 새로운 사용자 계정을 생성합니다.
- 요청 데이터:
- username: 사용자 이름 (필수)
- email: 이메일 주소 (필수)
- password: 비밀번호 (필수)
- phone: 전화번호 (필수)
- birthday: 생년월일 (필수)
- gender: 성별 (선택, "M" 또는 "F")
- role: 역할 (필수, "CEO" 또는 "user")
- 응답: 생성된 사용자 정보와 액세스 토큰
- 엔드포인트:
/accounts/login/ - 메소드: POST
- 설명: 사용자 인증 및 토큰 발급
- 요청 데이터:
- username: 사용자 이름 (필수)
- password: 비밀번호 (필수)
- 응답: 액세스 토큰 및 리프레시 토큰
- 엔드포인트:
/accounts/logout/ - 메소드: POST
- 설명: 사용자 로그아웃 및 토큰 무효화
- 요청 데이터:
- refresh: 리프레시 토큰 (필수)
- 응답: 로그아웃 성공 메시지
- 엔드포인트:
/accounts/password-change/ - 메소드: PUT
- 설명: 로그인한 사용자의 비밀번호 변경
- 요청 데이터:
- old_password: 현재 비밀번호 (필수)
- new_password: 새 비밀번호 (필수)
- 응답: 비밀번호 변경 성공 메시지
- 엔드포인트:
/accounts/password-reset/ - 메소드: POST
- 설명: 비밀번호 재설정 이메일 발송 요청
- 요청 데이터:
- email: 사용자 이메일 주소 (필수)
- 응답: 이메일 발송 성공 메시지
- 엔드포인트:
/accounts/password-reset/confirm/<uidb64>/<token>/ - 메소드: POST
- 설명: 이메일로 받은 링크를 통해 새 비밀번호 설정
- 요청 데이터:
- new_password: 새 비밀번호 (필수)
- 응답: 비밀번호 재설정 성공 메시지
- 엔드포인트:
/accounts/userUD/ - 메소드: PUT
- 설명: 로그인한 사용자의 정보 수정
- 요청 데이터:
- email: 이메일 주소 (선택)
- phone: 전화번호 (선택)
- gender: 성별 (선택)
- profile: 프로필 정보 (선택)
- 응답: 수정된 사용자 정보
- 엔드포인트:
/accounts/userUD/ - 메소드: DELETE
- 설명: 로그인한 사용자 계정 비활성화
- 응답: 회원 탈퇴 완료 메시지
- 엔드포인트:
/accounts/profile/ - 메소드: GET
- 설명: 로그인한 사용자의 프로필 정보 조회
- 응답: 사용자 프로필 정보
- 엔드포인트:
/accounts/profile/<int:pk>/ - 메소드: GET
- 설명: 특정 사용자의 프로필 정보 조회
- 응답: 해당 사용자의 프로필 정보
- 엔드포인트:
/stores/ - 메소드: GET
- 설명: 모든 매장 목록 조회
- 응답: 매장 목록 (페이지네이션 적용)
- 엔드포인트:
/stores/<int:pk>/ - 메소드: GET
- 설명: 특정 매장의 상세 정보 조회
- 응답: 매장 상세 정보 (직원 목록 포함)
- 엔드포인트:
/stores/ - 메소드: POST
- 설명: 새로운 매장 생성 (CEO 권한 필요)
- 요청 데이터:
- name: 매장 이름 (필수)
- address: 매장 주소 (필수)
- 응답: 생성된 매장 정보
- 엔드포인트:
/stores/<int:pk>/ - 메소드: PUT
- 설명: 특정 매장 정보 수정 (CEO 권한 필요)
- 요청 데이터:
- name: 매장 이름 (선택)
- address: 매장 주소 (선택)
- 응답: 수정된 매장 정보
- 엔드포인트:
/stores/<int:pk>/ - 메소드: DELETE
- 설명: 특정 매장 삭제 (CEO 권한 필요)
- 응답: 삭제 성공 메시지
- 엔드포인트:
/stores/<int:store_id>/staff/ - 메소드: GET
- 설명: 특정 매장의 직원 목록 조회
- 응답: 직원 목록
- 엔드포인트:
/stores/<int:store_id>/staff/ - 메소드: POST
- 설명: 특정 매장에 새로운 직원 추가
- 요청 데이터:
- user: 사용자 ID (필수)
- role: 역할 (필수, "designer" 또는 "manager")
- phone: 전화번호 (선택)
- 응답: 추가된 직원 정보
- 엔드포인트:
/stores/<int:store_id>/staff/<int:pk>/ - 메소드: PUT
- 설명: 특정 매장 직원의 정보 수정
- 요청 데이터:
- role: 역할 (선택)
- phone: 전화번호 (선택)
- available_services: 제공 가능한 서비스 ID 목록 (선택)
- 응답: 수정된 직원 정보
- 엔드포인트:
/stores/<int:store_id>/staff/<int:pk>/ - 메소드: DELETE
- 설명: 특정 매장에서 직원 삭제
- 응답: 삭제 성공 메시지
- 엔드포인트:
/services/ - 메소드: GET
- 설명: 모든 서비스 목록 조회
- 응답: 서비스 목록 (페이지네이션 적용)
- 엔드포인트:
/services/<int:pk>/ - 메소드: GET
- 설명: 특정 서비스의 상세 정보 조회
- 응답: 서비스 상세 정보
- 엔드포인트:
/services/ - 메소드: POST
- 설명: 새로운 서비스 생성
- 요청 데이터:
- category: 카테고리 ID (필수)
- name: 서비스 이름 (필수)
- price: 가격 (필수)
- duration: 소요 시간 (필수)
- store: 매장 ID (필수)
- 응답: 생성된 서비스 정보
- 엔드포인트:
/services/<int:pk>/ - 메소드: PUT
- 설명: 특정 서비스 정보 수정
- 요청 데이터:
- category: 카테고리 ID (선택)
- name: 서비스 이름 (선택)
- price: 가격 (선택)
- duration: 소요 시간 (선택)
- 응답: 수정된 서비스 정보
- 엔드포인트:
/services/<int:pk>/ - 메소드: DELETE
- 설명: 특정 서비스 삭제
- 응답: 삭제 성공 메시지
- 엔드포인트:
/reservations/ - 메소드: GET
- 설명: 모든 예약 목록 조회
- 응답: 예약 목록 (페이지네이션 적용)
- 엔드포인트:
/reservations/<int:pk>/ - 메소드: GET
- 설명: 특정 예약의 상세 정보 조회
- 응답: 예약 상세 정보
- 엔드포인트:
/reservations/ - 메소드: POST
- 설명: 새로운 예약 생성
- 요청 데이터:
- customer: 고객 ID (필수)
- service: 서비스 ID (필수)
- reservation_time: 예약 시간 (필수)
- assigned_designer: 디자이너 ID (선택)
- 응답: 생성된 예약 정보
- 엔드포인트:
/reservations/<int:pk>/update_status/ - 메소드: PATCH
- 설명: 특정 예약의 상태 수정
- 요청 데이터:
- status: 새로운 상태 (필수, "예약 중", "예약 대기", "예약 취소", "방문 완료" 중 하나)
- new_date: 새로운 예약 날짜 (선택, 예약 중 상태일 때만 변경 가능)
- 응답: 수정된 예약 정보
- 엔드포인트:
/reservations/<int:pk>/ - 메소드: DELETE
- 설명: 특정 예약 삭제
- 응답: 삭제 성공 메시지
- 엔드포인트:
/inventory/ - 메소드: GET
- 설명: 모든 재고 아이템 목록 조회
- 응답: 재고 아이템 목록 (페이지네이션 적용)
- 엔드포인트:
/inventory/<int:pk>/ - 메소드: GET
- 설명: 특정 재고 아이템의 상세 정보 조회
- 응답: 재고 아이템 상세 정보
- 엔드포인트:
/inventory/ - 메소드: POST
- 설명: 새로운 재고 아이템 생성
- 요청 데이터:
- category: 카테고리 ID (필수)
- name: 제품명 (필수)
- purchase_price: 입고가 (필수)
- selling_price: 판매가 (필수)
- usage: 사용 용도 (필수, "SALE", "SERVICE", "STAFF" 중 하나)
- stock: 재고 수량 (필수)
- safety_stock: 안전 재고 수량 (필수)
- storage_location: 보관 장소 (필수)
- 응답: 생성된 재고 아이템 정보
- 엔드포인트:
/inventory/<int:pk>/ - 메소드: PUT
- 설명: 특정 재고 아이템 정보 수정
- 요청 데이터:
- name: 제품명 (선택)
- purchase_price: 입고가 (선택)
- selling_price: 판매가 (선택)
- usage: 사용 용도 (선택)
- stock: 재고 수량 (선택)
- safety_stock: 안전 재고 수량 (선택)
- storage_location: 보관 장소 (선택)
- 응답: 수정된 재고 아이템 정보
- 엔드포인트:
/inventory/<int:pk>/ - 메소드: DELETE
- 설명: 특정 재고 아이템 삭제
- 응답: 삭제 성공 메시지
- 엔드포인트:
/ai-assistant/ - 메소드: POST
- 설명: AI 비서에게 질문하고 응답 받기
- 요청 데이터:
- query: 사용자의 질문 (필수)
- 응답: AI 비서의 응답 내용
Hairable/
├── hairable/
│ ├── accounts/
│ │ ├── migrations/
│ │ ├── init.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── permissions.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── utils.py
│ │ └── views.py
│ ├── hairable/
│ │ ├── init.py
│ │ ├── ai_assistant.py
│ │ ├── asgi.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── inventory/
│ │ ├── migrations/
│ │ ├── init.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── service/
│ │ ├── migrations/
│ │ ├── init.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── stores/
│ │ ├── migrations/
│ │ ├── init.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── permissions.py
│ │ ├── serializers.py
│ │ ├── signals.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── manage.py
│ └── requirements.txt
└── README.md
- MYSQL DB 문제:
- 문제: MYSQL을 사용하여 작성된 코드를 마이그레이션 하는 과정에서 오류 발생
- 해결: MySQL command line client에서 데이터 베이스 초기화 진행
- Gmail SMTP 인증 오류:
- 문제: 이메일 인증 기능 구현 후 테스트 과정에서 Gmail SMTP 인증 오류' 발생
- 해결: 구글 보안 설정에서 2단계 인증 활성화 및 앱 비밀번호 세팅하여 해결
- 기능 문제_ 겸업 방지:
- 문제: 한명의 직원을 여러 매장에 직원으로 등록 가능함
- 해결: StoreStaff 모델에 대해 UniqueConstraint를 적용하여 한 명의 사용자가 여러 매장에 동시에 등록되지 않도록 함. AddStaffView에 이미 등록되어있을 경우 에러 매시지 출력하도록 조치
- 기능 문제_ 권한 설정:
- 문제: 다른 매장의 직원, 예약 등을 조작 가능함
- 해결: 예약 등록 시 매장의 소유자가 현재 사용자인지 확인하고, 다른 CEO가 예약을 등록할 수 없도록 막고ReservationViewSet 클래스의 create() 메서드 수정, 소유한 매장이 아닐경우 매시지 출력하도록 조치
- 기능 문제_ 카테고리 및 재고 미등록 시 안내:
- 문제: 서비스 카테고리 등록 전에 서비스 등록시 서버 다운됨
- 해결: 서비스 등록 시 필수로 제공해야 하는 카테고리나 재고가 누락된 경우, 사용자에게 안내 메시지를 출력하도록 변경, create() 메서드에 로직을 추가. inventory item의 경우 빈칸 허용
- 기능 문제_ 중복된 model 요소 제거:
- 문제: user. staff 혼용으로 오류가 잦음
- 해결: user로 통합
- 기능 문제_ 서비스 목록에서 “해당서비스가 가능한 디자이너” 표시:
- 문제: 가능한 기술로 등록시 서비스 목록에 반영 안됨
- 해결: update 로직에서 service list에도 등록/삭제가 반영되도록 수정
- EC2 문제:
- 문제: ec2 에서 python3 켤때 소문자로 python -v하면 python 라이브러리나 모듈을 불러오는 과정에 대한 디버깅 정보를 출력
- 해결: ec2 에서 python3 켤때 v를 소문자로 할 경우 다른 기능이 실행되므로 꼭 대문자를 사용해야함



