diff --git a/.gitignore b/.gitignore index 7d9db00..c54b1af 100644 --- a/.gitignore +++ b/.gitignore @@ -173,3 +173,4 @@ blob-report/ /results/ /phpunit*.xml +docs/ diff --git a/docs/2차인증-TOTP-개발계획.md b/docs/2차인증-TOTP-개발계획.md deleted file mode 100644 index 97ae279..0000000 --- a/docs/2차인증-TOTP-개발계획.md +++ /dev/null @@ -1,133 +0,0 @@ -# 2차 인증(TOTP) 개발 계획 - -종량제(쓰레기봉투 물류) 시스템 로그인에 **시간 기반 일회용 암호(TOTP, RFC 6238)** 를 도입하기 위한 계획서입니다. -웹 기능 목록(CSV)의 “로그인 2차 인증” 요구에 대응합니다. - ---- - -## 1. 목표 및 범위 - -| 구분 | 내용 | -|------|------| -| **목표** | 아이디·비밀번호 이후 **인증 앱(Google/Microsoft Authenticator 등)** 6자리 코드로 2차 검증 | -| **범위** | CodeIgniter 4 앱, `session` 기반 로그인(`Auth`), `member` 테이블 | -| **비범위(초기)** | SMS/이메일 OTP, WebAuthn, 공동인증서 연동 | - ---- - -## 2. 정책(적용 대상) - -- **1차 권장:** 관리자 계정만 TOTP **필수** — `mb_level` 지자체 관리자(3), super admin(4), 본부 관리자(5) -- **일반 사용자(1)·지정판매소(2):** 초기에는 **미적용 또는 선택 적용** 검토(지원 부담·UX) -- 최종 정책은 보안/감사 요구에 맞춰 `Roles` 또는 설정으로 **한 함수에 모아** 판단 (`needsTotpForMember()` 등) - ---- - -## 3. 사용자 흐름 - -### 3.1 로그인 - -1. 기존과 동일: `login_id`, `password`, 승인 상태 검증 -2. **TOTP 대상**이고 시크릿이 **등록됨**(`mb_totp_enabled = 1`): - - `logged_in` **세팅하지 않음** - - 세션에 `pending_2fa`, `pending_mb_idx`, (선택) 만료 시각만 저장 - - `GET /login/two-factor` 로 이동 → 6자리 입력 → 검증 성공 시 기존과 동일 세션 + `mb_latestdate` 갱신 -3. **TOTP 대상**인데 **미등록:** - - 정책 A: 최초 로그인 시 **시크릿 생성 + QR 표시** → 확인 코드 1회 검증 후 `mb_totp_enabled = 1` - - 정책 B: 관리자가 수동으로 등록 유도(별도 화면) - -### 3.2 로그아웃 - -- `pending_2fa` 등 임시 키 **반드시 제거** - -### 3.3 인증 앱 - -- 표준 TOTP 앱이면 동일 시크릿으로 사용 가능(Google / Microsoft Authenticator 등) - ---- - -## 4. 데이터베이스 - -`member` 테이블에 컬럼 추가(예시): - -| 컬럼명 | 타입 | 설명 | -|--------|------|------| -| `mb_totp_secret` | `VARBINARY` 또는 `TEXT` | Base32 시크릿 — **저장 시 암호화** 권장(`encryption.key` 등) | -| `mb_totp_enabled` | `TINYINT(1)` | 0=미사용, 1=등록 완료·로그인 시 검증 대상 | - -선택: - -- `mb_totp_enabled_at` — 감사 -- **백업 코드** — 별도 테이블 또는 컬럼에 **일회용 코드의 해시만** 저장 - -DDL은 `writable/database/` 에 `member_add_totp.sql` 등으로 관리 가능. - ---- - -## 5. 기술 스택 - -- **TOTP 생성·검증:** Composer 패키지 (예: `spomky-labs/otphp` 또는 `robthree/twofactorauth`) -- **QR(otpauth URI):** 라이브러리 또는 URL 문자열만 표시 후 앱 수동 입력 -- **시크릿 보관:** 평문 DB 저장 지양, CI `Encrypter` 또는 기존 PII 암호화 헬퍼와 동일 정책 - ---- - -## 6. 코드 변경 요약 - -| 영역 | 작업 | -|------|------| -| `app/Config/Routes.php` | `login/two-factor` GET·POST, (선택) `setup` 라우트 | -| `app/Controllers/Auth.php` | 로그인 분기, 2단계 검증 액션, 로그아웃 시 pending 제거 | -| `app/Models/MemberModel.php` | `allowedFields` 확장 | -| 신규 뷰 | `auth/login_two_factor.php`, (선택) `auth/totp_setup.php` | -| `app/Config/` | (선택) `Auth.php` 또는 기존 설정에 `requireTotp` 등 | -| `app/Filters/` | `pending_2fa` 상태에서는 보호 URL 접근 불가(원칙상 `logged_in` 없음으로 자연 차단, 허용 화이트리스트만 정리) | -| `writable/database/*.sql` | 마이그레이션/ALTER | - -기존 `MemberLogModel`에 “2차 성공/실패” 구분 기록 여부 결정. - ---- - -## 7. 개발 환경에서 2FA 생략 - -- `.env` 예: `auth.requireTotp = false` (로컬만) -- 운영/스테이징: `true` -- 로직: `비밀번호 검증 성공` 후 `needsTotp && config('Auth')->requireTotp` 일 때만 2단계로 보냄 -- **운영에 `false`가 배포되지 않도록** CI·배포 체크리스트에 포함 - ---- - -## 8. 보안·운영 - -- TOTP 검증 **실패 횟수 제한** 및 짧은 잠금(브루트포스 방지) -- 시간 윈도우: 라이브러리 기본(예: ±1 step) 및 서버 NTP 권장 -- 기기 분실: **백업 코드** 또는 관리자 **시크릿 재발급(감사 로그)** 절차 -- `admin_selected_lg_idx` 등 기존 세션은 **2차 완료 후**에만 의미 있게 유지 - ---- - -## 9. 테스트 시나리오(초안) - -1. TOTP 미등록 관리자 — 등록 플로우 후 로그인 성공 -2. TOTP 등록 관리자 — 잘못된 코드 거부, 올바른 코드 성공 -3. 일반 사용자 — 정책에 따라 2단계 생략 확인 -4. `requireTotp = false` — 개발 모드에서 1단계만으로 `logged_in` -5. 로그아웃 — `pending_2fa` 잔존 없음 - ---- - -## 10. 구현 단계(제안) - -| 단계 | 내용 | -|------|------| -| **Phase 1** | DB 컬럼, 패키지, 시크릿 생성·저장·검증 유틸, 관리자만 TOTP 필수 | -| **Phase 2** | 등록 UI(QR), 백업 코드 또는 재설정 프로세스 | -| **Phase 3** | 일반 사용자 확대·정책 조정, 로그/감사 보강 | - ---- - -## 11. 참고 - -- 역할 상수: `app/Config/Roles.php` -- 현재 로그인 완료 지점: `app/Controllers/Auth.php` (세션에 `logged_in` 설정) -- 기존 내부 문서는 `docs/` 에 둘 수 있으나 **현재 `.gitignore`에 포함**되어 저장소에는 올라가지 않음. 팀 저장소 공유용으로 본 파일은 `documentation/` 에 둠. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 621860c..0000000 --- a/docs/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# 종량제 프로젝트 문서 (docs) - -Cursor AI 및 개발자가 **작업 내역·기능 요구사항**을 파악할 수 있도록, CSV로 업로드된 기능 요구사항을 정리한 문서입니다. - ---- - -## 문서 목차 - -| 파일 | 내용 | -|------|------| -| **00-project-overview.md** | 프로젝트 개요, 사용자 권한, 문서 구성 | -| **01-web-features.md** | 웹 기능 목록 63건 (SFR-PWB-001 ~ 011, 대분류별 요약) | -| **02-mobile-features.md** | 모바일앱 기능 목록 15건 (PDF417 스캔·권한별) | -| **03-basic-codes.md** | 기본코드 종류 A~Y (지역·봉투·수불·판매 등) | -| **04-menu-structure.md** | 전체 메뉴 구조 (1차정리/SMT) | -| **05-meeting-notes.md** | 회의 내용 참고 (스캐너·재고·전화접수·단가·바코드 등) | -| **06-development-plan.md** | 앞으로의 개발 계획 (단계별 Phase 1~11) | -| **07-local-db-setup.md** | 로컬 DB 설정 (MariaDB 설치·DB 생성·.env) | - ---- - -## 원본 자료 - -- `종량제_개발목록_20260127(웹 기능목록).csv` -- `종량제_개발목록_20260127(모바일앱 기능목록).csv` -- `종량제_개발목록_20260127(기본코드 종류).csv` -- `종량제_개발목록_20260127(전체 메뉴 - 1차정리).csv` / `(전체 메뉴 - SMT).csv` -- `종량제_개발목록_20260127(회의 내용 참고).csv` - -위 CSV는 기준일 2024-08-19, 개발목록 기준 2026-01-27 문서를 요약·정리한 것입니다. diff --git a/docs/SCREENSHOTS.md b/docs/SCREENSHOTS.md deleted file mode 100644 index 789c62b..0000000 --- a/docs/SCREENSHOTS.md +++ /dev/null @@ -1,92 +0,0 @@ -# 종량제 — 구현 화면 스크린샷 - -> 2026-03-25 기준 구현 완료된 전체 화면 캡처 - ---- - -## 공개 페이지 - -### 홈페이지 (`/`) -![홈페이지](../screenshots/01_home.png) - -### 로그인 (`/login`) -![로그인](../screenshots/02_login.png) - -### 회원가입 (`/register`) -![회원가입](../screenshots/03_register.png) - ---- - -## 관리자 — Super Admin - -### 지자체 선택 (`/admin/select-local-government`) -Super Admin 로그인 시 첫 화면. 작업할 지자체를 선택해야 관리자 기능 사용 가능. -![지자체 선택](../screenshots/04_admin_select_lg.png) - -### 관리자 대시보드 (`/admin`) -![관리자 대시보드](../screenshots/05_admin_dashboard.png) - -### 회원 관리 (`/admin/users`) -전체 회원 목록 조회. 역할, 상태, 승인 상태 확인 가능. -![회원 관리](../screenshots/06_admin_users.png) - -### 회원 등록 (`/admin/users/create`) -관리자가 직접 회원을 등록하는 화면. 역할 및 지자체 지정 가능. -![회원 등록](../screenshots/07_admin_users_create.png) - -### 로그인 이력 (`/admin/access/login-history`) -전체 로그인 성공/실패 이력. 기간별 조회 가능. -![로그인 이력](../screenshots/08_admin_login_history.png) - -### 승인 대기 (`/admin/access/approvals`) -회원가입 승인 요청 목록. 승인/거절 처리. -![승인 대기](../screenshots/09_admin_approvals.png) - -### 역할 관리 (`/admin/roles`) -시스템 역할 목록 조회 (4단계 RBAC). -![역할 관리](../screenshots/10_admin_roles.png) - -### 메뉴 관리 (`/admin/menus`) -트리 구조 메뉴 CRUD. 관리자/사이트 메뉴 분리, 역할별 노출 설정. -![메뉴 관리](../screenshots/11_admin_menus.png) - -### 지자체 관리 (`/admin/local-governments`) -Super Admin 전용. 등록된 지자체 목록. -![지자체 관리](../screenshots/12_admin_local_governments.png) - -### 지자체 등록 (`/admin/local-governments/create`) -![지자체 등록](../screenshots/13_admin_lg_create.png) - -### 지정판매소 관리 (`/bag/designated-shops`) -현재 지자체 소속 지정판매소 목록. -![지정판매소 관리](../screenshots/14_admin_designated_shops.png) - -### 지정판매소 등록 (`/bag/designated-shops/create`) -판매소번호 자동생성, 상세 정보 입력. -![지정판매소 등록](../screenshots/15_admin_ds_create.png) - ---- - -## 사용자 화면 - -### 일일 봉투 수불현황 — 대시보드 (`/dashboard`) -로그인 후 기본 화면. -![대시보드](../screenshots/16_user_dashboard.png) - -### 클래식 대시보드 (`/dashboard/classic-mock`) -![클래식 대시보드](../screenshots/17_dashboard_classic.png) - -### 모던 대시보드 (`/dashboard/modern`) -![모던 대시보드](../screenshots/18_dashboard_modern.png) - -### 밀집형 대시보드 (`/dashboard/dense`) -![밀집형 대시보드](../screenshots/19_dashboard_dense.png) - -### 차트 대시보드 (`/dashboard/charts`) -![차트 대시보드](../screenshots/20_dashboard_charts.png) - -### 재고 조회 (`/bag/inventory-inquiry`) -![재고 조회](../screenshots/21_bag_inventory.png) - -### 봉투 수불현황 (`/bag/waste-suibal-enterprise`) -![봉투 수불현황](../screenshots/22_bag_waste_suibal.png) diff --git a/docs/ai용 개발계획/관리자단_개발_설계.md b/docs/ai용 개발계획/관리자단_개발_설계.md deleted file mode 100644 index 787d805..0000000 --- a/docs/ai용 개발계획/관리자단_개발_설계.md +++ /dev/null @@ -1,244 +0,0 @@ -# 관리자단 기능 개발 설계서 - -> 웹 기능목록 CSV(관리자단 PWB-020000) 기준 · Auth 프로젝트와 동일한 방식으로 구현 - -**참조 CSV**: `docs/종량제 관련 자료/종량제 개발목록/종량제_개발목록_20260127(웹 기능목록) (1).csv` -**참조 구현**: `app/Controllers/Auth.php`, `app/Views/auth/`, `app/Models/MemberModel.php`, `app/Config/Routes.php` - ---- - -## 1. Auth 프로젝트 구조 (참조 패턴) - -### 1.1 디렉터리/파일 구조 - -``` -app/ -├── Controllers/ -│ └── Auth.php # showLoginForm, login, logout, showRegisterForm, register -├── Models/ -│ ├── MemberModel.php # 회원 CRUD, findByLoginId -│ └── MemberLogModel.php # 로그인 이력 -├── Views/ -│ └── auth/ -│ ├── login.php # 로그인 폼 -│ └── register.php # 회원가입 폼 -└── Config/ - └── Routes.php # login, logout, register 라우트 -``` - -### 1.2 네이밍 규칙 - -| 구분 | 규칙 | 예시 | -|------|------|------| -| 컨트롤러 | PascalCase, 단수/역할명 | `Auth`, `Home` | -| 메서드 | camelCase, 동사+명사 | `showLoginForm`, `login` | -| 뷰 폴더 | 컨트롤러명 소문자 | `auth/`, `home/` | -| 뷰 파일 | 소문자+언더스코어 | `login.php`, `register.php` | -| 라우트 URI | 소문자, 케밥 또는 경로 | `login`, `logout`, `register` | -| 모델 | PascalCase + Model | `MemberModel`, `MemberLogModel` | - -### 1.3 라우트 패턴 (Auth 기준) - -```php -// GET = 폼 표시 (showXxxForm 또는 index) -// POST = 처리 (login, register) -$routes->get('login', 'Auth::showLoginForm'); -$routes->post('login', 'Auth::login'); -$routes->get('logout', 'Auth::logout'); -$routes->get('register', 'Auth::showRegisterForm'); -$routes->post('register', 'Auth::register'); -``` - -### 1.4 컨트롤러 메서드 패턴 - -- **폼 표시**: `showXxxForm()` → `return view('auth/xxx');` -- **처리**: `xxx()` → 유효성 검사 → Model 호출 → `redirect()->to(...)->with(...)` -- **유효성**: `$this->validate($rules, $messages)` 사용 -- **에러 시**: `redirect()->back()->withInput()->with('errors', ...)` - -### 1.5 뷰 공통 사항 - -- `base_url()`, `csrf_field()`, `esc()`, `old()` 사용 -- 플래시: `session()->getFlashdata('success')`, `getFlashdata('error')`, `getFlashdata('errors')` - ---- - -## 2. 관리자단 기능 목록 (CSV 매핑) - -| No | SFR 2레벨 | SFR 3레벨 | 기능 ID | 기능명 | 비고 | -|----|-----------|-----------|---------|--------|------| -| 4 | PWB-020100 | PWB-020101 | PWB-020101-001 | 사용자 권한 관리 | 권한 등록/수정/삭제, 역할별 설명 | -| 5 | PWB-020200 | PWB-020201 | PWB-020201-001 | 사용자 관리 | 사용자 등록/수정/삭제(삭제상태 5년 유지) | -| 6 | PWB-020300 | PWB-020301 | PWB-020301-001 | 사용자 로그인 이력 확인 | 기간 지정 조회 | -| 7 | PWB-020300 | PWB-020301 | PWB-020301-001 | 사용자 권한 승인 | 브라우저 회원가입 시 권한 승인 루틴 | -| 8 | PWB-020400 | PWB-020401 | PWB-020401-001 | 메뉴 관리 | 메뉴 등록/수정/삭제, "전체 메뉴" 시트 참고 | -| 9 | PWB-020400 | PWB-020401 | PWB-020401-001 | 메뉴 별 권한 설정 | 메뉴별 사용자 접근 권한 설정 | - ---- - -## 3. 관리자단 구현 설계 (Auth 방식 적용) - -### 3.1 URL/라우트 구조 - -관리자 전용 prefix `admin` 사용, 인증 필터 적용 대상. - -``` -admin/ # 관리자 대시보드 (선택) -admin/users # 사용자 관리 목록 (GET) -admin/users/create # 사용자 등록 폼 (GET) -admin/users/store # 사용자 등록 처리 (POST) -admin/users/(:num)/edit # 사용자 수정 폼 (GET) -admin/users/(:num)/update # 사용자 수정 처리 (POST) -admin/users/(:num)/delete # 사용자 삭제(상태변경) (POST) - -admin/roles # 사용자 권한 관리 (목록/등록/수정/삭제) -admin/roles/create -admin/roles/store -admin/roles/(:num)/edit -admin/roles/(:num)/update -admin/roles/(:num)/delete - -admin/access # 사용자 접근 관리 (하위: 로그인이력, 권한승인) -admin/access/login-history # 로그인 이력 조회 (GET, 기간 조건) -admin/access/approvals # 권한 승인 대기 목록 (GET) -admin/access/approvals/(:num) # 권한 승인/반려 처리 (POST) - -admin/menus # 메뉴 관리 (목록/등록/수정/삭제) -admin/menus/create -admin/menus/store -admin/menus/(:num)/edit -admin/menus/(:num)/update -admin/menus/(:num)/delete -admin/menus/permissions # 메뉴별 권한 설정 -``` - -### 3.2 컨트롤러 구성 (Auth와 동일 패턴) - -| 컨트롤러 | 파일 | 역할 | 주요 메서드 | -|----------|------|------|-------------| -| Admin\Dashboard | `Controllers/Admin/Dashboard.php` | 관리자 첫 화면 | `index()` | -| Admin\User | `Controllers/Admin/User.php` | 사용자 관리 | `index()`, `create()`, `store()`, `edit($id)`, `update($id)`, `delete($id)` | -| Admin\Role | `Controllers/Admin/Role.php` | 사용자 권한 관리 | `index()`, `create()`, `store()`, `edit($id)`, `update($id)`, `delete($id)` | -| Admin\Access | `Controllers/Admin/Access.php` | 접근 관리 | `loginHistory()`, `approvals()`, `approve($id)`, `reject($id)` | -| Admin\Menu | `Controllers/Admin/Menu.php` | 메뉴 관리 | `index()`, `create()`, `store()`, `edit($id)`, `update($id)`, `delete($id)`, `permissions()` | - -- **목록/폼**: GET → `view('admin/xxx/yyy')` -- **저장/수정/삭제**: POST → `validate` → Model → `redirect()->to(...)->with(...)` -- **에러**: `redirect()->back()->withInput()->with('errors', ...)` (Auth와 동일) - -### 3.3 모델 구성 - -| 모델 | 파일 | 테이블 | 비고 | -|------|------|--------|------| -| MemberModel | (기존) | member | 사용자 관리에서 재사용 | -| MemberLogModel | (기존) | member_log | 로그인 이력에서 재사용 | -| RoleModel | `Models/RoleModel.php` | role (신규) | 권한/역할 마스터 | -| MenuModel | `Models/MenuModel.php` | menu (신규) | 메뉴 마스터 | -| MenuPermissionModel | `Models/MenuPermissionModel.php` | menu_permission (신규) | 메뉴별 권한 | - -- `member.mb_level`은 `Roles` 설정과 연동 유지. -- 권한 테이블(role)이 있으면 `member.mb_level`과 매핑 또는 확장. - -### 3.4 뷰 디렉터리 구조 - -``` -app/Views/ -└── admin/ - ├── layout.php # 관리자 공통 레이아웃 (선택) - ├── dashboard/ - │ └── index.php - ├── user/ - │ ├── index.php # 목록 - │ ├── create.php # 등록 폼 - │ └── edit.php # 수정 폼 - ├── role/ - │ ├── index.php - │ ├── create.php - │ └── edit.php - ├── access/ - │ ├── login_history.php # 로그인 이력 조회 - │ └── approvals.php # 권한 승인 목록/처리 - └── menu/ - ├── index.php - ├── create.php - ├── edit.php - └── permissions.php # 메뉴별 권한 설정 -``` - -- 공통: `base_url()`, `csrf_field()`, `esc()`, `old()`, 플래시 메시지 (Auth와 동일). - -### 3.5 인증/권한 - -- **관리자 구분**: `mb_level`이 `Roles::LEVEL_SUPER_ADMIN` 또는 `LEVEL_LOCAL_ADMIN`인 경우만 `admin/*` 접근 허용. -- **필터**: `app/Config/Filters.php`에 `adminAuth` 등 필터 등록 후, `admin/*` before에 적용. -- **필터 내부**: `session()->get('logged_in')` 및 `session()->get('mb_level')` 확인 후 미인증/비관리자면 `redirect()->to('login')` 또는 전용 에러 페이지. - ---- - -## 4. Routes.php 등록 예시 - -```php -// 관리자단 (admin prefix, 인증 필터 적용) -$routes->group('admin', ['filter' => 'adminAuth'], static function ($routes) { - $routes->get('/', 'Admin\Dashboard::index'); - $routes->get('users', 'Admin\User::index'); - $routes->get('users/create', 'Admin\User::create'); - $routes->post('users/store', 'Admin\User::store'); - $routes->get('users/(:num)/edit', 'Admin\User::edit/$1'); - $routes->post('users/(:num)/update', 'Admin\User::update/$1'); - $routes->post('users/(:num)/delete', 'Admin\User::delete/$1'); - - $routes->get('roles', 'Admin\Role::index'); - $routes->get('roles/create', 'Admin\Role::create'); - $routes->post('roles/store', 'Admin\Role::store'); - $routes->get('roles/(:num)/edit', 'Admin\Role::edit/$1'); - $routes->post('roles/(:num)/update', 'Admin\Role::update/$1'); - $routes->post('roles/(:num)/delete', 'Admin\Role::delete/$1'); - - $routes->get('access/login-history', 'Admin\Access::loginHistory'); - $routes->get('access/approvals', 'Admin\Access::approvals'); - $routes->post('access/approvals/(:num)', 'Admin\Access::approve/$1'); - - $routes->get('menus', 'Admin\Menu::index'); - $routes->get('menus/create', 'Admin\Menu::create'); - $routes->post('menus/store', 'Admin\Menu::store'); - $routes->get('menus/(:num)/edit', 'Admin\Menu::edit/$1'); - $routes->post('menus/(:num)/update', 'Admin\Menu::update/$1'); - $routes->post('menus/(:num)/delete', 'Admin\Menu::delete/$1'); - $routes->get('menus/permissions', 'Admin\Menu::permissions'); - $routes->post('menus/permissions', 'Admin\Menu::savePermissions'); -}); -``` - -- `adminAuth`는 별도 필터 클래스에서 로그인 + 관리자 레벨 체크. - ---- - -## 5. 구현 순서 제안 - -1. **관리자 필터** - - `Filters.php`에 `adminAuth` 등록, 필터 클래스에서 `logged_in` + `mb_level` 검사. -2. **사용자 관리 (PWB-020201)** - - `Admin\User` 컨트롤러, `admin/user` 뷰, 기존 `MemberModel` 활용. - - 삭제는 상태값 변경, 5년 유지 정책은 정책/스케줄로 처리. -3. **사용자 권한 관리 (PWB-020101)** - - `Role` 테이블/모델 정비, `Admin\Role` 컨트롤러·뷰. - - `member.mb_level`과 역할 매핑 유지. -4. **사용자 접근 관리 (PWB-020301)** - - 로그인 이력: `Admin\Access::loginHistory`, 기간 조건, `MemberLogModel` 조회. - - 권한 승인: 대기 목록용 테이블/플로우 정한 뒤 `approvals`, `approve`/`reject` 구현. -5. **메뉴 관리 (PWB-020401)** - - `menu`, `menu_permission` 테이블, `MenuModel`, `MenuPermissionModel`. - - `Admin\Menu` CRUD + `permissions`/`savePermissions`. - ---- - -## 6. 정리 - -- **웹 기능목록 CSV**의 관리자단(No 4~9)을 **Auth와 같은 방식**으로 구현한다. -- **컨트롤러**: GET은 폼/목록, POST는 처리; 유효성 검사 후 Model 호출, 실패 시 `redirect()->back()->withInput()->with('errors', ...)`. -- **뷰**: `auth`와 동일하게 `base_url()`, `csrf_field()`, `esc()`, `old()`, 플래시 메시지 사용. -- **라우트**: `admin` 그룹 + 필터로 인증/권한 통제. -- **모델**: 기존 Member/MemberLog 활용하고, 권한·메뉴·메뉴권한은 신규 테이블/모델로 추가. - -이 설계에 따라 단위 기능별로 Controller → Model → View → Route 순으로 구현하면 Auth와 일관된 관리자단을 만들 수 있다. diff --git a/docs/portfolio-jongryangje.md b/docs/portfolio-jongryangje.md deleted file mode 100644 index 0240874..0000000 --- a/docs/portfolio-jongryangje.md +++ /dev/null @@ -1,44 +0,0 @@ -# 종량제(Jongryangje) — 포트폴리오 소개 - -## 한 줄 요약 (채용 담당자용) - -지자체 **종량제 봉투 유통·재고·매출**을 다루는 **웹 시스템**을 **기획·디자인부터 구현까지** 주도했습니다. 백엔드는 **PHP(CodeIgniter 4)**, **역할·지자체별 데이터 분리**, **보안·자동 테스트**를 전제로 두었고, UI 초안에는 **Stitch**(Google), 개발 보조에는 **Cursor**를 사용했습니다. - ---- - -## 프로젝트 소개 - -**종량제(Jongryangje)**는 지자체 단위 **봉투 판매·재고·보고**를 한곳에서 처리하는 **관리·조회 웹앱**입니다. 시민·판매소·관리자 등 **역할에 맞는 화면**으로 업무 데이터를 나누고, **지자체별로 데이터 범위를 분리**합니다. - -**세부 기획과 디자인**은 본인이 맡았습니다. 화면 흐름과 정보 구조를 정하고, **Stitch**로 시안·레이아웃을 빠르게 시도한 뒤 실제 화면은 **코드로 맞춰 반영**했습니다. - -**Cursor**로는 구조 파악·반복 코드 초안·디버깅 단서에 시간을 썼고, **권한·민감정보·배포·요구사항 일치**는 **직접 검증**했습니다. - -*(스크린샷 1~2장을 넣으면 좋습니다.)* - ---- - -## 프로젝트 하이라이트 - -| 초점 | 한 줄 | -| --- | --- | -| **역할** | 기획·디자인(Stitch)·풀스택 구현·품질 확인까지 **엔드투엔드 소유권**이 있습니다. | -| **제품 구조** | **역할별 접근**과 **지자체(테넌트) 단위 분리**를 전제로 설계했습니다. | -| **품질·보안** | 민감정보 보호·관리자 통제, **브라우저 자동 테스트(E2E)**로 주요 흐름을 검증합니다. | -| **도구** | Stitch·Cursor는 **속도**용이며, **최종 판단과 동작 보증은 본인**이 합니다. | - ---- - -## 서비스 범위 (간단히) - -**봉투 입출고·가격·코드 마스터·보고·관리자/현장 화면** 등 **기관 운영에 필요한 기능 묶음**을 웹으로 제공합니다. 세부 메뉴명·화면별 스펙은 포트폴리오 분량에서 생략합니다. - ---- - -## 기술·도구 (요약) - -**PHP 8 + CodeIgniter 4**, **MySQL/MariaDB**, 서버 렌더링 기반 화면, **PHPUnit·Playwright** 등으로 테스트합니다. 기획·UI 탐색 **Stitch**, 코딩 보조 **Cursor**. - ---- - -*기관명·저장소 링크·캡처는 공개 범위에 맞게 조정하시면 됩니다.* diff --git a/docs/server.md b/docs/server.md deleted file mode 100644 index 8543863..0000000 --- a/docs/server.md +++ /dev/null @@ -1,286 +0,0 @@ -# 서버 인프라 / 배포 가이드 - -## 접속 정보 요약 - -| 서비스 | URL | 계정 | -|--------|-----|------| -| 웹 서비스 | https://trash.wxn.co.kr | (아래 테스트 계정 참조) | -| Gitea | https://gitea.wxn.co.kr | `wixon` / `wixon1234!` | -| SSH | `ssh wixon@116.122.157.166` | `wixon` / `1111` | - -### 웹 테스트 계정 (비밀번호: `test1234!`) - -| ID | 역할 | Level | 소속 | -|----|------|-------|------| -| `tester_admin` | Super Admin | 4 | 전체 (지자체 선택 필요) | -| `tester_local` | 지자체관리자 | 3 | 중구청 | -| `tester_shop` | 지정판매소 | 2 | - | -| `tester_user` | 일반 사용자 | 1 | - | - ---- - -## 1. 서버 환경 - -| 항목 | 값 | -|------|------| -| IP | `116.122.157.166` | -| OS | Ubuntu 22.04.5 LTS | -| 호스팅 | 카페24 (`qm391-0435.cafe24.com`) | -| PHP | 8.2.30 (PHP-FPM) | -| nginx | 호스트 설치 (80/443/8045) | -| Docker | 28.5.1 | -| DB | MySQL (원격 `3.36.27.239`) | - ---- - -## 2. 서비스 구조 - -``` - ┌─── https://trash.wxn.co.kr -[클라이언트] ─── nginx ───┤ - (80/443) └─── https://gitea.wxn.co.kr - │ │ - ▼ ▼ - nginx (8045) Gitea Docker (3001) - │ - PHP-FPM 8.2 - │ - CodeIgniter 4 - │ - MySQL 3.36.27.239 -``` - -### 포트 구성 - -| 포트 | 서비스 | 설명 | -|------|--------|------| -| 80 | nginx | HTTP → HTTPS 리다이렉트 | -| 443 | nginx | HTTPS (Let's Encrypt) | -| 8045 | nginx | PHP-FPM vhost (내부) | -| 3001 | Gitea | Git 서버 (Docker, 내부) | -| 9000 | webhook | 배포 트리거 수신 (내부) | -| 3306 | MySQL | 원격 DB (`3.36.27.239`) | - ---- - -## 3. Gitea (Git 서버) - -| 항목 | 값 | -|------|------| -| 외부 URL | https://gitea.wxn.co.kr | -| 관리자 | `wixon` / `wixon1234!` (`admin@wxn.co.kr`) | -| 레포 | https://gitea.wxn.co.kr/wixon/jongryangje | -| 컨테이너 | `gitea` (Docker) | -| DB | SQLite (`/srv/gitea/data/gitea/gitea.db`) | -| docker-compose | `/srv/gitea/docker-compose.yml` | -| 데이터 | `/srv/gitea/data` | - -### 관리 명령 - -```bash -# 상태 확인 -sudo docker ps | grep gitea - -# 재시작 -cd /srv/gitea && sudo docker compose restart - -# 로그 -sudo docker logs gitea --tail 50 - -# 사용자 추가 -sudo docker exec -u git gitea gitea admin user create \ - --username --password --email --admin -``` - ---- - -## 4. 자동 배포 (CI/CD) - -### 플로우 - -``` -로컬 git push → Gitea → Webhook (9000) → deploy.sh → 서버 반영 -``` - -`git push gitea main` 한 번이면 서버에 자동 반영됩니다. - -### 배포 스크립트 (`/srv/jongryangje/deploy.sh`) - -```bash -#!/bin/bash -cd /srv/jongryangje -git fetch origin main && git reset --hard origin/main -composer install --no-dev --no-interaction | tail -3 -chmod -R 777 writable/ -echo "Deployed at $(date)" -``` - -### 관련 파일 - -| 파일 | 용도 | -|------|------| -| `/srv/jongryangje/deploy.sh` | 배포 실행 (git fetch + reset + composer) | -| `/srv/jongryangje/webhook-server.sh` | Webhook 수신 (nc 기반) | -| `/etc/systemd/system/jongryangje-webhook.service` | Webhook systemd 서비스 | -| `/srv/jongryangje/writable/logs/deploy.log` | 배포 로그 | - -### 수동 배포 - -```bash -ssh wixon@116.122.157.166 "/srv/jongryangje/deploy.sh" -``` - -### 배포 로그 확인 - -```bash -ssh wixon@116.122.157.166 "tail -20 /srv/jongryangje/writable/logs/deploy.log" -``` - ---- - -## 5. 로컬 Git 설정 - -### Remote - -| Remote | URL | 용도 | -|--------|-----|------| -| `origin` | `github.com/wixon-associates/jongryangje` | GitHub (소스 관리) | -| `gitea` | `gitea.wxn.co.kr/wixon/jongryangje` | 서버 배포 (auto-deploy) | - -### Push 방법 - -```bash -# GitHub + 서버 동시 배포 -git push origin main && git push gitea main -``` - ---- - -## 6. 서버 파일 구조 - -``` -/srv/ -├── jongryangje/ # 프로젝트 (git clone) -│ ├── public/ # nginx document root -│ ├── .env # 환경 설정 (gitignore) -│ ├── deploy.sh # 배포 스크립트 -│ └── webhook-server.sh # Webhook 수신 -└── gitea/ # Gitea Docker - ├── docker-compose.yml - └── data/ # Gitea 데이터 - -/etc/nginx/sites-available/ -├── jongryangje # PHP-FPM vhost (:8045) -├── jongryangje-ssl # trash.wxn.co.kr (80→443, SSL) -└── gitea # gitea.wxn.co.kr (80→443, SSL → :3001) - -/etc/letsencrypt/live/ -├── trash.wxn.co.kr/ # 웹 SSL 인증서 -└── gitea.wxn.co.kr/ # Gitea SSL 인증서 -``` - ---- - -## 7. SSL 인증서 (Let's Encrypt) - -| 도메인 | 인증서 경로 | 만료 | -|--------|-------------|------| -| `trash.wxn.co.kr` | `/etc/letsencrypt/live/trash.wxn.co.kr/` | 자동 갱신 (certbot) | -| `gitea.wxn.co.kr` | `/etc/letsencrypt/live/gitea.wxn.co.kr/` | 자동 갱신 (certbot) | -| `blog.wxn.co.kr` | `/etc/letsencrypt/live/blog.wxn.co.kr/` | 자동 갱신 (certbot) | - -```bash -# 인증서 상태 확인 -sudo certbot certificates - -# 수동 갱신 -sudo certbot renew -``` - ---- - -## 8. 서비스 관리 - -```bash -# nginx -sudo systemctl restart nginx -sudo nginx -t # 설정 테스트 - -# PHP-FPM -sudo systemctl restart php8.2-fpm - -# Gitea -cd /srv/gitea && sudo docker compose restart - -# Webhook -sudo systemctl restart jongryangje-webhook - -# 전체 상태 -sudo systemctl status nginx php8.2-fpm jongryangje-webhook -sudo docker ps -``` - ---- - -## 9. DNS 설정 - -| 도메인 | 타입 | 값 | -|--------|------|------| -| `trash.wxn.co.kr` | A | `116.122.157.166` | -| `gitea.wxn.co.kr` | A | `116.122.157.166` | -| `blog.wxn.co.kr` | A | `116.122.157.166` | - ---- - -## 10. 기타 서비스 — WIXON Blog - -| 항목 | 값 | -|------|------| -| 도메인 | https://blog.wxn.co.kr | -| 앱 | Flask (Python3), port 8899 | -| 소스 경로 | `/srv/wixon_blog/` (배포용), `/var/lib/jenkins/workspace/wixon_blog/` (원본) | -| Gitea 레포 | https://gitea.wxn.co.kr/wixon/wixon_blog | -| SSL | Let's Encrypt (`/etc/letsencrypt/live/blog.wxn.co.kr/`) | -| nginx | `/etc/nginx/sites-available/blog` | -| 자동 배포 | Webhook (port 9001) → `/srv/wixon_blog/deploy.sh` | -| webhook 서비스 | `wixon-blog-webhook.service` | - -```bash -# 배포 로그 -tail -20 /srv/wixon_blog/log/deploy.log - -# webhook 서비스 상태 -sudo systemctl status wixon-blog-webhook -``` - ---- - -## 11. 트러블슈팅 - -### 사이트 접속 안 됨 -```bash -# nginx 상태 확인 -sudo systemctl status nginx -sudo tail -20 /var/log/nginx/error.log - -# PHP-FPM 확인 -sudo systemctl status php8.2-fpm -``` - -### 배포 안 됨 -```bash -# webhook 서비스 확인 -sudo systemctl status jongryangje-webhook - -# 수동 배포로 테스트 -/srv/jongryangje/deploy.sh - -# 배포 로그 -tail -30 /srv/jongryangje/writable/logs/deploy.log -``` - -### Gitea 접속 안 됨 -```bash -sudo docker ps | grep gitea -sudo docker logs gitea --tail 30 -``` diff --git a/docs/개발 규칙/00-README.md b/docs/개발 규칙/00-README.md deleted file mode 100644 index 8fa3d28..0000000 --- a/docs/개발 규칙/00-README.md +++ /dev/null @@ -1,27 +0,0 @@ -# 개발 규칙 (Development Rules) - -> **AI 코드 생성 시 반드시 참고**: 본 폴더의 규칙을 따라 Auth 프로젝트와 동일한 스타일로 개발한다. - -## 문서 목록 - -| 파일 | 내용 | -|------|------| -| [01-개발스타일.md](01-개발스타일.md) | 전체 개발 스타일·흐름 (Auth 기준) | -| [02-코딩컨벤션.md](02-코딩컨벤션.md) | PHP/네이밍/포맷 규칙 | -| [03-파일분리구조.md](03-파일분리구조.md) | Controller / Model / Config 분리 구조 | -| [04-CSS정리구조.md](04-CSS정리구조.md) | CSS·Tailwind·커스텀 스타일 정리 | -| [05-View정리구조.md](05-View정리구조.md) | 뷰 디렉터리·파일·공통 요소 | -| [06-데이터베이스정리구조.md](06-데이터베이스정리구조.md) | 테이블·컬럼·Model 매핑 규칙 | -| [07-전체구조.md](07-전체구조.md) | 프로젝트 전체 디렉터리·역할 요약 | -| [08-디자인규칙.md](08-디자인규칙.md) | **디자인 기준**·레이아웃·색상·버튼·테이블 (기준: `app/Views/bag/daily_inventory.php`) | - -## 참조 구현 (기준 코드) - -- **Controller**: `app/Controllers/Auth.php` -- **Model**: `app/Models/MemberModel.php`, `app/Models/MemberLogModel.php` -- **View**: `app/Views/auth/login.php`, `app/Views/auth/register.php` -- **디자인 기준 뷰**: `app/Views/bag/daily_inventory.php` (일관된 디자인 시 이 파일 참고) -- **Route**: `app/Config/Routes.php` -- **Config**: `app/Config/Roles.php` - -새 기능 추가 시 위 파일들의 패턴을 따르고, 본 폴더 규칙과 충돌 시 **본 폴더 규칙을 우선**한다. diff --git a/docs/개발 규칙/01-개발스타일.md b/docs/개발 규칙/01-개발스타일.md deleted file mode 100644 index 5ff0f19..0000000 --- a/docs/개발 규칙/01-개발스타일.md +++ /dev/null @@ -1,50 +0,0 @@ -# 개발 스타일 (Development Style) - -> Auth 프로젝트(`Auth.php`, `auth/login.php`, `MemberModel`)를 기준으로 한 개발 스타일. AI 생성 코드는 이 스타일을 따른다. - -## 1. 요청 흐름 - -- **GET**: 폼 표시 또는 목록 조회 → `view('폴더/파일')` 반환. -- **POST**: 유효성 검사 → Model 호출 → 성공 시 `redirect()->to(...)->with('success', ...)`, 실패 시 `redirect()->back()->withInput()->with('error'|'errors', ...)`. - -## 2. 컨트롤러 메서드 패턴 - -| 용도 | 메서드명 예시 | 동작 | -|------|----------------|------| -| 폼 표시 | `showLoginForm()`, `create()`, `edit($id)` | `return view('auth/login');` 등 | -| 처리 | `login()`, `store()`, `update($id)`, `delete($id)` | `$this->validate()` → Model → `redirect()` | - -- 폼 표시 메서드는 가능하면 `showXxxForm()` 또는 리소스형 `index`, `create`, `edit` 사용. -- 처리 메서드는 동사형(`login`, `store`, `update`, `delete`). - -## 3. 유효성 검사 - -- 규칙·메시지는 배열로 정의, 한글 메시지 사용. -- 실패 시: `redirect()->back()->withInput()->with('errors', $this->validator->getErrors())`. -- 단일 에러 메시지는 `with('error', '메시지')`. - -```php -$rules = ['login_id' => 'required|max_length[50]', ...]; -$messages = ['login_id' => ['required' => '아이디를 입력해 주세요.', ...]]; -if (! $this->validate($rules, $messages)) { - return redirect()->back()->withInput()->with('errors', $this->validator->getErrors()); -} -``` - -## 4. Model 사용 - -- `model(MemberModel::class)` 형태로 로드. -- 조회·추가·수정·삭제는 Model 메서드에 위임. 컨트롤러에서 직접 쿼리 빌더 노출 최소화. - -## 5. 리다이렉트 - -- 성공: `redirect()->to(site_url('/'))->with('success', '...')` 또는 `redirect()->to('login')->with('success', '...')`. -- 실패: `redirect()->back()->withInput()->with('error', '...')` 또는 `with('errors', ...)`. -- 내부 URL은 `site_url()` 또는 `base_url()` 사용. - -## 6. 뷰 공통 - -- 출력 시 `esc()` 사용. 폼에는 `csrf_field()`, `old('필드명')` 사용. -- 플래시: `session()->getFlashdata('success')`, `getFlashdata('error')`, `getFlashdata('errors')` 표시. - -이 스타일을 유지하면 Auth와 동일한 톤으로 확장된다. diff --git a/docs/개발 규칙/02-코딩컨벤션.md b/docs/개발 규칙/02-코딩컨벤션.md deleted file mode 100644 index 937c9f2..0000000 --- a/docs/개발 규칙/02-코딩컨벤션.md +++ /dev/null @@ -1,42 +0,0 @@ -# 코딩 컨벤션 (Coding Convention) - -> PHP 8.2+, CodeIgniter 4 기준. Auth·MemberModel·MemberLogModel 스타일을 따른다. - -## 1. PHP 기본 - -- **네임스페이스**: `App\Controllers`, `App\Models`, `Config` 등 CI4 규칙 준수. -- **클래스명**: PascalCase. 컨트롤러는 단수/역할명(`Auth`, `Home`). 모델은 `~Model` 접미사(`MemberModel`). -- **메서드명**: camelCase. 동사+명사(`showLoginForm`, `findByLoginId`). -- **상수**: 클래스 상수는 `UPPER_SNAKE_CASE` (`MB_STATE_NORMAL`, `LEVEL_SUPER_ADMIN`). -- **private/protected**: 비공개 로직은 `private` 메서드로 분리(예: `buildLogData`, `insertMemberLog`). - -## 2. 타입·공백 - -- 메서드 인자·반환 타입 선언 권장. 예: `function findByLoginId(string $mbId): ?object`, `function buildLogData(string $mbId, ?int $mbIdx): array`. -- 연산자·쉼표 뒤 공백. `if (! $this->validate(...))` 처럼 `!` 뒤 공백. -- 배열 키·값 정렬 시 화살표 정렬로 가독성 유지(선택). - -## 3. 네이밍 규칙 요약 - -| 구분 | 규칙 | 예시 | -|------|------|------| -| 컨트롤러 | PascalCase, 단수/역할 | `Auth`, `Home`, `Admin\User` | -| 메서드 | camelCase | `showLoginForm`, `login`, `create`, `store` | -| 뷰 폴더 | 소문자, 컨트롤러 대응 | `auth/`, `home/`, `admin/user/` | -| 뷰 파일 | 소문자, 언더스코어 가능 | `login.php`, `register.php`, `daily_inventory.php` | -| 라우트 URI | 소문자, 케밥 또는 경로 | `login`, `logout`, `admin/users` | -| 모델 | PascalCase + Model | `MemberModel`, `MemberLogModel` | -| 테이블 | 소문자, 언더스코어 | `member`, `member_log` | -| 테이블 PK | 테이블 약어_idx | `mb_idx`, `mll_idx` | -| 테이블 컬럼 | 테이블 약어_컬럼명 | `mb_id`, `mb_name`, `mll_regdate` | - -## 4. 주석 - -- 클래스 상단·복잡한 비즈니스 로직에 한글 주석 허용. 예: `/** mb_state: 1=정상, 2=정지, 0=탈퇴 */`. -- PHPDoc: `@param`, `@return`, `@var` 등 필요 시 사용. - -## 5. Config 참조 - -- 설정은 `config('Roles')`, `config('App')` 등으로 접근. `config('Roles')->getLevelName($level)` 형태 사용. - -이 컨벤션을 지키면 Auth와 동일한 코드 스타일로 유지된다. diff --git a/docs/개발 규칙/03-파일분리구조.md b/docs/개발 규칙/03-파일분리구조.md deleted file mode 100644 index f327b45..0000000 --- a/docs/개발 규칙/03-파일분리구조.md +++ /dev/null @@ -1,57 +0,0 @@ -# 파일 분리 구조 (File Separation Structure) - -> Auth·Home·Member·MemberLog 기준. 컨트롤러/모델/설정 역할별 분리 규칙. - -## 1. 컨트롤러 (Controllers) - -- **위치**: `app/Controllers/` -- **네임스페이스**: `App\Controllers` 또는 서브(예: `App\Controllers\Admin`). -- **기준**: `Auth.php` — 로그인/로그아웃/회원가입 등 한 도메인당 한 컨트롤러. -- **상속**: `extends BaseController`. -- **역할**: 요청 수신 → 유효성 → Model 호출 → view() 또는 redirect(). 비즈니스 로직은 Model·별도 클래스로 분리. - -``` -app/Controllers/ -├── BaseController.php # 공통 상속 -├── Auth.php # 로그인/로그아웃/회원가입 -├── Home.php # 홈/대시보드 -└── Admin/ # 관리자단(선택) - ├── Dashboard.php - ├── User.php - └── ... -``` - -## 2. 모델 (Models) - -- **위치**: `app/Models/` -- **네임스페이스**: `App\Models` -- **기준**: `MemberModel.php`, `MemberLogModel.php` — 테이블 1:1, `$table`, `$primaryKey`, `$allowedFields` 정의. -- **역할**: DB 접근·조회/추가/수정/삭제. 컨트롤러는 Model 메서드만 호출. - -``` -app/Models/ -├── MemberModel.php # member 테이블 -└── MemberLogModel.php # member_log 테이블 -``` - -## 3. 설정 (Config) - -- **위치**: `app/Config/` -- **기준**: `Routes.php`, `Roles.php` — 라우트·역할 등 앱 전역 설정. -- **역할**: URL 라우팅, 역할 코드·한글명 매핑 등. 비즈니스 로직은 넣지 않는다. - -``` -app/Config/ -├── Routes.php # 라우트 정의 -├── Roles.php # mb_level 상수·levelNames -├── App.php -├── Database.php -└── ... -``` - -## 4. 라우트 규칙 - -- **GET** = 폼/목록, **POST** = 처리. 같은 URI를 GET/POST로 나누는 패턴 사용(예: `get('login')`, `post('login')`). -- 그룹 필요 시 `$routes->group('admin', ['filter' => 'adminAuth'], function ($routes) { ... });` 형태. - -새 기능 추가 시 위 구조에 맞춰 Controller/Model/Config를 분리하고, Auth·Member와 동일한 패턴을 따른다. diff --git a/docs/개발 규칙/04-CSS정리구조.md b/docs/개발 규칙/04-CSS정리구조.md deleted file mode 100644 index 642d96a..0000000 --- a/docs/개발 규칙/04-CSS정리구조.md +++ /dev/null @@ -1,42 +0,0 @@ -# CSS 정리 구조 (CSS Organization) - -> Auth·일일봉투 수불현황 뷰 기준. Tailwind + 페이지 단위 커스텀 스타일. - -## 1. 기본 원칙 - -- **Tailwind CSS**를 메인으로 사용. CDN: `https://cdn.tailwindcss.com?plugins=forms,container-queries`. -- **페이지/화면 단위**로 필요한 경우에만 `tailwind.config` 확장(colors, fontFamily 등)과 `