taekyoungc c8d1612f0e 운영 Whoops 방지를 위해 메뉴 활성 계산 의존성을 단순화
레이아웃에서 내부 헬퍼 함수를 직접 호출하지 않고 공개 메뉴 매칭 함수만 사용하도록 변경해 운영 환경 차이에 따른 오류 가능성을 줄였습니다.
2026-04-14 00:38:51 +09:00
2026-04-08 15:43:10 +09:00

종량제 -- 쓰레기봉투 물류시스템 (jongryangje)

종량제 개발목록 (엑셀 다운로드) -- 로컬 복제 후에는 assets/종량제_개발목록_20260127.xlsx

지자체/지정판매소 등을 대상으로 하는 종량제 쓰레기봉투 물류/업무 웹 애플리케이션입니다. 백엔드는 CodeIgniter 4 기반입니다.

저장소: wixon-associates/jongryangje | 구현 화면 스크린샷 | Notion 진행상황 | 서버/배포 가이드 |

운영 환경

서비스 URL
웹 서비스 https://trash.wxn.co.kr
Gitea (Git) https://gitea.wxn.co.kr
GitHub https://github.com/wixon-associates/jongryangje

기술 스택

항목 기술
Framework CodeIgniter 4.7+
Language PHP 8.2+ (strict types)
Database MySQL / MariaDB (MySQLi)
의존성 관리 Composer 2.x
E2E 테스트 Playwright (Chromium)
세션 파일 기반 (writable/session/)
프론트엔드 Tailwind CSS (CDN), Vanilla JS

프로젝트 구조

app/
├── Config/              # Routes, Database, Roles, Filters, Session 등 (45개)
├── Controllers/         # 28개 컨트롤러
│   ├── Auth.php         # 로그인/로그아웃/회원가입
│   ├── Bag.php          # 사이트 메뉴 페이지 (기본정보·기본코드 목록 등)
│   ├── Home.php         # 홈/대시보드
│   └── Admin/           # 관리자 컨트롤러 24개
│       ├── BagOrder.php       # 발주 관리
│       ├── BagReceiving.php   # 입고 관리
│       ├── BagInventory.php   # 재고 현황
│       ├── BagSale.php        # 판매/반품 관리
│       ├── BagIssue.php       # 무료용 불출 관리
│       ├── ShopOrder.php      # 주문 접수 관리
│       ├── BagPrice.php       # 봉투 단가 관리
│       ├── PackagingUnit.php  # 포장 단위 관리
│       ├── CodeKind.php       # 기본코드 종류
│       ├── CodeDetail.php     # 세부코드
│       ├── SalesAgency.php    # 판매 대행소
│       ├── Manager.php        # 담당자
│       ├── Company.php        # 업체 (제작/협회/회수)
│       ├── FreeRecipient.php  # 무료용 대상자
│       ├── SalesReport.php    # 리포트 (판매대장/일계표/수불)
│       ├── User.php           # 회원 관리
│       ├── DesignatedShop.php # 지정판매소
│       ├── LocalGovernment.php # 지자체
│       ├── Menu.php           # 메뉴 관리
│       ├── PasswordChange.php # 비밀번호 변경
│       └── ...
├── Models/              # 25개 모델
├── Views/               # 88개 뷰 템플릿
│   ├── admin/           # 관리자 뷰 (59개, 엔티티별 하위 디렉토리)
│   ├── bag/             # 사이트 메뉴 뷰 (17개 + 레이아웃)
│   ├── auth/            # 로그인/회원가입 (2개)
│   └── home/            # 대시보드 (1개)
├── Filters/             # AdminAuthFilter, LoginAuthFilter (`/bag/code-kinds` 등)
├── Helpers/             # admin_helper, pii_encryption_helper
└── Database/            # Migrations, Seeds
public/                  # 웹 루트
writable/database/       # SQL 초기화/시드 스크립트 (21개)
e2e/                     # Playwright E2E 테스트 (84개 테스트)
assets/                  # 기획 문서 (엑셀)

데이터베이스 (25개 테이블)

회원/인증

테이블 용도
member 회원 (mb_id, mb_level, mb_state, PII 암호화, 로그인 실패 lock)
member_log 로그인/로그아웃 감사 로그 (IP, User-Agent)
member_approval_request 회원가입 역할 승인 요청 (pending/approved/rejected)

지자체/판매소

테이블 용도
local_government 지자체 (테넌트 루트, lg_code 기반)
designated_shop 지정판매소 (지자체별, 판매소번호 자동생성)

메뉴 시스템

테이블 용도
menu_type 메뉴 유형 (admin, site)
menu 메뉴 항목 (트리 구조, 역할별 노출, 지자체별)

기본코드 마스터

테이블 용도
code_kind 코드 종류 (A~T, 20종)
code_detail 세부코드 (행정구역, 봉투구분, 재질, 용량 등)

단가/포장

테이블 용도
bag_price 봉투 단가 (발주/도매/소비자가, 적용기간)
bag_price_history 단가 변경 이력
packaging_unit 포장 단위 (박스/팩/낱장)
packaging_unit_history 포장 단위 변경 이력

업체/담당자/대상자

테이블 용도
sales_agency 판매 대행소
company 업체 (manufacturer/association/collector)
manager 담당자 (소속/직위)
free_recipient 무료용 대상자 (생보자/시설/수훈자)

발주/입고/재고

테이블 용도
bag_order 발주 (UUID, LOT번호, SHA-256 해시)
bag_order_item 발주 품목 (봉투코드별 수량/금액)
bag_receiving 입고 (발주 연계, 박스/낱장 수량)
bag_inventory 재고 현황 (봉투코드별 현재 재고)

판매/주문/불출

테이블 용도
bag_sale 판매/반품 (판매소, 봉투코드, 수량/금액)
shop_order 주문 접수 (배달일, 결제/입금/수령 상태)
shop_order_item 주문 품목 (박스/팩/낱장 단위)
bag_issue 무료용 불출 (연도/분기, 불출처, 상태)

역할 체계 (RBAC)

Level 역할 설명
4 Super Admin 전체 시스템 관리, 작업 지자체 선택 필수
3 지자체관리자 소속 지자체 범위 내 관리
2 지정판매소 봉투 판매/재고 관리
1 일반 사용자 기본 조회 (시민)
  • 역할 상수: Config\Roles -- LEVEL_SUPER_ADMIN(4), LEVEL_LOCAL_ADMIN(3), LEVEL_SHOP(2), LEVEL_CITIZEN(1)
  • AdminAuthFilter가 로그인 + 레벨 3/4 + 지자체 선택 여부 검증
  • 기본코드 마스터 CRUDRoles::canManageCodeMaster()(지자체관리자·Super Admin 등)로 제한. 종류·세부 목록 조회는 로그인 사용자 전원 (/bag/code-kinds, /bag/code-details/{ck_idx}, loginAuth 필터)

멀티테넌시

  • local_government.lg_idx가 테넌트 루트
  • 관리자 필터에서 admin_effective_lg_idx() 기반 테넌트 분리
  • Super Admin은 /admin/select-local-government에서 작업 지자체 선택
  • 지자체관리자는 소속 mb_lg_idx 자동 적용

라우트 구조

공개 페이지

경로 설명
/ 홈 (비로그인: 환영, 로그인: 대시보드)
/login, /logout 로그인/로그아웃
/register 회원가입 (역할 승인 플로우)
/dashboard/* 대시보드 시안 (classic/modern/dense/charts)

사이트 메뉴 (/bag/*)

경로 설명 기능
/bag/basic-info 기본정보관리 단가·포장단위 등 링크 허브 (/bag/code-kinds로 기본코드 조회)
/bag/code-kinds 기본코드 종류 종류 목록·세부코드 링크 (조회; CRUD는 관리자만)
/bag/code-details/{ck_idx} 기본코드 세부 해당 종류의 세부코드 목록 (조회; CRUD는 관리자만)
/bag/purchase-inbound 발주 입고 관리 발주/입고 목록 + 등록 버튼
/bag/issue 불출 관리 불출 목록 + 처리/취소
/bag/inventory 재고 관리 봉투별 현재 재고 조회
/bag/sales 판매 관리 주문/판매/반품 + 등록
/bag/sales-stats 판매 현황 기간별 판매 데이터
/bag/flow 봉투 수불 관리 봉투코드별 입출고 수불 요약
/bag/analytics 통계 분석 관리 Phase 6 예정
/bag/window Phase 6 예정
/bag/help 도움말 시스템 안내

관리자 (/admin/*, adminAuth 필터)

시스템 관리

경로 기능
/admin 관리자 대시보드
/admin/users/* 회원 관리 (CRUD)
/admin/access/login-history 로그인 이력
/admin/access/approvals 회원 승인 대기 처리
/admin/roles 역할 목록
/admin/menus/* 메뉴 관리 (트리 CRUD)
/admin/local-governments/* 지자체 관리 (CRUD)
/admin/select-local-government 작업 지자체 선택 (Super Admin)

기본코드 CRUD만 관리자 경로 (목록·조회는 /bag/*)

경로 기능
/admin/code-kinds/* 기본코드 종류 CRUD만 (create/edit/store/update/delete; 목록 없음 — 조회는 /bag/code-kinds)
/admin/code-details/* 세부코드 CRUD만 (목록 없음 — 조회는 /bag/code-details/{ck_idx})
(호환) GET /admin/code-details/{ck_idx} /bag/code-details/{ck_idx} 로 리다이렉트

업무 화면 (/bag/*, adminAuth 필터)

동일 Admin\* 컨트롤러·뷰를 쓰며 메인 사이트 레이아웃으로 렌더된다. GET /admin/managers 등 옛 업무 URL은 301·POST307/bag/...에 리다이렉트된다.

경로 기능
/bag/password-change 비밀번호 변경
/bag/designated-shops/* 지정판매소 관리 (CRUD)
/bag/bag-prices/* 봉투 단가 (CRUD + 이력)
/bag/packaging-units/manage/* 포장 단위 (CRUD + 이력; 조회 전용은 /bag/packaging-units)
/bag/sales-agencies/* 판매 대행소 (CRUD)
/bag/managers/* 담당자 (CRUD)
/bag/companies/* 업체 (CRUD)
/bag/free-recipients/* 무료용 대상자 (CRUD)
/bag/bag-orders/* 발주 관리 (등록/상세/취소/삭제)
/bag/bag-receivings/* 입고 관리 (등록, 재고 자동 반영)
/bag/bag-inventory 재고 현황 조회
/bag/shop-orders/* 주문 접수 (등록/취소)
/bag/bag-sales/* 판매/반품 (등록)
/bag/bag-issues/* 무료용 불출 (등록/취소, 재고 연동)
/bag/reports/sales-ledger 판매 대장 (일자별/기간별)
/bag/reports/daily-summary 일계표 (일계 + 월간 누계)
/bag/reports/period-sales 기간별 판매현황
/bag/reports/supply-demand 봉투 수불 현황

모델 (25개)

모델 테이블 용도
MemberModel member 회원 계정
MemberLogModel member_log 로그인 이력
MemberApprovalRequestModel member_approval_request 승인 요청
LocalGovernmentModel local_government 지자체
DesignatedShopModel designated_shop 지정판매소
MenuModel menu 메뉴 항목
MenuTypeModel menu_type 메뉴 유형
CodeKindModel code_kind 코드 종류
CodeDetailModel code_detail 세부코드
BagPriceModel bag_price 봉투 단가
BagPriceHistoryModel bag_price_history 단가 변경 이력
PackagingUnitModel packaging_unit 포장 단위
PackagingUnitHistoryModel packaging_unit_history 포장 단위 이력
SalesAgencyModel sales_agency 판매 대행소
CompanyModel company 업체
ManagerModel manager 담당자
FreeRecipientModel free_recipient 무료 대상자
BagOrderModel bag_order 발주
BagOrderItemModel bag_order_item 발주 품목
BagReceivingModel bag_receiving 입고
BagInventoryModel bag_inventory 재고
BagSaleModel bag_sale 판매/반품
ShopOrderModel shop_order 주문 접수
ShopOrderItemModel shop_order_item 주문 품목
BagIssueModel bag_issue 무료 불출

보안

항목 구현
인증 세션 기반 로그인, AdminAuthFilter로 관리자 접근 제어, 기본코드 목록 경로는 LoginAuthFilter(loginAuth)
RBAC 4단계 역할 (Config\Roles), 메뉴별 역할 노출
PII 암호화 pii_encryption_helper (AES, ENC: prefix) - 이메일/전화번호
비밀번호 password_hash() + password_verify() (bcrypt)
로그인 보호 5회 실패 시 계정 잠금 (mb_login_fail_count, mb_locked_until)
CSRF CodeIgniter 내장 CSRF 필터
멀티테넌시 lg_idx 기반 데이터 격리, 세션에서 테넌트 관리

빠른 시작

1) 저장소 복제 및 의존성 설치

git clone https://github.com/wixon-associates/jongryangje.git
cd jongryangje
composer install
npm install        # Playwright E2E 테스트용

2) 환경 설정

cp env .env

.env에서 설정:

항목 설명
app.baseURL 예: http://localhost:8045/
database.default.* DB 호스트/DB명/사용자/비밀번호
encryption.key PII 암호화용 64자리 hex

3) 데이터베이스 준비

SQL 스크립트 실행 순서:

순서 파일 용도
1 init_jongryangje_dev.sql DB/사용자 생성
2 login_tables.sql 회원/로그인/지자체/지정판매소 테이블
3 member_approval_request_add.sql 승인 요청 테이블
4 member_login_lock_add.sql 로그인 잠금 컬럼
5 menu_tables.sql 메뉴 시스템 + 시드
6 menu_type_add_site.sql 사이트 메뉴 타입
7 local_government_init_daegu.sql 대구 8개 구군 지자체
8 code_master_init_daegu.sql 기본코드 마스터 (20종)
9 bag_price_tables.sql 단가 + 단가 이력 테이블
10 packaging_unit_tables.sql 포장 단위 + 이력 테이블
11 sales_agency_tables.sql 판매 대행소 테이블
12 manager_tables.sql 담당자 테이블
13 company_tables.sql 업체 테이블
14 free_recipient_tables.sql 무료 대상자 테이블
15 order_tables.sql 발주/발주품목 테이블
16 sales_tables.sql 판매/입고/재고/불출/주문 테이블
17 seed_test_accounts.sql 테스터 계정 4개
18 seed_realistic_data.sql 실제형 시범 데이터

기본코드 전용 보강 (선택·기존 DB): menu_fix_basic_code_link.sql, menu_site_add_basic_code_child.sql, 개발목록 CSV 반영 시 code_master_sync_from_csv.sql 또는 writable/tools/sync_basic_codes_from_csv.py.

4) 개발 서버 실행

php spark serve --port=8045

5) 시드 데이터 (선택)

node e2e/helpers/db-seed.js              # 테스터 계정 생성
node e2e/helpers/db-seed-realistic.js    # 실제형 시범 데이터

E2E 테스트 (Playwright)

# 전체 테스트
npm test

# headed 모드 (브라우저 표시)
npm run test:headed

# 특정 파일
npx playwright test e2e/auth.spec.js

# 특정 테스트
npx playwright test -g "로그인 페이지"

테스터 계정 (비밀번호: test1234!)

ID 역할 Level
tester_badmin 본부 관리자 5
tester_admin Super Admin 4
tester_local 지자체관리자 (중구청) 3
tester_shop 지정판매소 2
tester_user 일반 사용자 1

테스트 파일 (84개 테스트)

파일 테스트 수 대상
auth.spec.js 9 로그인/로그아웃/회원가입
admin.spec.js 10 관리자 패널 접근
public.spec.js 4 공개 페이지
bag-site.spec.js 11 사이트 메뉴 /bag/*
code-management.spec.js 7 기본코드 CRUD (/bag/* 목록 + /admin/* 폼)
bag-price.spec.js 6 봉투 단가
packaging-unit.spec.js 3 포장 단위
phase2-entities.spec.js 8 대행소/담당자/업체/무료대상자
phase2-extra.spec.js 4 지자체 수정/비밀번호/로그인 lock
phase3-order.spec.js 8 발주/입고/재고
phase4-sales.spec.js 10 주문/판매/불출
phase5-reports.spec.js 4 리포트

기본코드 체계

코드 관리 URL·동작

구분 경로 설명
목록·조회 /bag/code-kinds, /bag/code-details/{ck_idx} 사이트(bag) 레이아웃. 시민·판매소는 열람만; 코드 마스터 관리 권한이 있으면 CRUD용 링크(관리자 화면) 노출
등록·수정·삭제 /admin/code-kinds/*, /admin/code-details/* adminAuth + canManageCodeMaster. 처리 후 flash 메시지와 함께 위 bag 목록으로 되돌아감
데이터 보강 (선택) writable/tools/sync_basic_codes_from_csv.py → 생성 SQL 또는 code_master_sync_from_csv.sql 개발목록 CSV와 DB 종류·세부코드 맞출 때 참고

A~T 총 20종의 코드 체계 (code_kind + code_detail):

코드 코드명 코드 코드명
A 도/특별시/광역시 구분 K 반품사유
B 특별시/광역시/시/군코드 L 지정판매소 변경사유
C 구코드 M 수불구분
D 동코드 N 동판종류
E 봉투구분 O 봉투명 (상세 봉투코드)
F 봉투재질 P 작업권한
G 용량별 Q 예산과목
H 무상지급 대상 R 은행목록
I 판매형태 S 소속
J 반품형태 T 직위

개발 진행 현황

Phase별 완료 현황

Phase 내용 상태
Phase 1 프로젝트 초기 세팅, 로그인/회원가입, RBAC, 멀티테넌시, 메뉴 관리, PII 암호화 완료
Phase 2 기본정보관리 (코드/단가/포장/대행소/담당자/업체/무료대상자/지자체수정/비밀번호/로그인lock) 완료
Phase 3 발주/입고/재고 (발주등록/LOT/취소/삭제/현황/입고처리/재고현황) 완료
Phase 4 주문/판매/불출 (주문접수/판매/반품/불출처리/취소) 완료
Phase 5 리포트 (판매대장/일계표/기간별현황/수불현황) 완료
Phase 6 모바일앱 + 고급기능 (바코드/통계/엑셀/인쇄) 대기

Phase 6 이후 대기 작업

  • 지정판매소 다조건 조회 + 엑셀 + 인쇄 + 바코드 출력
  • 지정판매소 지도 표시 / 현황 (신규/취소)
  • 카카오 주소 검색 API 연동
  • 년 판매 현황 (월별/분기별)
  • 지정판매소별 판매현황
  • 홈택스 세금계산서 엑셀 생성
  • 반품/파기 현황, LOT 수불 조회
  • 바코드 스캐너 연동 (Electron + serialport)
  • 실사 선별/등록/조회
  • 페이지네이션/엑셀/인쇄 공통 컴포넌트
  • CRUD 로깅 (전체 데이터 변경 이력)
  • 2차 인증 적용
  • 대시보드 실 데이터 연동
  • 모바일앱 (15개 기능)

SQL 스크립트 목록 (writable/database/)

파일 용도
init_jongryangje_dev.sql DB/사용자 생성
login_tables.sql member, member_log, local_government, designated_shop
member_approval_request_add.sql 승인 요청 테이블
member_login_lock_add.sql 로그인 실패 잠금 컬럼
menu_tables.sql menu_type, menu + admin/site 시드
menu_type_add_site.sql 사이트 메뉴 타입 추가
menu_add_lg_idx.sql 메뉴에 지자체 컬럼 추가
menu_site_seed_from_csv.sql 사이트 네비게이션 시드
local_government_init_daegu.sql 대구 8개 구군 지자체
code_master_init_daegu.sql 기본코드 20종 + 세부코드
menu_fix_basic_code_link.sql 사이트 메뉴에서 기본코드 링크 보정 (기존 DB용, 선택)
menu_site_add_basic_code_child.sql 사이트 메뉴에 기본코드 하위 항목 (선택)
code_master_sync_from_csv.sql CSV 기준 기본코드 보강 (선택)
bag_price_tables.sql bag_price, bag_price_history
packaging_unit_tables.sql packaging_unit, packaging_unit_history
sales_agency_tables.sql sales_agency
manager_tables.sql manager
company_tables.sql company
free_recipient_tables.sql free_recipient
order_tables.sql bag_order, bag_order_item
sales_tables.sql bag_sale, bag_receiving, bag_inventory, bag_issue, shop_order, shop_order_item
seed_test_accounts.sql 테스터 계정 4개
seed_realistic_data.sql 실제형 시범 데이터 (대구 남구청 기준)
fix_double_encoding.sql UTF-8 이중인코딩 수정
Description
종량제 쓰레기봉투 물류시스템
Readme MIT 33 MiB
Languages
PHP 93.5%
JavaScript 4.6%
Hack 1.2%
Python 0.3%
CSS 0.2%
Other 0.1%