# 종량제 (Jongryangje) - Claude Code 프로젝트 가이드

## 프로젝트 개요

지자체 종량제 쓰레기봉투 물류/유통 관리 웹 애플리케이션

## 기술 스택

- **Framework**: CodeIgniter 4.7+ (PHP 8.2+, strict types)
- **Database**: MySQL/MariaDB (MySQLi 드라이버)
- **의존성 관리**: Composer 2.x
- **테스트**: PHPUnit 10.x
- **세션**: 파일 기반 (`writable/session/`)

## 프로젝트 구조

```
app/
├── Config/          # Routes, Database, Roles, Filters, Session 등
├── Controllers/     # Home, Auth, Admin/* (8개 관리자 컨트롤러)
├── Models/          # MemberModel, LocalGovernmentModel, DesignatedShopModel 등
├── Views/           # admin/, auth/, bag/, home/ 템플릿
├── Filters/         # AdminAuthFilter (관리자 접근 제어)
├── Helpers/         # admin_helper, pii_encryption_helper
└── Database/        # Migrations, Seeds
public/              # 웹 루트
writable/database/   # SQL 초기화 스크립트
tests/               # unit/, database/, session/
assets/              # 기획 문서 (엑셀)
```

## 역할 체계 (RBAC)

| Level | 역할 | 설명 |
|-------|------|------|
| 4 | Super Admin | 전체 시스템 관리, 지자체 선택 필수 |
| 3 | 지자체관리자 | 소속 지자체 범위 내 관리 |
| 2 | 지정판매소 | 봉투 판매/재고 관리 |
| 1 | 일반 사용자 | 기본 조회 |

역할 상수: `Config\Roles` (`LEVEL_SUPER_ADMIN`, `LEVEL_LOCAL_ADMIN`, `LEVEL_SHOP`, `LEVEL_CITIZEN`)

## 멀티테넌시

- `local_government.lg_idx`가 테넌트 루트
- 관리자 필터에서 `session('admin_lg_idx')` 기반 테넌트 분리
- Super Admin은 `/admin/select-local-government`에서 작업 지자체 선택

## 코딩 컨벤션

### PHP

- `declare(strict_types=1)` 모든 PHP 파일 상단
- CodeIgniter 4 네이밍 규칙 준수 (PascalCase 클래스, camelCase 메서드)
- DB 컬럼: snake_case with prefix (`mb_`, `lg_`, `ds_`, `mm_`, `mt_`, `mar_`)
- 모델에서 `$allowedFields` 명시, `$useTimestamps` 활용

### 보안

- PII(이메일, 전화번호)는 `pii_encryption_helper`로 암호화 (`ENC:` prefix)
- 비밀번호: `password_hash()` + `password_verify()` (bcrypt)
- 입력 유효성: CodeIgniter Validation 사용
- `.env` 파일 절대 커밋 금지

### View

- Admin 레이아웃: `admin/layout/main` 기반
- 메뉴: DB 기반 동적 메뉴 (`admin_helper.php`의 `buildMenuTree()`)

## 개발 서버 실행

```bash
php spark serve --port=8045
```

- 로컬에서 **Apache + 여러 VirtualHost + PHP-FPM**을 쓰면 `localhost`·포트·FPM(예: 9001) 설정에 따라 500/503이 나기 쉽습니다. **일상 개발은 위 내장 서버를 기본**으로 두고, `.env`의 `app.baseURL`을 `http://localhost:8045/` 등과 맞추는 것을 권장합니다.

## 테스트 (Playwright E2E)

모든 작업 완료 후 반드시 Playwright 브라우저 테스트를 수행합니다.

```bash
# 전체 테스트
npm test

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

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

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

### 테스트 구조
```
e2e/
├── helpers/
│   ├── auth.js       # 로그인/로그아웃 헬퍼, 테스터 계정 정보
│   └── db-seed.js    # 테스터 계정 DB 시딩 스크립트
├── auth.spec.js      # 인증 테스트 (로그인/로그아웃/회원가입)
├── admin.spec.js     # 관리자 패널 테스트 (지자체관리자/Super Admin)
└── public.spec.js    # 공개 페이지 테스트
```

### 테스터 계정 (비밀번호: `test1234!`)
| ID | 역할 | Level |
|----|------|-------|
| `tester_admin` | Super Admin | 4 |
| `tester_local` | 지자체관리자 (대구) | 3 |
| `tester_shop` | 지정판매소 | 2 |
| `tester_user` | 일반 사용자 | 1 |

### 테스트 규칙
- **작업 완료 시 해당 기능의 E2E 테스트를 반드시 작성/실행**
- 테스트 파일: `e2e/{기능명}.spec.js`
- 공통 로그인은 `e2e/helpers/auth.js`의 `login(page, role)` 사용
- 새 기능 추가 시 해당 페이지 접근 + 주요 CRUD 동작 테스트 작성
- 테스터 계정 시딩: `node e2e/helpers/db-seed.js`

## DB 초기화 순서

1. `writable/database/init_jongryangje_dev.sql` - DB/사용자 생성
2. `writable/database/login_tables.sql` - 기본 테이블
3. `writable/database/member_approval_request_add.sql` - 승인 테이블
4. `writable/database/menu_tables.sql` - 메뉴 시스템
5. `writable/database/local_government_init_daegu.sql` - 대구 시범 데이터
6. `writable/database/code_master_init_daegu.sql` - 코드 마스터

## 주요 라우트

- 공개: `/`, `/login`, `/register`
- 인증: `/dashboard`, `/bag/*`
- 관리자 (`adminAuth` 필터): `/admin/*`

라우트 정의: `app/Config/Routes.php`

## 작업 관리 (jobs.md)

프로젝트 루트의 `jobs.md` 파일로 모든 개발 작업을 추적합니다.

### 세션 시작 시
1. `jobs.md`의 "현재 작업" 섹션을 **반드시 확인**
2. 중단된 작업이 있으면 "이어서 할 것"을 읽고 이어서 진행
3. 없으면 Backlog에서 우선순위 높은 대기 작업 선택

### 작업 수행 시
- **시작**: "현재 작업"에 작업 정보 기록, Backlog 상태를 `진행중`으로 변경
- **완료**: "완료 작업"으로 이동, 작업 로그에 기록
- **중단**: "현재 작업"에 **중단 사유**와 **이어서 할 것**을 반드시 기록
  - 수정한 파일 목록, 현재 브랜치, 다음에 해야 할 구체적 단계를 명시

### 작업 ID 체계
- `P2-xx` ~ `P6-xx`: Phase별 기능 작업
- `CT-xx`: 공통 기술 과제
- 새 작업 추가 시 해당 Phase의 다음 번호 사용

## 주의사항

- 관리자 컨트롤러는 `App\Controllers\Admin` 네임스페이스
- `AdminAuthFilter`가 로그인 + 레벨 3/4 + 지자체 선택 여부 검증
- SQL 마이그레이션 미사용 — `writable/database/` SQL 스크립트 직접 실행
- encryption.key 필요 (64자리 hex) — PII 암호화용
