2026-05-07 · Phase 1 (D1) + Phase 2A (D2~D3 일부)
한 줄 요약
D0의 디자인 토큰 위에 인증·세션·CSRF·변경이력 인프라를 박고, 프로젝트와 발주내역 1차 CRUD를 끝냈다. 중간에 엑셀 양식과 다른 컬럼 배치로 만들었다가 한 번 갈아엎음 — 양식과의 시각적 일치가 이 시스템의 본질이라는 걸 다시 확인.
0. 결정 — CI4 폐기, Vanilla PHP로
D0 계획서에는 CodeIgniter 4. 그러나 실제 워크플로우는:
- 사용자 로컬에 PHP/Composer 미설치
- 닷홈 호스팅은 SSH 미지원
- 사용자가 직접 닷홈에 FTP 업로드해서 확인하는 방식
CI4는 composer install로 50MB짜리 vendor 폴더를 만들어야 작동하는데, composer를 돌릴 수 있는 환경이 어디에도 없다. 매 업데이트마다 vendor를 zip으로 같이 보내는 건 부담이 너무 큼.
→ Vanilla PHP 8.4로 전환. 작은 mini-framework 패턴으로 CI4의 좋은 점(필터·세션·CSRF·라우팅 흉내)을 직접 구현. 외부 라이브러리는 PhpSpreadsheet vendor 한 가지만 Phase 3 시점에 zip으로 동봉.
이 결정을 메모리에 박아둠 — 앞으로도 빌드 단계가 있는 프레임워크는 부적합.
1. Phase 1 — 인증·인프라
1A 환경·DB 점검
daehatech.kr/
├── .htaccess # 보안 헤더, 민감 파일 차단, gzip
├── config/
│ ├── .htaccess # Require all denied
│ └── env.php # DB·세션·앱 설정
├── lib/
│ ├── .htaccess # Require all denied
│ ├── bootstrap.php # 모든 페이지 첫 줄 require
│ ├── db.php # PDO 싱글턴 + 디버그 화면
│ └── helpers.php # e/input/redirect/fmt_*/layout_*
└── dashboard.php # 임시 점검 화면
확인: PHP 8.4.20 / MySQL 8.0.44 / 8테이블 + 1뷰(v_purchase_orders) 모두 정상.
1B 인증
attempt_login(): bcrypt 검증 +login_logs자동 기록 (성공/실패/비활성/잘못된ID 모두 추적)session_regenerate_id(true)+ CSRF 토큰 회전 — 세션 고정 공격 방지require_login()/require_admin()— 페이지 첫 줄 가드csrf_token()/csrf_verify()/csrf_field()— timing-safehash_equalslogout.php— CSRF 검증 → 세션 파괴 → 쿠키 만료
index.php(로그인)의 placeholder 인증을 실제 인증으로 교체. 이미 만든 디자인은 그대로.
1C 변경이력 + 공통 layout
audit_log($entity_type, $entity_id, $action, $before, $after)한 줄 헬퍼 — 자동diff_summary생성 (전후 row 비교,updated_at·amount같은 자동 컬럼은 제외)views/layout.php— 상단 슬림 헤더 + 좌측 사이드바 + 메인.layout_start()/layout_end('타이틀','메뉴키')패턴assets/css/app.css— KPI / 카드 / 테이블 / audit 리스트 / 배지 / 버튼- 정식 대시보드 — 4 KPI(운행 중 차량/입고 지연/입고 임박/진행 프로젝트) + 운행 중 차량 표 + 입고 임박·지연 발주 표 + 최근 변경이력 10건
index.php 로그인 성공 시 + logout.php에서 audit_log('user', id, 'login'/'logout') 자동 기록.
2. 가독성 + 모바일 대응
폰트 스케일 한 단계 위로
대시보드를 본 사용자 피드백: "폰트가 너무들 작아 나이든 사람들이 많기 때문에 폰트를 키워줘야해". 정보 밀도보다 가독성 우선.
| 토큰 | 이전 | 이후 |
|---|---|---|
--fs-base (본문) | 14 | 16 |
| 사이드바 메뉴 | 13 | 16 |
| KPI 값 | 32 | 44 |
| 페이지 제목 | 28 | 34 |
| 테이블 | 13 | 16 |
| 버튼 | 13 | 16 |
이 정책을 메모리에 박아둠 — 앞으로 새 화면 만들 때 자동 적용.
햄버거 + 오프캔버스 사이드바
760px 이하에서 사이드바가 그냥 사라져 메뉴 접근 불가였던 걸 햄버거로:
- 헤더에 ☰ 노출
- 좌측에서 슬라이드 인 (280px 폭)
- 백드롭 클릭 또는 메뉴 항목 클릭(=페이지 이동) 시 자동 닫힘
- vanilla JS
onclick="document.body.classList.toggle('sidebar-open')"한 줄. Alpine.js 도입은 미룸.
사이드바 그룹 헤더 시인성
"자재관리·차량관리·관리"가 안 보임 — text-transform: uppercase + letter-spacing: 0.1em + muted gray + 13px 조합. 한글에 자간/uppercase는 효과 없는데 일반 SaaS 디폴트를 그대로 가져온 실수. 16px + 700 + brand-navy + 그룹 사이 1px 보더로 다시.
3. Phase 2A — 자재 모듈
2A1 프로젝트 마스터 CRUD
projects/index.php— 4필드 LIKE 검색 + 20건 페이징projects/edit.php—?id=new/?id=N분기, 7필드 폼projects/delete.php— soft delete + 발주내역 함께 마킹 (트랜잭션)- 권한 분기: 관리자만 저장/삭제, 일반 직원 readonly
- 모든 mutation에
audit_log자동 기록 [공사번호 + 주문번호]UNIQUE 위반(에러 코드 1062) 잡아서 친절 메시지
2A2 발주내역 CRUD (1차)
orders/edit.php— 16필드 폼을 5섹션으로 묶음 (품목·수량·일정·담당자·비고)orders/delete.php— soft deleteorders/index.php— 전체 발주 통합 목록projects/edit.php하단에 11컬럼 축약 표seq_no자동 채번,amountgenerated column,remaining_days는 view에서 SELECT 시 계산
이게 잘못 만든 1차.
4. 시행착오 — 양식을 안 봤던 사고
사용자 지적: "왜 이 양식에 따라서 개발하지 않는거야?"
요구사항 정의서의 16컬럼 텍스트만 보고 폼·표를 임의로 재구성한 게 잘못. 클라이언트가 매일 보는 엑셀 양식의 컬럼 순서·헤더 라벨·시각 구조 그대로가 이 시스템의 본질("엑셀 양식을 그대로 웹으로")이라는 걸 잊었다.
openpyxl로 양식 직접 분석:
| 시트 | 구조 | 발견 |
|---|---|---|
| 프로젝트 정보 | 7행 × 2열 (라벨/값) | 내 폼 순서 OK |
| 발주내역 | 96행 × 16열 가로 표 | 헤더 라벨이 "수 량"(공백 1칸), "입고(예정)일"(괄호 포함) — 양식 그대로 써야 |
엑셀 컬럼 순서:
순번 → 품목코드 → 품명 및 규격 → 수 량 → 구분 →
자재 청구일 → 구매담당자 → 발주일 → 입고(예정)일 → 잔여일수 →
불출일 → 수령인 → 단가 → 금액 → 업체명 → 비고
수정:
projects/edit.php하단 표를 16컬럼 가로 표(min-width 1600px, 가로 스크롤)로 재구성. 헤더 양식 라벨 그대로- 자동 계산 컬럼(순번·잔여일수·금액)에 옅은 노란 배경(
#FFFBEB) — 엑셀에서 수식 셀 표시 관행과 일치, 사용자가 "이 셀은 자동"임을 직관적으로 인식 orders/edit.php폼도 5섹션 그룹핑 폐기 → 양식 좌→우 순서 그대로 4열 그리드 재배치- 잔여일수 색상: 지연(빨강) / 임박(주황) / 여유(초록) / 불출 완료(회색)
이 결정도 메모리에 박아둠 — "새 화면을 만들기 전, 양식 파일을 직접 열어서 분석한다". 헤더 라벨까지 양식 그대로.
5. 단가 옵셔널 처리
발주 등록 시 단가 미입력도 통과되도록. 양식의 일부 행처럼 단가/금액이 비어 있는 발주가 정상 케이스. 검증을 "입력했을 때만 숫자/음수 체크"로 완화하고, 화면에서 0인 경우 빈칸으로 표시 (양식과 동일한 시각).
현재 상태 (2026-05-07 종료 시점)
작동
- 로그인/로그아웃, 권한 가드, CSRF, 세션 보호, 변경이력 자동 기록
- 정식 대시보드 (KPI + 운행 중 차량 + 입고 임박/지연 + 최근 이력)
- 프로젝트 CRUD (list/new/edit/delete + 검색 + 페이징)
- 발주내역 CRUD (양식 16컬럼 표 + 별도 폼 페이지) + 통합 목록
- 모바일 햄버거 메뉴
미구현
- 자재 검색 (단일 8필드 + 복합 + 입고 임박/지연 자동 필터)
- 자재 엑셀 업/다운로드
- 차량관리 모듈 전체
- 사용자 마스터 (admin/users)
- 변경이력 조회 화면 (admin/audits)
- 자동 백업
다음 — 즉시 우선순위
- 발주내역 시인성 개선 — 16컬럼 표가 정보가 많고 빽빽함. 행 구분/그룹화/주요 컬럼 강조 등 디자인 개선
- 수정 흐름 변경 — 행 클릭 = 수정 페이지로 즉각 이동이 너무 직접적. 명시적 [수정] 버튼을 눌러야 편집 폼이 열리는 방향으로 (실수 방지 + 의도 명확)
이후 큰 그림:
- Phase 3: 자재 검색 + 엑셀 업/다운로드 (PhpSpreadsheet vendor 도입)
- Phase 4: 차량관리 (중복 출차 방지 4규칙 포함, 운행 중 차량 대시보드)
- Phase 5: 사용자 마스터, 이력 화면, 자동 백업, 보안·성능 점검, UAT, 운영 매뉴얼
메모리에 새로 박은 정책 4건
| 메모리 | 핵심 |
|---|---|
| 정적 미리보기 사본 금지 | PHP 본체와 함께 .html 사본 만들지 말 것 |
| 닷홈 직접 배포 워크플로우 | 로컬 환경 X, FTP 직배포 — 빌드 단계 있는 프레임워크 금지 |
| 노년 사용자 가독성 우선 | 본문 16px 이상, 정보밀도보다 가독성 |
| 엑셀 양식 일치 | 자재/차량 화면은 양식 컬럼 순서·헤더·라벨 그대로, 양식 직접 분석 후 작업 |
진행하면서 가이드가 점점 명확해진다.