feat: TK 안전관리 플랫폼 초기 구현

위험성평가, 안전 RAG Q&A, 안전점검 체크리스트를 통합한
안전관리자 전용 웹 플랫폼 전체 구현.

- Next.js 15 (App Router) + TypeScript + Tailwind + shadcn/ui
- Drizzle ORM + PostgreSQL 16 (12개 테이블)
- 위험성평가 CRUD + 5x5 위험성 매트릭스 + 인쇄 내보내기
- 체크리스트 템플릿/점검/NCR 추적
- RAG 문서 파이프라인 (Tika + bge-m3 + Qdrant)
- SSE 스트리밍 RAG 채팅 (qwen3.5:35b-a3b)
- AI 어시스트 (위험요인 추천, 감소대책, 점검항목 생성)
- 대시보드 통계/차트 (recharts)
- 단일 사용자 인증 (HMAC 쿠키 세션)
- 다크모드 지원
- Docker 멀티스테이지 빌드 (standalone)
- 프로젝트 가이드 문서 (docs/)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-03 12:33:55 +09:00
parent 6e01d783c4
commit 2a9968fa7f
103 changed files with 14992 additions and 91 deletions

107
docs/architecture.md Normal file
View File

@@ -0,0 +1,107 @@
# TK 안전관리 플랫폼 - 아키텍처 가이드
## 기술 스택
| 분류 | 기술 |
|------|------|
| 프레임워크 | Next.js 15 (App Router, TypeScript, Server Actions) |
| UI | Tailwind CSS + shadcn/ui + Lucide icons + recharts |
| ORM | Drizzle ORM |
| DB | PostgreSQL 16 (컨테이너 `tk-safety-db`) |
| AI 생성 | 맥미니 Ollama qwen3.5:35b-a3b |
| AI 임베딩 | 조립컴 Ollama bge-m3 (1024d) |
| 벡터DB | Qdrant (컬렉션 `safety-docs`) |
| OCR | Apache Tika (port 9998) |
| 인증 | 단일 사용자 (환경변수 비밀번호 + HMAC 쿠키 세션) |
## 포트 매핑
| 서비스 | 호스트:컨테이너 |
|--------|------------------|
| tk-safety (Next.js) | 3100:3000 |
| tk-safety-db (PostgreSQL) | 127.0.0.1:5433:5432 |
## 프로젝트 구조
```
tk-safety/
├── docker-compose.yml # 서비스 정의
├── Dockerfile # multi-stage 빌드 (standalone)
├── .env / .env.example # 환경변수
├── drizzle.config.ts # Drizzle ORM 설정
├── drizzle/migrations/ # DB 마이그레이션 (자동 생성)
├── uploads/ # 업로드 파일 (documents, photos)
├── docs/ # 프로젝트 가이드 문서
└── src/
├── app/
│ ├── layout.tsx # 루트 레이아웃 (다크모드 초기화)
│ ├── page.tsx # 인증 리다이렉트
│ ├── login/page.tsx # 로그인 페이지
│ ├── middleware.ts # 인증 미들웨어
│ ├── (authenticated)/ # 인증 필요 라우트 그룹
│ │ ├── layout.tsx # 사이드바 + 헤더
│ │ ├── dashboard/ # 대시보드
│ │ ├── risk-assessment/ # 위험성평가
│ │ ├── rag/ # 안전 Q&A
│ │ ├── checklists/ # 점검 체크리스트
│ │ └── settings/ # 설정
│ └── api/
│ ├── auth/ # 로그인/로그아웃 API
│ ├── ai/ # AI 엔드포인트 (SSE 스트리밍)
│ └── health/ # 서비스 헬스체크
├── actions/ # Server Actions (CRUD)
├── components/
│ ├── ui/ # shadcn/ui 컴포넌트
│ ├── layout/ # 사이드바, 헤더, 모바일 내비
│ ├── dashboard/ # 통계, 차트, 퀵액션
│ ├── risk-assessment/ # 평가 폼, 매트릭스, AI 패널
│ ├── rag/ # 채팅, 문서 관리
│ └── checklists/ # 템플릿, 점검, NCR
├── lib/
│ ├── db/ # schema.ts, index.ts
│ ├── ai/ # ollama, qdrant, tika, embeddings, prompts
│ ├── auth.ts # 인증 유틸
│ ├── constants.ts # 상수 정의
│ └── utils.ts # shadcn 유틸
├── hooks/ # use-streaming.ts (SSE)
└── types/ # 타입 정의
```
## DB 스키마 (12개 테이블)
### 위험성평가
- `risk_assessments` — 평가 마스터 (제목, 상태, 버전)
- `risk_assessment_hazards` — 유해위험요인 (S×L=위험성)
### RAG 문서
- `rag_documents` — 업로드 문서 (처리 상태 포함)
- `rag_chunks` — 문서 청크 (Qdrant pointId 매핑)
- `rag_conversations` — 대화 세션
- `rag_messages` — 메시지 (질문/답변 + 출처)
### 체크리스트
- `checklist_templates` — 점검 템플릿
- `checklist_template_items` — 템플릿 항목
- `inspections` — 점검 실행 기록
- `inspection_results` — 항목별 결과
- `non_conformances` — 부적합 사항 (NCR)
### 기타
- `app_settings` — 앱 설정 (key-value)
## AI 연동 흐름
### RAG Q&A
```
질문 → bge-m3 임베딩(조립컴) → Qdrant 검색(top-5) → 컨텍스트 + 질문 → qwen3.5 생성(맥미니) → SSE 스트리밍
```
### AI 위험요인 추천
```
작업 설명 → bge-m3 임베딩 → Qdrant 검색(top-3) → 컨텍스트 + 프롬프트 → qwen3.5 JSON 생성 → 구조화 응답
```
### 문서 처리 파이프라인
```
파일 업로드 → Tika 텍스트 추출 → 1500자/200 overlap 청킹 → bge-m3 배치 임베딩(10개씩) → Qdrant 저장
```

107
docs/deployment.md Normal file
View File

@@ -0,0 +1,107 @@
# TK 안전관리 - 배포 가이드
## 사전 요구사항
맥미니 서버 (192.168.1.122)에 다음 서비스가 실행 중이어야 합니다:
- Ollama (qwen3.5:35b-a3b) — port 11434
- Qdrant — port 6333
- Apache Tika — port 9998
- Docker Desktop
조립컴 (192.168.1.186 / Tailscale 100.111.160.84):
- Ollama (bge-m3) — port 11434
## 빠른 시작
### 1. 환경변수 설정
```bash
cd ~/docker/tk-safety
cp .env.example .env
# .env 파일에서 ADMIN_PASSWORD, SESSION_SECRET 변경
```
### 2. Docker 빌드 및 실행
```bash
docker-compose up -d
```
### 3. DB 마이그레이션
```bash
# 로컬에서 마이그레이션 생성
npx drizzle-kit generate
# 마이그레이션 적용
npx drizzle-kit push
```
또는 DB URL을 직접 지정:
```bash
DATABASE_URL=postgres://tksafety:tksafety_password@localhost:5433/tksafety npx drizzle-kit push
```
### 4. 접속 확인
- http://192.168.1.122:3100
- 설정한 비밀번호로 로그인
## 환경변수
| 변수 | 설명 | 기본값 |
|------|------|--------|
| DATABASE_URL | PostgreSQL 연결 문자열 | (필수) |
| ADMIN_PASSWORD | 로그인 비밀번호 | changeme |
| SESSION_SECRET | 세션 서명 키 (32자 이상) | (필수) |
| OLLAMA_BASE_URL | Ollama 생성 AI URL | http://host.docker.internal:11434 |
| OLLAMA_MODEL | 생성 모델명 | qwen3.5:35b-a3b |
| EMBEDDING_BASE_URL | 임베딩 서버 URL | http://100.111.160.84:11434 |
| EMBEDDING_MODEL | 임베딩 모델명 | bge-m3 |
| QDRANT_URL | Qdrant URL | http://host.docker.internal:6333 |
| QDRANT_COLLECTION | Qdrant 컬렉션명 | safety-docs |
| TIKA_URL | Tika URL | http://host.docker.internal:9998 |
## 업데이트
```bash
cd ~/docker/tk-safety
git pull
docker-compose up -d --build
```
## 데이터 백업
### PostgreSQL
```bash
docker exec tk-safety-db pg_dump -U tksafety tksafety > backup.sql
```
### 복원
```bash
docker exec -i tk-safety-db psql -U tksafety tksafety < backup.sql
```
### 업로드 파일
`~/docker/tk-safety/uploads/` 디렉토리를 백업하세요.
## 트러블슈팅
### DB 연결 실패
```bash
# DB 컨테이너 상태 확인
docker logs tk-safety-db
# DB 직접 접속
docker exec -it tk-safety-db psql -U tksafety tksafety
```
### AI 서비스 연결 실패
설정 페이지 (Settings)에서 서비스 연결 상태를 확인하세요.
- Ollama: `curl http://localhost:11434/api/tags`
- Qdrant: `curl http://localhost:6333/collections`
- Tika: `curl http://localhost:9998/tika`
### 빌드 실패
```bash
# 캐시 정리 후 재빌드
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```

80
docs/development.md Normal file
View File

@@ -0,0 +1,80 @@
# TK 안전관리 - 개발 가이드
## 로컬 개발 환경 설정
### 1. 의존성 설치
```bash
cd ~/docker/tk-safety
npm install
```
### 2. DB 실행 (Docker)
```bash
docker-compose up db -d
```
### 3. DB 마이그레이션
```bash
npx drizzle-kit push
```
### 4. 개발 서버 실행
```bash
npm run dev
```
→ http://localhost:3000
## 주요 패턴
### Server Actions
모든 CRUD 작업은 `src/actions/` 디렉토리의 Server Actions로 구현됩니다.
- `risk-assessment.ts` — 위험성평가 + 유해위험요인
- `checklists.ts` — 템플릿 + 점검 + NCR
- `rag.ts` — 문서 업로드/처리 + 대화
### AI API 라우트
SSE 스트리밍이 필요한 AI 기능은 `src/app/api/ai/` 라우트로 구현됩니다.
- `chat/route.ts` — RAG Q&A (SSE)
- `suggest-hazards/route.ts` — 위험요인 추천 (JSON)
- `suggest-controls/route.ts` — 감소대책 제안 (SSE)
- `suggest-checklist/route.ts` — 점검항목 생성 (JSON)
### SSE 스트리밍
클라이언트에서는 `src/hooks/use-streaming.ts` 훅을 사용합니다.
```tsx
const { isStreaming, content, sources, error, streamChat, reset } = useStreaming();
await streamChat("/api/ai/chat", { question, conversationId });
```
### 인증 시스템
- HMAC 기반 쿠키 세션 (7일 유효)
- `src/lib/auth.ts` — 세션 생성/검증
- `src/middleware.ts` — 라우트 보호
- `src/app/(authenticated)/layout.tsx` — 서버사이드 인증 확인
## DB 스키마 수정
1. `src/lib/db/schema.ts` 수정
2. 마이그레이션 생성: `npx drizzle-kit generate`
3. 마이그레이션 적용: `npx drizzle-kit push`
## 새 컴포넌트 추가
### shadcn/ui 컴포넌트
```bash
npx shadcn@latest add [component-name]
```
### 커스텀 컴포넌트
기능별 디렉토리에 배치:
- `src/components/risk-assessment/` — 위험성평가 관련
- `src/components/rag/` — RAG/채팅 관련
- `src/components/checklists/` — 체크리스트 관련
- `src/components/dashboard/` — 대시보드 관련
## 코드 컨벤션
- TypeScript strict 모드
- Drizzle ORM 타입 추론 (`InferSelectModel<typeof table>`)
- Server Actions에서 `revalidatePath()` 호출
- 한국어 UI 텍스트 (상수는 `src/lib/constants.ts`에 정의)

71
docs/features.md Normal file
View File

@@ -0,0 +1,71 @@
# TK 안전관리 - 기능 가이드
## 1. 위험성평가 (Risk Assessment)
### 평가 작성
1. 대시보드 또는 위험성평가 페이지에서 "새 평가" 클릭
2. 기본 정보 입력 (제목, 부서, 장소, 평가자)
3. 평가 생성 후 유해위험요인 추가
### 유해위험요인 등록
- **수동 입력**: "위험요인 추가" 버튼 → 분류, 작업, 위험요인, 중대성(1-5) × 가능성(1-5)
- **AI 추천**: "AI 추천" 버튼 → 작업 설명 입력 → AI가 위험요인 분석 → "추가" 클릭
### 위험성 매트릭스
- 5×5 매트릭스 자동 시각화
- 위험등급: 저위험(1-4), 보통(5-9), 고위험(10-16), 매우위험(17-25)
### AI 감소대책 제안
- 각 위험요인 행의 "대책 제안" 클릭
- 제거 → 대체 → 공학적 → 관리적 → PPE 계층별 제안
### 상태 워크플로
초안 → 검토 → 승인 → 보관
### 인쇄/내보내기
- "인쇄" 버튼으로 고용노동부 양식 기반 인쇄 페이지 열기
- 브라우저 인쇄(Ctrl+P)로 PDF 저장 가능
## 2. 안전 Q&A (RAG)
### 문서 업로드
1. "문서 관리" 탭 선택
2. 카테고리 선택 (산업안전보건법, KOSHA 가이드, 사내규정, 안전작업절차서, 기타)
3. 파일 선택 (PDF, HWP, DOCX 등)
4. 자동 처리: Tika 추출 → 청킹 → 임베딩 → Qdrant 저장
### 채팅
1. "채팅" 탭에서 "새 대화" 클릭
2. 질문 입력 (Enter 전송, Shift+Enter 줄바꿈)
3. AI가 업로드된 문서 기반으로 답변 (SSE 스트리밍)
4. 출처 배지로 참고 문서 확인
## 3. 점검 체크리스트
### 템플릿 관리
1. "새 템플릿" 클릭 → 이름, 유형(일상/정기/특별/장비), 설명 입력
2. 점검 항목 추가 (수동 또는 AI 생성)
3. **AI 항목 생성**: "AI 항목 생성" → 작업환경 설명 → AI가 항목 제안 → 개별 또는 전체 추가
### 점검 실행
1. "점검 실행" → 템플릿 선택, 점검자, 장소 입력
2. 각 항목별 합격/불합격/해당없음 선택 + 메모
3. 불합격 항목에서 NCR(부적합) 등록 가능
4. "점검 완료" 클릭
### 부적합 사항 (NCR) 추적
- 상태 흐름: 미조치 → 시정조치 중 → 확인 중 → 종결
- "부적합" 탭에서 전체 NCR 현황 관리
## 4. 대시보드
- **통계 카드**: 총 평가 수, 점검 수, 미조치 NCR, RAG 문서 수
- **위험등급 분포 차트**: 전체 위험요인의 등급별 분포 (막대 차트)
- **부적합 현황 차트**: NCR 상태별 분포 (파이 차트)
- **빠른 실행**: 새 위험성평가, 안전 Q&A, 점검 실행 바로가기
## 5. 설정
- **테마**: 라이트/다크 모드 전환
- **서비스 연결 상태**: Ollama, Embedding, Qdrant, Tika 연결 확인
- **시스템 정보**: 버전, 프레임워크, 모델 정보