feat: 3-System 분리 프로젝트 초기 코드 작성
TK-FB(공장관리+신고)와 M-Project(부적합관리)를 3개 독립 시스템으로 분리하기 위한 전체 코드 구조 작성. - SSO 인증 서비스 (bcrypt + pbkdf2 이중 해시 지원) - System 1: 공장관리 (TK-FB 기반, 신고 코드 제거) - System 2: 신고 (TK-FB에서 workIssue 코드 추출) - System 3: 부적합관리 (M-Project 기반) - Gateway 포털 (path-based 라우팅) - 통합 docker-compose.yml 및 배포 스크립트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
369
system3-nonconformance/api/database/schemas.py
Normal file
369
system3-nonconformance/api/database/schemas.py
Normal file
@@ -0,0 +1,369 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from typing import Optional, List, Dict, Any
|
||||
from enum import Enum
|
||||
|
||||
class UserRole(str, Enum):
|
||||
admin = "admin"
|
||||
user = "user"
|
||||
|
||||
class IssueStatus(str, Enum):
|
||||
new = "new"
|
||||
progress = "progress"
|
||||
complete = "complete"
|
||||
|
||||
class IssueCategory(str, Enum):
|
||||
material_missing = "material_missing"
|
||||
design_error = "design_error" # 설계미스 (기존 dimension_defect 대체)
|
||||
incoming_defect = "incoming_defect"
|
||||
inspection_miss = "inspection_miss" # 검사미스 (신규 추가)
|
||||
etc = "etc" # 기타
|
||||
|
||||
class ReviewStatus(str, Enum):
|
||||
pending_review = "pending_review" # 수신함 (검토 대기)
|
||||
in_progress = "in_progress" # 관리함 (진행 중)
|
||||
completed = "completed" # 관리함 (완료됨)
|
||||
disposed = "disposed" # 폐기함 (폐기됨)
|
||||
|
||||
class DisposalReasonType(str, Enum):
|
||||
duplicate = "duplicate" # 중복 (기본값)
|
||||
invalid_report = "invalid_report" # 잘못된 신고
|
||||
not_applicable = "not_applicable" # 해당 없음
|
||||
spam = "spam" # 스팸/오류
|
||||
custom = "custom" # 직접 입력
|
||||
|
||||
class DepartmentType(str, Enum):
|
||||
production = "production" # 생산
|
||||
quality = "quality" # 품질
|
||||
purchasing = "purchasing" # 구매
|
||||
design = "design" # 설계
|
||||
sales = "sales" # 영업
|
||||
|
||||
# User schemas
|
||||
class UserBase(BaseModel):
|
||||
username: str
|
||||
full_name: Optional[str] = None
|
||||
role: UserRole = UserRole.user
|
||||
department: Optional[DepartmentType] = None
|
||||
|
||||
class UserCreate(UserBase):
|
||||
password: str
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
full_name: Optional[str] = None
|
||||
password: Optional[str] = None
|
||||
role: Optional[UserRole] = None
|
||||
department: Optional[DepartmentType] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
class PasswordChange(BaseModel):
|
||||
current_password: str
|
||||
new_password: str
|
||||
|
||||
class User(UserBase):
|
||||
id: int
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Auth schemas
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
user: User
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: Optional[str] = None
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
|
||||
# Issue schemas
|
||||
class IssueBase(BaseModel):
|
||||
category: IssueCategory
|
||||
description: str
|
||||
project_id: int
|
||||
|
||||
class IssueCreate(IssueBase):
|
||||
photo: Optional[str] = None # Base64 encoded image
|
||||
photo2: Optional[str] = None
|
||||
photo3: Optional[str] = None
|
||||
photo4: Optional[str] = None
|
||||
photo5: Optional[str] = None
|
||||
|
||||
class IssueUpdate(BaseModel):
|
||||
category: Optional[IssueCategory] = None
|
||||
description: Optional[str] = None
|
||||
project_id: Optional[int] = None
|
||||
work_hours: Optional[float] = None
|
||||
detail_notes: Optional[str] = None
|
||||
status: Optional[IssueStatus] = None
|
||||
photo: Optional[str] = None # Base64 encoded image for update
|
||||
photo2: Optional[str] = None
|
||||
photo3: Optional[str] = None
|
||||
photo4: Optional[str] = None
|
||||
photo5: Optional[str] = None
|
||||
|
||||
class Issue(IssueBase):
|
||||
id: int
|
||||
photo_path: Optional[str] = None
|
||||
photo_path2: Optional[str] = None
|
||||
photo_path3: Optional[str] = None
|
||||
photo_path4: Optional[str] = None
|
||||
photo_path5: Optional[str] = None
|
||||
status: IssueStatus
|
||||
reporter_id: int
|
||||
reporter: User
|
||||
project_id: Optional[int] = None
|
||||
# project: Optional['Project'] = None # 순환 참조 방지를 위해 제거
|
||||
report_date: datetime
|
||||
work_hours: float
|
||||
detail_notes: Optional[str] = None
|
||||
|
||||
# 수신함 워크플로우 관련 필드들
|
||||
review_status: ReviewStatus
|
||||
disposal_reason: Optional[DisposalReasonType] = None
|
||||
custom_disposal_reason: Optional[str] = None
|
||||
disposed_at: Optional[datetime] = None
|
||||
reviewed_by_id: Optional[int] = None
|
||||
reviewed_at: Optional[datetime] = None
|
||||
original_data: Optional[Dict[str, Any]] = None
|
||||
modification_log: Optional[List[Dict[str, Any]]] = None
|
||||
|
||||
# 중복 신고 추적 시스템
|
||||
duplicate_of_issue_id: Optional[int] = None
|
||||
duplicate_reporters: Optional[List[Dict[str, Any]]] = None
|
||||
|
||||
# 관리함에서 사용할 추가 필드들
|
||||
solution: Optional[str] = None # 해결방안
|
||||
responsible_department: Optional[DepartmentType] = None # 담당부서
|
||||
responsible_person: Optional[str] = None # 담당자
|
||||
expected_completion_date: Optional[datetime] = None # 조치 예상일
|
||||
actual_completion_date: Optional[datetime] = None # 완료 확인일
|
||||
cause_department: Optional[DepartmentType] = None # 원인부서
|
||||
management_comment: Optional[str] = None # ISSUE에 대한 의견
|
||||
project_sequence_no: Optional[int] = None # 프로젝트별 순번
|
||||
final_description: Optional[str] = None # 최종 내용
|
||||
final_category: Optional[IssueCategory] = None # 최종 카테고리
|
||||
|
||||
# 추가 정보 필드들 (관리함에서 기록용)
|
||||
responsible_person_detail: Optional[str] = None # 해당자 상세 정보
|
||||
cause_detail: Optional[str] = None # 원인 상세 정보
|
||||
additional_info_updated_at: Optional[datetime] = None # 추가 정보 입력 시간
|
||||
additional_info_updated_by_id: Optional[int] = None # 추가 정보 입력자
|
||||
|
||||
# 완료 신청 관련 필드들
|
||||
completion_requested_at: Optional[datetime] = None # 완료 신청 시간
|
||||
completion_requested_by_id: Optional[int] = None # 완료 신청자
|
||||
completion_photo_path: Optional[str] = None # 완료 사진 1
|
||||
completion_photo_path2: Optional[str] = None # 완료 사진 2
|
||||
completion_photo_path3: Optional[str] = None # 완료 사진 3
|
||||
completion_photo_path4: Optional[str] = None # 완료 사진 4
|
||||
completion_photo_path5: Optional[str] = None # 완료 사진 5
|
||||
completion_comment: Optional[str] = None # 완료 코멘트
|
||||
|
||||
# 완료 반려 관련 필드들
|
||||
completion_rejected_at: Optional[datetime] = None # 완료 반려 시간
|
||||
completion_rejected_by_id: Optional[int] = None # 완료 반려자
|
||||
completion_rejection_reason: Optional[str] = None # 완료 반려 사유
|
||||
|
||||
# 일일보고서 추출 이력
|
||||
last_exported_at: Optional[datetime] = None # 마지막 일일보고서 추출 시간
|
||||
export_count: Optional[int] = 0 # 추출 횟수
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# 수신함 워크플로우 전용 스키마들
|
||||
class IssueDisposalRequest(BaseModel):
|
||||
"""부적합 폐기 요청"""
|
||||
disposal_reason: DisposalReasonType = DisposalReasonType.duplicate
|
||||
custom_disposal_reason: Optional[str] = None
|
||||
duplicate_of_issue_id: Optional[int] = None # 중복 대상 이슈 ID
|
||||
|
||||
class IssueReviewRequest(BaseModel):
|
||||
"""부적합 검토 및 수정 요청"""
|
||||
project_id: Optional[int] = None
|
||||
category: Optional[IssueCategory] = None
|
||||
description: Optional[str] = None
|
||||
modifications: Optional[Dict[str, Any]] = None
|
||||
|
||||
class IssueStatusUpdateRequest(BaseModel):
|
||||
"""부적합 상태 변경 요청"""
|
||||
review_status: ReviewStatus
|
||||
completion_photo: Optional[str] = None # 완료 사진 (Base64)
|
||||
solution: Optional[str] = None # 해결방안
|
||||
responsible_department: Optional[DepartmentType] = None # 담당부서
|
||||
responsible_person: Optional[str] = None # 담당자
|
||||
|
||||
class ManagementUpdateRequest(BaseModel):
|
||||
"""관리함에서 사용할 필드 업데이트 요청"""
|
||||
solution: Optional[str] = None # 해결방안
|
||||
responsible_department: Optional[DepartmentType] = None # 담당부서
|
||||
responsible_person: Optional[str] = None # 담당자
|
||||
expected_completion_date: Optional[datetime] = None # 조치 예상일
|
||||
cause_department: Optional[DepartmentType] = None # 원인부서
|
||||
management_comment: Optional[str] = None # ISSUE에 대한 의견
|
||||
completion_photo: Optional[str] = None # 완료 사진 (Base64)
|
||||
final_description: Optional[str] = None # 최종 내용 (부적합명 + 상세 내용)
|
||||
|
||||
class AdditionalInfoUpdateRequest(BaseModel):
|
||||
"""추가 정보 업데이트 요청 (관리함 진행중에서 사용)"""
|
||||
cause_department: Optional[DepartmentType] = None # 원인부서
|
||||
responsible_person_detail: Optional[str] = None # 해당자 상세 정보
|
||||
cause_detail: Optional[str] = None # 원인 상세 정보
|
||||
|
||||
class CompletionRequestRequest(BaseModel):
|
||||
"""완료 신청 요청"""
|
||||
completion_photo: Optional[str] = None # 완료 사진 1 (Base64)
|
||||
completion_photo2: Optional[str] = None # 완료 사진 2 (Base64)
|
||||
completion_photo3: Optional[str] = None # 완료 사진 3 (Base64)
|
||||
completion_photo4: Optional[str] = None # 완료 사진 4 (Base64)
|
||||
completion_photo5: Optional[str] = None # 완료 사진 5 (Base64)
|
||||
completion_comment: Optional[str] = None # 완료 코멘트
|
||||
|
||||
class CompletionRejectionRequest(BaseModel):
|
||||
"""완료 신청 반려 요청"""
|
||||
rejection_reason: str # 반려 사유
|
||||
|
||||
class ManagementUpdateRequest(BaseModel):
|
||||
"""관리함에서 이슈 업데이트 요청"""
|
||||
final_description: Optional[str] = None
|
||||
final_category: Optional[IssueCategory] = None
|
||||
solution: Optional[str] = None
|
||||
responsible_department: Optional[DepartmentType] = None
|
||||
responsible_person: Optional[str] = None
|
||||
expected_completion_date: Optional[str] = None
|
||||
cause_department: Optional[DepartmentType] = None
|
||||
management_comment: Optional[str] = None
|
||||
completion_comment: Optional[str] = None
|
||||
completion_photo: Optional[str] = None # Base64 - 완료 사진 1
|
||||
completion_photo2: Optional[str] = None # Base64 - 완료 사진 2
|
||||
completion_photo3: Optional[str] = None # Base64 - 완료 사진 3
|
||||
completion_photo4: Optional[str] = None # Base64 - 완료 사진 4
|
||||
completion_photo5: Optional[str] = None # Base64 - 완료 사진 5
|
||||
review_status: Optional[ReviewStatus] = None
|
||||
|
||||
class InboxIssue(BaseModel):
|
||||
"""수신함용 부적합 정보 (간소화된 버전)"""
|
||||
id: int
|
||||
category: IssueCategory
|
||||
description: str
|
||||
photo_path: Optional[str] = None
|
||||
photo_path2: Optional[str] = None
|
||||
project_id: Optional[int] = None
|
||||
reporter_id: int
|
||||
reporter: User
|
||||
report_date: datetime
|
||||
review_status: ReviewStatus
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class ModificationLogEntry(BaseModel):
|
||||
"""수정 이력 항목"""
|
||||
field: str
|
||||
old_value: Any
|
||||
new_value: Any
|
||||
modified_at: datetime
|
||||
modified_by: int
|
||||
|
||||
# Project schemas
|
||||
class ProjectBase(BaseModel):
|
||||
job_no: str = Field(..., min_length=1, max_length=50)
|
||||
project_name: str = Field(..., min_length=1, max_length=200)
|
||||
|
||||
class ProjectCreate(ProjectBase):
|
||||
pass
|
||||
|
||||
class ProjectUpdate(BaseModel):
|
||||
project_name: Optional[str] = Field(None, min_length=1, max_length=200)
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
class Project(ProjectBase):
|
||||
id: int
|
||||
created_by_id: int
|
||||
created_by: User
|
||||
created_at: datetime
|
||||
is_active: bool
|
||||
# issues: Optional[List['Issue']] = None # 순환 참조 방지를 위해 제거
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Daily Work schemas
|
||||
class DailyWorkBase(BaseModel):
|
||||
date: datetime
|
||||
worker_count: int = Field(gt=0)
|
||||
overtime_workers: Optional[int] = 0
|
||||
overtime_hours: Optional[float] = 0
|
||||
|
||||
class DailyWorkCreate(DailyWorkBase):
|
||||
pass
|
||||
|
||||
class DailyWorkUpdate(BaseModel):
|
||||
worker_count: Optional[int] = Field(None, gt=0)
|
||||
overtime_workers: Optional[int] = None
|
||||
overtime_hours: Optional[float] = None
|
||||
|
||||
class DailyWork(DailyWorkBase):
|
||||
id: int
|
||||
regular_hours: float
|
||||
overtime_total: float
|
||||
total_hours: float
|
||||
created_by_id: int
|
||||
created_by: User
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Report schemas
|
||||
class ReportRequest(BaseModel):
|
||||
start_date: datetime
|
||||
end_date: datetime
|
||||
|
||||
class CategoryStats(BaseModel):
|
||||
material_missing: int = 0
|
||||
dimension_defect: int = 0
|
||||
incoming_defect: int = 0
|
||||
|
||||
class ReportSummary(BaseModel):
|
||||
start_date: datetime
|
||||
end_date: datetime
|
||||
total_hours: float
|
||||
total_issues: int
|
||||
category_stats: CategoryStats
|
||||
completed_issues: int
|
||||
average_resolution_time: float
|
||||
|
||||
# Project Daily Work schemas
|
||||
class ProjectDailyWorkBase(BaseModel):
|
||||
date: datetime
|
||||
project_id: int
|
||||
hours: float
|
||||
|
||||
class ProjectDailyWorkCreate(ProjectDailyWorkBase):
|
||||
pass
|
||||
|
||||
class ProjectDailyWork(ProjectDailyWorkBase):
|
||||
id: int
|
||||
created_by_id: int
|
||||
created_at: datetime
|
||||
project: Project
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# 일일보고서 관련 스키마
|
||||
class DailyReportRequest(BaseModel):
|
||||
project_id: int
|
||||
|
||||
class DailyReportStats(BaseModel):
|
||||
total_count: int = 0
|
||||
management_count: int = 0 # 관리처리 현황 (진행 중)
|
||||
completed_count: int = 0
|
||||
delayed_count: int = 0
|
||||
Reference in New Issue
Block a user