이 프로젝트는 음식점 및 매장의 일일 영업 기록을 체계적으로 관리하기 위한 웹 애플리케이션입니다. 기존 스프레드시트 방식의 영업일보를 웹 기반 시스템으로 전환하여, 여러 지점의 데이터를 중앙에서 관리하고 실시간으로 통계를 확인할 수 있도록 구현했습니다.
Express.js를 활용한 RESTful API 구조로 구현하여 확장 가능한 아키텍처를 갖추었으며, Passport.js를 통한 세션 기반 인증 시스템과 역할별 접근 제어를 구현했습니다. MySQL 데이터베이스를 사용하여 영업 데이터를 안전하게 저장하고, Chart.js를 활용한 시각화 기능을 제공합니다.
주요 기능
1. 다중 권한 기반 사용자 관리
시스템은 관리자(admin), 매니저(manager), 직원(staff), 주방(kitchen) 네 가지 권한 레벨을 지원합니다. 각 권한에 따라 접근 가능한 페이지와 기능이 자동으로 제한되며, Passport.js의 Local Strategy를 사용하여 안전한 인증을 구현했습니다.
비밀번호는 bcrypt를 사용하여 해시화하여 저장하며, 세션 관리는 express-mysql-session을 통해 MySQL 데이터베이스에 저장합니다. 계정 활성화/비활성화 기능을 통해 사용자 관리를 유연하게 할 수 있습니다.
2. 영업일보 입력 및 관리
직원 권한 사용자는 일일 영업일보를 입력할 수 있습니다. 현금 매출, 카드 매출, 배달 매출을 구분하여 기록하며, 직원별 급여 정보와 물류 항목을 입력할 수 있습니다. 각 지점별로 설정된 직원 목록과 물류 항목이 자동으로 로드되어 사용자 편의성을 높였습니다.
입력된 데이터는 실시간으로 데이터베이스에 저장되며, 날짜별로 조회 및 수정이 가능합니다. 주방 권한 사용자를 위한 별도의 주방 영업일보 페이지도 제공하여 역할에 맞는 데이터 입력을 지원합니다.
3. 대시보드 및 실시간 통계
관리자와 매니저 권한 사용자는 대시보드를 통해 실시간 매출 통계를 확인할 수 있습니다. 당일 매출, 이번 달 누적 매출, 최근 30일간의 일별 매출 추이를 차트로 시각화하여 제공합니다.
Chart.js를 활용하여 매출 구성(현금/카드/배달)을 원형 차트로 표시하고, 일별 매출 추이를 선 그래프로 표현합니다. 또한 물류 항목별 집계 데이터를 제공하여 비용 관리에도 도움을 줍니다.
4. 월별 통계 및 비고 관리
통계 페이지에서는 특정 월의 상세한 영업 데이터를 확인할 수 있습니다. 월별 매출 합계, 인건비 합계, 물류 비용 등을 섹션별로 구분하여 표시하며, 각 항목에 대한 비고를 추가하여 관리할 수 있습니다.
비고 기능을 통해 특정 월의 특이사항이나 메모를 기록할 수 있으며, 이는 별도의 데이터베이스 테이블에 저장되어 추후 참조가 가능합니다.
5. 관리자 설정 기능
관리자 권한 사용자는 시스템의 다양한 설정을 관리할 수 있습니다. 지점 관리, 사용자 관리, 직원 목록 관리, 물류 항목 관리 등의 기능을 제공합니다.
각 설정 항목은 CRUD 작업을 지원하며, 표시 순서를 조정할 수 있는 기능도 포함되어 있습니다. 사용자 권한 변경, 계정 활성화/비활성화 등의 작업도 관리자 페이지에서 수행할 수 있습니다.
제작 과정
기술 스택
이 프로젝트는 다음과 같은 기술 스택을 사용했습니다:
- 백엔드: Node.js, Express.js
- 데이터베이스: MySQL (mysql2 드라이버 사용)
- 템플릿 엔진: EJS
- 인증: Passport.js (Local Strategy), express-session
- 보안: bcryptjs (비밀번호 해싱)
- 데이터 시각화: Chart.js
- 유틸리티: dayjs (날짜 처리), xlsx (Excel 내보내기), axios (외부 API 호출)
주요 구현 내용
데이터베이스 연결 관리를 위해 자동 재연결 기능을 구현했습니다. MySQL 연결이 끊어졌을 때 자동으로 재연결을 시도하며, 연결 상태를 지속적으로 모니터링합니다. 이를 통해 서버의 안정성을 높였습니다.
권한 기반 접근 제어는 미들웨어 함수로 구현하여 코드 재사용성을 높였습니다. requireLogin(), requireAdmin(), requireNotStaff(), requireKitchen() 등의 미들웨어를 통해 각 라우트에 적절한 권한 체크를 적용했습니다.
보안을 위해 XSS 방지, 프레임 옵션, 콘텐츠 타입 보호 등의 보안 헤더를 설정했으며, 프로덕션 환경에서는 HTTPS를 강제하는 HSTS 헤더도 추가했습니다.
특별히 고민했던 부분
물류 데이터의 경우 JSON 형식으로 저장하여 유연한 데이터 구조를 지원했습니다. 각 지점마다 다른 물류 항목을 사용할 수 있도록 설계했으며, 물류 항목의 추가/삭제/순서 변경이 관리자 페이지에서 가능하도록 구현했습니다.
날씨 정보를 외부 API를 통해 가져와 영업일보에 자동으로 포함시키는 기능을 구현했습니다. 이를 통해 영업 환경에 영향을 주는 날씨 정보를 자동으로 기록할 수 있습니다.
데이터 조회 시 읽기 전용 쿼리와 쓰기 쿼리를 분리하여 데이터베이스 부하를 최적화했습니다. 또한 트랜잭션을 적절히 활용하여 데이터 일관성을 보장했습니다.
작동 방식
화면 흐름
사용자는 로그인 페이지에서 인증 정보를 입력하여 로그인합니다. 로그인 성공 시 사용자의 권한에 따라 자동으로 적절한 페이지로 리다이렉트됩니다. 직원은 영업일보 페이지로, 주방 권한은 주방 영업일보 페이지로, 관리자와 매니저는 대시보드로 이동합니다.
사이드바 네비게이션은 사용자 권한에 따라 동적으로 메뉴가 표시됩니다. 직원 권한은 영업일보 메뉴만, 주방 권한은 주방 영업일보 메뉴만, 관리자와 매니저는 대시보드, 영업일보, 통계, 설정 메뉴가 모두 표시됩니다.
주요 기능별 설명
영업일보 입력 페이지에서는 날짜 선택기를 통해 원하는 날짜의 영업일보를 조회하거나 새로 입력할 수 있습니다. 입력 폼은 여러 섹션으로 나뉘어 있으며, 각 섹션의 데이터는 실시간으로 유효성 검사를 수행합니다.
대시보드에서는 AJAX를 통해 실시간으로 데이터를 가져와 차트를 업데이트합니다. 날짜 범위를 선택하여 특정 기간의 통계를 확인할 수 있으며, 데이터는 서버에서 집계되어 전송됩니다.
통계 페이지에서는 년도와 월을 선택하여 해당 월의 상세 통계를 확인할 수 있습니다. 각 섹션의 비고를 클릭하여 메모를 추가하거나 수정할 수 있으며, 변경사항은 즉시 저장됩니다.
기술적 세부사항
아키텍처
프로젝트는 MVC 패턴을 따르며, Express.js의 라우팅 시스템을 활용하여 RESTful API 구조를 구현했습니다. 뷰는 EJS 템플릿 엔진을 사용하여 서버 사이드 렌더링을 수행하며, 정적 파일은 public 디렉토리에서 제공됩니다.
데이터베이스 쿼리는 Prepared Statement를 사용하여 SQL 인젝션 공격을 방지했으며, 모든 사용자 입력에 대해 유효성 검사를 수행합니다.
데이터베이스 설계
관계형 데이터베이스를 사용하여 지점, 사용자, 영업일보, 통계 비고 등의 데이터를 관리합니다. 지점별로 데이터를 분리하여 다중 지점 운영을 지원하며, 외래키를 활용하여 데이터 무결성을 보장합니다.
세션 데이터는 별도의 세션 스토어를 통해 MySQL에 저장되며, 만료된 세션은 주기적으로 자동 정리됩니다.
보안 구현
Passport.js를 사용한 세션 기반 인증을 구현했으며, 비밀번호는 bcrypt를 사용하여 해시화하여 저장합니다. 세션 쿠키는 httpOnly와 sameSite 옵션을 설정하여 XSS 및 CSRF 공격을 방지했습니다.
모든 API 엔드포인트는 적절한 권한 체크를 수행하며, 인증되지 않은 요청은 자동으로 로그인 페이지로 리다이렉트됩니다. 프로덕션 환경에서는 HTTPS를 사용하도록 설정되어 있습니다.