From 5bfc89afa7443e7154644688223b759c1e88b072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 6 Mar 2026 21:09:57 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[=EC=A0=9C=ED=92=88=EA=B2=80=EC=82=AC]?= =?UTF-8?q?=20FQC=20=EB=AC=B8=EC=84=9C=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20?= =?UTF-8?q?=EA=B3=84=ED=9A=8D=20+=20=EC=8A=A4=EB=83=85=EC=83=B7=20Lazy=20S?= =?UTF-8?q?napshot=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fqc-document-system-plan.md: FormRequest 상태 수정, Phase 2.4 Lazy Snapshot 확정, 참고 파일 추가 - document-snapshot-architecture-plan.md: Lazy Snapshot 캡처 원칙 추가 - server-access-management.md 신규 - README.md 수정 Co-Authored-By: Claude Opus 4.6 --- README.md | 2 +- .../document-snapshot-architecture-plan.md | 41 ++++- dev/dev_plans/fqc-document-system-plan.md | 42 ++++- system/server-access-management.md | 150 ++++++++++++++++++ 4 files changed, 224 insertions(+), 11 deletions(-) create mode 100644 system/server-access-management.md diff --git a/README.md b/README.md index fe0b3df..9ed2b97 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SAM 프로젝트 문서 +# SAM 프로젝트 문서 SAM ERP 시스템의 기술 문서, 비즈니스 규칙, 기능 명세를 관리하는 저장소입니다. diff --git a/dev/dev_plans/document-snapshot-architecture-plan.md b/dev/dev_plans/document-snapshot-architecture-plan.md index b968adc..c702698 100644 --- a/dev/dev_plans/document-snapshot-architecture-plan.md +++ b/dev/dev_plans/document-snapshot-architecture-plan.md @@ -53,6 +53,7 @@ 2. rendered_html이 있으면 무조건 그것을 사용 (완전한 스냅샷) 3. 구조화 데이터는 편집/검색/통계용으로 병행 유지 4. React에서만 문서 렌더링 책임 → MNG는 출력만 담당 +5. Lazy Snapshot: 조회 시 rendered_html 없으면 자동 캡처 → 저장 (점진적 스냅샷 전환) ``` ### 1.4 변경 승인 정책 @@ -76,8 +77,9 @@ ### 2.2 React 현황 (구현 완료) -rendered_html 캡처 원칙: **입력 화면에서 저장할 때** 해당 데이터의 "문서 뷰"를 캡처. -보기(readOnly)에서는 캡처하지 않음. +#### 캡처 원칙 A: 입력 시 저장 (Active Capture) + +입력 화면에서 저장할 때 해당 데이터의 "문서 뷰"를 캡처. 보기(readOnly)에서는 캡처하지 않음. | Save Path | 파일 | 방식 | 캡처 대상 | |-----------|------|------|----------| @@ -90,6 +92,40 @@ rendered_html 캡처 원칙: **입력 화면에서 저장할 때** 해당 데이 > 이후 InspectionReportModal을 edit 모드로 열어 저장하면 캡처됨. > 향후 오프스크린 렌더링으로 확장 가능 (템플릿 로딩 등 async 의존성 해결 필요). +#### 캡처 원칙 B: 조회 시 자동 캡처 (Lazy Snapshot) + +문서 조회(view/readOnly) 시 `rendered_html`이 없으면 자동 캡처하여 백그라운드 저장. + +``` +문서 View 시 +├── rendered_html 있음 → 그대로 표시 (기존) +└── rendered_html 없음 → 동적 렌더링 완료 후 캡처 → API로 rendered_html 저장 + (다음 조회부터는 스냅샷 사용) +``` + +**적용 대상**: +- readonly 문서 (제품검사 요청서 등 — 입력 없이 자동 생성되는 문서) +- 마이그레이션 이전 기존 데이터 (rendered_html이 NULL인 과거 문서) +- WorkerScreen 인라인 저장 후 아직 모달에서 저장하지 않은 문서 + +**구현 방식**: +```typescript +// 문서 표시 컴포넌트에서 (DocumentViewer, Modal 등) +useEffect(() => { + if (document && !document.rendered_html && isContentRendered) { + const html = contentWrapperRef.current?.innerHTML + || await captureRenderedHtml(DocumentComponent, props); + patchDocumentRenderedHtml(document.id, html); // 백그라운드 저장 + } +}, [document, isContentRendered]); +``` + +**고려사항**: +- 사용자 UX 영향 없음 (백그라운드 비동기 저장) +- 조회 권한만 있는 사용자도 트리거 가능해야 함 +- 동시 접속 시 중복 저장 가능 → 같은 HTML이므로 실질적 문제 없음 +- 캡처 타이밍: template 로드 + 데이터 바인딩 완료 후 (isContentRendered 판단 필요) + ### 2.3 API 현황 (구현 완료) - Document 모델 `$fillable`에 `rendered_html` 포함 ✅ @@ -298,6 +334,7 @@ Phase 1과 Phase 3의 MNG 코드 수정은 병렬 가능 (fallback 유지). | 2026-03-06 | Phase 2 보정 | API UpsertRequest rendered_html 누락 수정, DocumentService upsert() rendered_html 전달 추가 | UpsertRequest.php, DocumentService.php | ✅ | | 2026-03-06 | Phase 2 보정 | ImportInspection: 입력폼 캡처 → 오프스크린 성적서 렌더링으로 변경 | ImportInspectionInputModal.tsx, capture-rendered-html.tsx | ✅ | | 2026-03-06 | Phase 2 보정 | InspectionReportModal readOnly 자동 캡처 useEffect 제거 | InspectionReportModal.tsx | ✅ | +| 2026-03-06 | 원칙 확장 | Lazy Snapshot 패턴 추가 — 조회 시 rendered_html 없으면 자동 캡처/저장 | 아키텍처 원칙 | - | --- diff --git a/dev/dev_plans/fqc-document-system-plan.md b/dev/dev_plans/fqc-document-system-plan.md index 22a0e48..c773e91 100644 --- a/dev/dev_plans/fqc-document-system-plan.md +++ b/dev/dev_plans/fqc-document-system-plan.md @@ -135,7 +135,7 @@ | 2.1 | mng에 제품검사 요청서 template 신규 등록 (시더) | ⏳ | 시더 방식 확정 | | 2.2 | React 동적 렌더링 컴포넌트 구현 | ⏳ | 하드코딩 → 양식 기반 전환 | | 2.3 | 요청서 문서 생성 API 연동 | ⏳ | quality_document 생성 시 자동 생성 확정 | -| 2.4 | rendered_html 스냅샷 저장 적용 | ⏳ | | +| 2.4 | rendered_html 스냅샷 저장 적용 (Lazy Snapshot) | ⏳ | 요청서 최초 조회 시 rendered_html 없으면 자동 캡처/저장 | ### Phase 3: 통합 및 정리 @@ -202,9 +202,13 @@ Phase 2: 제품검사 요청서 신규 │ ├── 개소 데이터 자동 매핑 (quality_document_locations → 사전고지 테이블) │ └── 파일: api/app/Services/QualityDocumentService.php │ -└── Step 2.4: rendered_html 스냅샷 - ├── 요청서 저장/표시 시 HTML 캡처 - └── API 전송 및 저장 +└── Step 2.4: rendered_html 스냅샷 (Lazy Snapshot 패턴) + ├── 요청서는 readonly 문서 → "입력 시 저장" 캡처 불가 + ├── Lazy Snapshot 적용: 요청서 최초 조회 시 rendered_html 없으면 자동 캡처 + ├── captureRenderedHtml 유틸리티 활용 (react/src/lib/utils/capture-rendered-html.tsx) + ├── 또는 contentWrapperRef.innerHTML로 렌더링 완료 후 캡처 + ├── 백그라운드 API 호출로 rendered_html 저장 (PATCH /v1/documents/{id} 또는 upsert) + └── 참조: document-snapshot-architecture-plan.md 캡처 원칙 B Phase 3: 통합 및 정리 ├── InspectionDetail.tsx에서 모달 연동 통합 테스트 @@ -391,9 +395,14 @@ const methodFreqCoverage = buildCompositeRowSpan(sectionItems); - method+frequency `공인시험기관|1회/5년` → 9행 (내화3 + 차연1 + 개폐5) - `작동테스트`는 method/frequency 빈값 → 병합 대상 아님 -#### 5.1.4 rendered_html 캡처 패턴 (참조: 중간검사) +#### 5.1.4 rendered_html 캡처 패턴 -**`react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx`** (라인 341-366): +> **캡처 원칙** (document-snapshot-architecture-plan.md 참조): +> - **Active Capture**: 입력 화면에서 저장할 때 캡처. readOnly에서는 캡처하지 않음. +> - **Lazy Snapshot**: 조회 시 rendered_html 없으면 자동 캡처/저장 (점진적 전환). +> FQC 성적서는 Active Capture (편집 모드 저장 시), 요청서는 Lazy Snapshot (readonly 자동 캡처) 적용. + +**패턴 1: innerHTML 직접 캡처** (참조: 중간검사 `InspectionReportModal.tsx` 라인 341-366) ```typescript // 1. ref 정의 @@ -414,7 +423,19 @@ const handleSave = async () => { ``` -**FQC에 적용할 위치**: `InspectionReportModal.tsx`의 FQC 모드 저장 로직에 동일 패턴 추가. +**패턴 2: 오프스크린 렌더링** (참조: 수입검사 `ImportInspectionInputModal.tsx`) + +```typescript +import { captureRenderedHtml } from '@/lib/utils/capture-rendered-html'; + +// 문서 컴포넌트를 오프스크린으로 렌더링 → HTML 캡처 +const html = await captureRenderedHtml(DocumentComponent, documentProps); +``` + +- 유틸리티 위치: `react/src/lib/utils/capture-rendered-html.tsx` (flushSync + createRoot) +- 문서가 화면에 렌더링되지 않는 상황에서 캡처할 때 사용 (Lazy Snapshot에 활용 가능) + +**FQC 성적서 적용 (Phase 1.3)**: 패턴 1 사용. `InspectionReportModal.tsx`의 FQC 모드 저장 로직에 동일 패턴 추가. 현재 `fqcActions.ts`의 `saveFqcDocument()`는 `POST /v1/documents/upsert` 사용 → body에 `rendered_html` 추가. #### 5.1.5 FqcDocumentContent.tsx 현재 구조 (보완 대상) @@ -647,6 +668,7 @@ DocumentTemplate (제품검사 요청서) | 1 | 성적서 양식 보완 방안 | **방안 C 확정** — 하드코딩 데이터를 template items로 완전 이관. SectionItem에 method/frequency/measurement_type 이미 존재 | mng, react | ✅ 확정 | | 2 | 요청서 template 생성 방법 | **시더 확정** — ProductInspectionRequestTemplateSeeder 작성 (mng/database/seeders/). 재현성 + 버전 관리 | mng | ✅ 확정 | | 3 | 요청서 문서 생성 시점 | **자동 생성 확정** — quality_document 생성 시 자동. 기존 성적서 bulk create 패턴과 동일 | api | ✅ 확정 | +| 4 | 요청서 rendered_html 캡처 방식 | **Lazy Snapshot 확정** — 요청서는 readonly 문서이므로 최초 조회 시 rendered_html 없으면 자동 캡처/저장. `captureRenderedHtml` 유틸리티 또는 `contentWrapperRef.innerHTML` 활용 | react | ✅ 확정 | --- @@ -664,7 +686,7 @@ DocumentTemplate (제품검사 요청서) | API (DocumentService create/update) | ✅ | rendered_html 조건부 저장 | | React (InspectionReportModal) | ✅ | contentWrapperRef.innerHTML 캡처 | | MNG (show/print.blade.php) | ✅ | rendered_html 우선 출력 + fallback | -| FormRequest 검증 | ⚠️ | rendered_html 검증 규칙 확인 필요 | +| FormRequest 검증 | ✅ | StoreRequest/UpdateRequest/UpsertRequest 모두 nullable string 검증 완료 | ### mng template 구조 핵심 - `DocumentTemplateSectionItem` 필드: category, item, standard, tolerance, standard_criteria, method, measurement_type, frequency_n, frequency_c, frequency, regulation, field_values(JSON) @@ -689,6 +711,7 @@ DocumentTemplate (제품검사 요청서) | 2026-03-06 | 에이전트 조사 | template ID 65 현황, rendered_html 현황, mng 구조 분석 반영 | - | - | | 2026-03-06 | 자기완결성 보완 | 시더 데이터, rowSpan 로직, rendered_html 캡처 패턴, API 구조, 타입 정의 추가 | - | - | | 2026-03-06 | 방법론 수정 6건 | ①컬럼 아키텍처 재설계(template 2개+시각 8컬럼) ②프론트 타입 갭 보완 ③rowSpan 복합키 알고리즘 ④Template ID 안정성 대책 ⑤measurement_type=none 처리 ⑥시더 위치 명확화(mng) | - | - | +| 2026-03-06 | 스냅샷 아키텍처 정합성 검토 반영 | ①FormRequest 검증 ✅ 확인 ②Phase 2.4 Lazy Snapshot 전략 확정 ③참고 파일 추가(capture-rendered-html.tsx, UpsertRequest) ④캡처 원칙(Active/Lazy) 명시 ⑤오프스크린 렌더링 참조 추가 | 5.1.4, 6.1, 9 | - | --- @@ -724,6 +747,8 @@ DocumentTemplate (제품검사 요청서) |------|------|----------| | `react/src/components/production/WorkOrders/documents/TemplateInspectionContent.tsx` | 중간검사 동적 렌더링 (참조 모델) | 917-999: 컬럼타입별 렌더링, 1105-1183: renderComplexCells() | | `react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx` | 중간검사 모달 (rendered_html 캡처 패턴) | 167: contentWrapperRef, 341-366: handleSave+innerHTML | +| `react/src/lib/utils/capture-rendered-html.tsx` | 오프스크린 렌더링 유틸리티 (flushSync+createRoot) | Phase 2.4 Lazy Snapshot에서 활용 가능 | +| `react/src/components/material/ReceivingManagement/ImportInspectionInputModal.tsx` | 수입검사 오프스크린 캡처 참조 | captureRenderedHtml 사용 예시 | ### API (수정 대상) | 파일 | 역할 | 핵심 라인 | @@ -732,6 +757,7 @@ DocumentTemplate (제품검사 요청서) | `api/app/Services/QualityDocumentService.php` | 품질관리 문서 서비스 | 176-209: store(), 749-799: requestDocument(), 804-868: resultDocument() | | `api/app/Models/Documents/Document.php` | 문서 모델 | 76: $fillable에 rendered_html | | `api/app/Models/Qualitys/QualityDocumentLocation.php` | 개소 모델 | fillable: post_width, post_height, change_reason, inspection_data | +| `api/app/Http/Requests/Document/UpsertRequest.php` | documents/upsert 검증 | rendered_html nullable string 검증 완료 | ### MNG (확인/수정 대상) | 파일 | 역할 | diff --git a/system/server-access-management.md b/system/server-access-management.md new file mode 100644 index 0000000..7abc143 --- /dev/null +++ b/system/server-access-management.md @@ -0,0 +1,150 @@ +# SAM 서버 접근 권한 관리 + +## 개요 + +SAM 시스템의 서버 및 데이터베이스 접근 권한을 관리합니다. +서버 관리자는 1명이며, 외부 인원에게는 임시로 접근을 허용하고 작업 완료 후 차단합니다. + +**최종 업데이트:** 2026-03-05 + +--- + +## 서버 정보 + +| 구분 | 호스트 | SSH alias | 용도 | +|------|--------|-----------|------| +| 운영 (prod) | 211.117.60.189 | `sam-prod` | API + React 운영 배포 | +| CI/CD | 114.203.209.83 | `sam-cicd` | Jenkins + React 개발 배포 | + +--- + +## OS 계정 현황 + +### sam-prod (운영서버) + +| 계정 | 용도 | 상태 | +|------|------|------| +| `hskwon` | 서버 관리자 (배포, 운영) | 활성 | +| `pro` | 외부 작업자 임시 접근용 | **잠금** | + +### sam-cicd (CI/CD 서버) + +| 계정 | 용도 | 상태 | +|------|------|------| +| `hskwon` | 서버 관리자 | 활성 | +| `pro` | 외부 작업자 임시 접근용 | **잠금** | + +--- + +## OS 계정 잠금/해제 + +외부 작업자에게 서버 접근이 필요한 경우, 작업 시간 동안만 해제하고 완료 후 다시 잠금합니다. + +```bash +# 계정 잠금 +sudo usermod -L pro + +# 계정 해제 +sudo usermod -U pro + +# 상태 확인 (비밀번호 필드 앞에 ! 있으면 잠금 상태) +sudo passwd -S pro +``` + +### 임시 접근 절차 + +1. 작업 요청 접수 및 범위 확인 +2. `sudo usermod -U pro` 로 해제 +3. 작업 완료 확인 +4. `sudo usermod -L pro` 로 잠금 +5. 작업 내용 기록 + +--- + +## DB 계정 현황 + +### sam-prod (운영서버 MySQL 8.4) + +| 계정 | 인증 플러그인 | 접근 DB | 용도 | +|------|-------------|---------|------| +| `codebridge@localhost` | caching_sha2_password | sam, sam_stage, sam_stat, codebridge | 애플리케이션 (.env) | +| `hskwon@localhost` | caching_sha2_password | 전역 관리자 + sam | 서버 관리자 | +| `pro@localhost` | caching_sha2_password | sam, sam_stage, sam_stat, codebridge | 외부 작업자용 | + +### sam-cicd (CI/CD 서버 MySQL 8.4) + +| 계정 | 인증 플러그인 | 접근 DB | 용도 | +|------|-------------|---------|------| +| `hskwon@localhost` | caching_sha2_password | 전역 관리자 | 서버 관리자 | +| `pro@localhost` | caching_sha2_password | sam, sam_stage, sam_stat, codebridge, gitea | 외부 작업자용 | + +> **참고:** cicd 서버에는 `codebridge` DB 계정이 없음 (애플리케이션이 다른 계정 사용) + +--- + +## DB 계정 관리 + +### 계정 잠금/해제 (MySQL) + +```sql +-- 계정 잠금 +ALTER USER 'pro'@'localhost' ACCOUNT LOCK; + +-- 계정 해제 +ALTER USER 'pro'@'localhost' ACCOUNT UNLOCK; + +-- 상태 확인 +SELECT user, host, account_locked FROM mysql.user WHERE user = 'pro'; +``` + +### 인증 플러그인 변경 + +MySQL 8.4에서는 `mysql_native_password`가 제거되었으므로 `caching_sha2_password`를 사용합니다. + +```sql +ALTER USER 'username'@'localhost' IDENTIFIED WITH caching_sha2_password BY '비밀번호'; +FLUSH PRIVILEGES; +``` + +### PhpStorm 접속 시 주의사항 + +- SSH 터널 필수 (MySQL이 localhost만 허용) +- Host: `localhost` (127.0.0.1 아님) +- `caching_sha2_password` 사용 시 Advanced 탭에서 `allowPublicKeyRetrieval = true` 설정 필요 + +--- + +## 배포 계정 관리 + +### Jenkins 배포 흐름 + +| 프로젝트 | main | develop | +|----------|------|---------| +| **api** | Jenkins (Stage + Production) | post-update hook (Jenkins 미관여) | +| **react** | Jenkins (Stage + Production) | Jenkins (Development) | + +- 배포 SSH 계정: `hskwon` (deploy-ssh-key 크레덴셜) +- Slack 알림: `#deploy_api`, `#deploy_react` + +--- + +## 관리 정책 + +1. **서버 관리자 1명 원칙** — 여러 명이 동시에 관리하지 않음 +2. **임시 접근만 허용** — 외부 작업자는 필요 시에만 OS/DB 계정 해제 +3. **작업 완료 후 즉시 잠금** — 해제 상태로 방치하지 않음 +4. **DB 접근은 SSH 터널 경유** — 외부에서 MySQL 직접 접근 불가 (localhost 바인딩) + +--- + +## 참고 + +- API 보안 가이드: [security-policy.md](./security-policy.md) +- Docker 설정: [docker-setup.md](./docker-setup.md) +- 원격 근무 설정: [remote-work-setup.md](./remote-work-setup.md) + +--- + +**작성일:** 2026-03-05 +**버전:** 1.0 +**담당자:** SAM Infrastructure Team \ No newline at end of file