환경 초기화 및 벤더 리포지토리 스켈레톤 도입
This commit is contained in:
151
doc/API_CLIENT_SPEC.md
Normal file
151
doc/API_CLIENT_SPEC.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# ApiClient 설계서 (Dio 기반, Superport 스타일)
|
||||
|
||||
본 문서는 Superport 레포 스타일과 동일한 인증/네트워킹 패턴을 본 프로젝트에 적용하기 위한 ApiClient 설계를 정의한다. 실제 구현은 이후 단계에서 진행한다(문서 선정리).
|
||||
|
||||
## 1) 목표
|
||||
- 단일 진입점 ApiClient(Dio 래퍼)로 모든 네트워크 호출 일원화
|
||||
- 환경 변수 기반 BaseURL/타임아웃/로그 레벨 설정
|
||||
- 인증 토큰 주입, 401 자동 처리(토큰 갱신 → 재시도), 에러 매핑 일관화
|
||||
- 목록/단건 표준 응답 구조에 맞춘 헬퍼 제공
|
||||
|
||||
## 2) 의존성(추가 예정)
|
||||
- dio: ^5.x (HTTP 클라이언트)
|
||||
- get_it: ^7.x (DI) — 이미 사용 중
|
||||
- flutter_secure_storage(or web localStorage 대체): 토큰 저장(플랫폼별 분기)
|
||||
- intl: ^0.20.x (기존)
|
||||
- 개발 전용: pretty_dio_logger(선택)
|
||||
|
||||
## 3) 환경 변수
|
||||
- API_BASE_URL: 예) https://api.example.com/api/v1
|
||||
- API_CONNECT_TIMEOUT_MS: 예) 15000
|
||||
- API_RECEIVE_TIMEOUT_MS: 예) 30000
|
||||
- LOG_LEVEL: debug|info|warn|error
|
||||
|
||||
로드 순서: `await Environment.initialize()` → DI에서 ApiClient 생성 시 사용
|
||||
|
||||
## 4) 인증 방식(슈퍼포트와 동일)
|
||||
- 로그인: `POST /auth/login` → `{ data: { token: string, user?: {...} } }`
|
||||
- 요청 헤더: `Authorization: Bearer <token>`
|
||||
- 토큰 저장: 보안 저장소(모바일)/localStorage(웹) 또는 httpOnly 쿠키(백엔드 정책에 따름)
|
||||
- 토큰 갱신(선택): `POST /auth/refresh` → `{ data: { token: string } }`
|
||||
- 401 처리: `AuthInterceptor`가 401 수신 시 자동 갱신 → 원요청 재시도(1회). 갱신 실패 시 로그아웃/세션 초기화 및 로그인 화면 이동
|
||||
|
||||
## 5) 에러 매핑 정책
|
||||
- 400 BAD_REQUEST: 검증 오류 → 필드 에러로 매핑
|
||||
- 404 NOT_FOUND: 리소스 없음
|
||||
- 409 CONFLICT: 유니크 충돌/상태 충돌
|
||||
- 422 UNPROCESSABLE_ENTITY: 비즈니스 규칙 위반(예: 출고 고객 미선택, blocking 전이)
|
||||
- 500+: 서버 오류 → 공통 메시지 + 로그 수집
|
||||
- 표준 포맷: `{ error: { code, message, details? } }` 수용. 비표준 응답은 DioException 메시지로 대체
|
||||
|
||||
## 6) 쿼리 규약/헬퍼
|
||||
- 페이지네이션: `page`, `page_size`
|
||||
- 정렬: `sort`, `order=asc|desc`
|
||||
- 검색: `q`
|
||||
- 증분: `updated_since`
|
||||
- include 확장: `include=lines,customers,approval` 등
|
||||
- 헬퍼: `buildQuery({page, pageSize, q, sort, order, include, filters})`
|
||||
|
||||
## 7) ApiClient 스켈레톤(인터페이스)
|
||||
|
||||
```dart
|
||||
/// 네트워크 공통 클라이언트 (Dio 래퍼)
|
||||
class ApiClient {
|
||||
// 내부 Dio 인스턴스(외부 사용 금지, 필요한 경우 read-only 게터 제공)
|
||||
final Dio _dio;
|
||||
|
||||
ApiClient({required Dio dio}) : _dio = dio;
|
||||
|
||||
Dio get dio => _dio; // 과도한 사용은 지양하고, 가능하면 아래 헬퍼 사용
|
||||
|
||||
Future<Response<T>> get<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? query,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
});
|
||||
|
||||
Future<Response<T>> post<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? query,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
});
|
||||
|
||||
Future<Response<T>> patch<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? query,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
});
|
||||
|
||||
Future<Response<T>> delete<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? query,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
구현 시 기본 옵션
|
||||
- BaseOptions: baseUrl, connectTimeout, receiveTimeout
|
||||
- 공통 헤더: `Accept: application/json`, `Authorization: Bearer <token?>`
|
||||
- Interceptors:
|
||||
- `AuthInterceptor`(요청 전 토큰 주입, 401에서 갱신/재시도)
|
||||
- `LoggingInterceptor`(개발 모드에서만)
|
||||
|
||||
## 8) Interceptor 설계
|
||||
- AuthInterceptor
|
||||
- 요청: 저장된 토큰이 있으면 `Authorization` 헤더 추가
|
||||
- 응답: 401이면 1) 갱신 중 동시성 잠금 2) 갱신 성공 시 대기 중 요청 재시도 3) 실패 시 토큰 삭제/로그아웃
|
||||
- Retry 정책: 재시도는 1회, idempotent GET/HEAD 위주. POST/PATCH는 401 갱신 후 재시도 1회만 허용
|
||||
|
||||
## 9) 표준 응답 파서
|
||||
- 목록: `{ items: [...], page, page_size, total }`
|
||||
- 단건: `{ data: {...} }`
|
||||
- 제네릭 파서 유틸 제공: `parseList<T>(res, fromJson)`, `parseItem<T>(res, fromJson)`
|
||||
|
||||
## 10) 샘플 사용 (Repository)
|
||||
|
||||
```dart
|
||||
class VendorRepositoryImpl implements VendorRepository {
|
||||
final ApiClient api;
|
||||
VendorRepositoryImpl(this.api);
|
||||
|
||||
@override
|
||||
Future<Paged<Vendor>> list({int page = 1, int pageSize = 20, String? q}) async {
|
||||
final res = await api.get('/vendors', query: { 'page': page, 'page_size': pageSize, if (q != null) 'q': q });
|
||||
return parseList<Vendor>(res.data, Vendor.fromJson);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Vendor> create(VendorCreate body) async {
|
||||
final res = await api.post('/vendors', data: body.toJson());
|
||||
return parseItem<Vendor>(res.data, Vendor.fromJson);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11) 보안/스토리지
|
||||
- 토큰 저장: 플랫폼별로 적합한 저장소 사용(웹은 localStorage, 모바일은 secure storage)
|
||||
- 민감정보 로깅 금지(토큰/쿠키 마스킹)
|
||||
- CORS/쿠키 기반 인증 사용 시, Dio 요청에 `withCredentials=true` 설정 필요(백엔드 정책에 따름)
|
||||
|
||||
## 12) 테스트 전략
|
||||
- 위젯/도메인 테스트: 네트워크 의존 제거(리포지토리를 테스트 더블로 대체)
|
||||
- 통합 테스트: 실제 스테이징 API를 사용하여 로그인→호출→401→갱신→재시도 플로우 검증
|
||||
|
||||
## 13) 구현 순서 요약(체크)
|
||||
- [ ] pubspec에 `dio`(필수), `pretty_dio_logger`(개발) 추가
|
||||
- [ ] `ApiClient`/`AuthInterceptor` 스켈레톤 작성
|
||||
- [ ] `Environment.initialize()` → `get_it` DI에서 ApiClient 생성/주입
|
||||
- [ ] 리포지토리 구현에서 ApiClient 사용으로 통일(직접 Dio 인스턴스화 금지)
|
||||
- [ ] 에러/토큰/재시도 정책 위젯 레벨 연결(토스트/로그아웃)
|
||||
|
||||
참고
|
||||
- Superport 레포: `.env`의 `API_BASE_URL`, `test_api_integration.sh`의 `/auth/login` + Bearer 사용
|
||||
- 본 프로젝트: AGENTS.md의 “Do not use mock data” 및 DI/레이어 경계 정책 준수
|
||||
119
doc/IMPLEMENTATION_TASKS.md
Normal file
119
doc/IMPLEMENTATION_TASKS.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Superport v2 프론트엔드 구현 Task List (UI First → API Integration)
|
||||
|
||||
본 체크리스트는 PRD(`doc/PRD_입출고_결재_v2.md`)를 기준으로 shadcn_ui 스타일과 반응형 패턴을 준수하여 화면을 구현하기 위한 단계별 작업 목록입니다. 작업 순서는 ① 코드 시작 전 최종 확인 → ② UI 스캐폴딩/상호작용 구현 → ③ 실제 API 연동(Dio/ApiClient/DI)입니다. Mock 데이터는 사용하지 않습니다.
|
||||
|
||||
## 0) 코드 시작 전 최종 확인(Repository/환경)
|
||||
- [ ] Flutter 버전/채널 확인, `flutter pub get`
|
||||
- [ ] `pubspec.yaml` 확인: `go_router`, `shadcn_ui`, `intl`, `two_dimensional_scrollables`, `lucide_icons_flutter` 포함
|
||||
- [ ] `Environment.initialize()` 호출 및 `.env.development`/`.env.production`에서 `API_BASE_URL`/`TIMEOUT_MS`/`LOG_LEVEL` 로드
|
||||
- [ ] 라우팅 스켈레톤(go_router) 구성: 로그인/대시보드/입·출·대여/마스터/결재/보고서
|
||||
- [ ] 글로벌 테마/ShadTheme 확인(폰트/간격/배지/버튼 일관)
|
||||
|
||||
## 1) 공통 컴포넌트/레이아웃(UI)
|
||||
- [ ] AppLayout(좌 사이드바/상단 헤더/본문) 적용, 브레드크럼·타이틀·툴바 영역 정리
|
||||
- [ ] 테이블: `ShadTable.list` 표준화(고정 헤더/가로 스크롤/소팅/페이지네이션 UI만)
|
||||
- [ ] 모달: `SuperportShadDialog`(헤더/본문/푸터 분리, 모바일 풀스크린) 공통 wrapper
|
||||
- [ ] 입력 위젯: `ShadInput/Select/Switch`, `SuperportShadDatePicker/RangePicker` 적용 가이드
|
||||
- [ ] 필터바(검색/기간/상태/창고/Reset) 공통 위젯
|
||||
- [ ] 반응형 프리셋: 데스크톱/태블릿/모바일 열 가시성 설정(섹션 12 규칙 반영)
|
||||
- [ ] 토스트/스낵바/스켈레톤/Empty 상태 공통 처리
|
||||
|
||||
## 2) 인증/대시보드(UI)
|
||||
- [ ] 로그인 화면(`/login`): 아이디/비밀번호 UI(제출/로딩/에러 표시 흐름)
|
||||
- [ ] 대시보드(`/`): KPI 카드, 최근 트랜잭션, 내 결재 대기 리스트 — 스켈레톤/Empty 상태 구현
|
||||
|
||||
## 3) 입고(`/inbounds`) UI
|
||||
- [ ] 라우트/네비게이션 연결
|
||||
- [ ] 목록 테이블: 번호/처리일자/창고/트랜잭션번호/상태/작성자/품목수/총수량/비고
|
||||
- [ ] 필터: 기간/창고/상태/검색, 소팅/페이지네이션
|
||||
- [ ] 신규 모달: 헤더(처리일자/창고/상태/작성자/비고) + 시스템 필드(`transaction_type_id=입고` RO/숨김)
|
||||
- [ ] 라인 테이블: 제품(자동완성)→제조사/단위 자동, 수량/단가/비고, (+)/(−) 행 편집
|
||||
- [ ] 검증: 필수/수량>=1/단가>=0, 상단 요약 + 인라인 에러
|
||||
- [ ] 수정 모달: 작성자/트랜잭션번호 RO, 종결 상태 수정 제한
|
||||
|
||||
## 4) 출고(`/outbounds`) UI
|
||||
- [ ] 목록 테이블: 번호/처리일자/창고/트랜잭션번호/상태/작성자/고객수/품목수/총수량/비고
|
||||
- [ ] 필터: 기간/창고/상태/고객/검색
|
||||
- [ ] 신규/수정 모달: 헤더(…)+ 시스템 필드(`transaction_type_id=출고` RO/숨김)
|
||||
- [ ] 고객 연결(멀티): 고객사 자동완성 → 토큰/칩 UI, 최소 1건 검증
|
||||
- [ ] 라인 테이블: 제품/제조사RO/단위RO/수량/단가/비고
|
||||
|
||||
## 5) 대여(`/rentals`) UI
|
||||
- [ ] 목록 테이블: 번호/처리일자/창고/대여구분/트랜잭션번호/상태/반납예정일/고객수/품목수/비고
|
||||
- [ ] 필터: 기간/창고/상태/대여구분/반납예정일 범위/검색
|
||||
- [ ] 신규/수정 모달: 헤더(…/대여구분/반납예정일) + 시스템 필드(`transaction_type_id` 대여/반납 자동 매핑)
|
||||
- [ ] 고객 연결(멀티) + 라인 테이블(입고·출고와 동일)
|
||||
- [ ] 규칙: 대여구분은 종결 후 변경 불가, 반납예정일은 진행 중 수정 가능
|
||||
|
||||
## 6) 마스터(UI)
|
||||
- [ ] 벤더: 목록/필터(q/사용여부), 신규/수정(코드RO), 삭제/복구 UI
|
||||
- [ ] 제품: 목록/필터(q/제조사/단위/사용), 신규/수정(코드RO)
|
||||
- [ ] 창고: 목록/필터(q/사용), 신규/수정(우편번호 검색 모달 UI 연동)
|
||||
- [ ] 고객사: 목록/필터(q/유형/사용), 신규/수정(유형→is_partner/is_general 매핑 UI)
|
||||
- [ ] 사용자: 목록/필터(q/그룹/사용), 신규/수정(사번RO)
|
||||
- [ ] 그룹: 목록/필터(q/기본/사용), 신규/수정(그룹명RO)
|
||||
- [ ] 메뉴: 목록/필터(q/상위/사용), 신규/수정(메뉴코드RO)
|
||||
- [ ] 그룹 권한: 목록/필터(그룹/메뉴/사용), 체크박스 매트릭스 편집 UI
|
||||
|
||||
## 7) 결재(UI)
|
||||
- [ ] 결재(`/approvals`): 목록/필터, 상세(개요/단계/이력 탭)
|
||||
- [ ] 템플릿 불러오기: 단계 탭에서 템플릿 선택 UI(단계 리스트 반영)
|
||||
- [ ] 단계 행위: 승인/반려/코멘트 버튼(가능 여부 상태에 따라 비활성/툴팁)
|
||||
- [ ] 단계 관리(`/approval-steps`): 목록/편집(신규/수정)
|
||||
- [ ] 이력(`/approval-histories`): 조회 전용 테이블
|
||||
- [ ] 템플릿(`/approval-templates`): 목록/헤더+단계 반복 폼
|
||||
|
||||
## 8) 우편번호 검색 모달(UI)
|
||||
- [ ] 입력: 검색어 텍스트
|
||||
- [ ] 결과 테이블: 우편번호/시도/시군구/도로명/건물번호
|
||||
- [ ] 선택 시: 부모 폼 `zipcode`/주소 구성요소 채움
|
||||
|
||||
## 9) 보고서(`/reports`) UI
|
||||
- [ ] 조건 폼: 기간/유형/창고/상태
|
||||
- [ ] 액션: XLSX/PDF 버튼 — 미제공 시 버튼 비활성 UI(연동은 API 단계에서)
|
||||
|
||||
## 10) 데이터 계층/상태 관리
|
||||
- [ ] 리포지토리 인터페이스(domain) 정의 및 구현(data): 트랜잭션/결재/마스터/룩업/우편번호
|
||||
- [ ] DTO ↔ 도메인 엔티티 매핑(응답 `{ items }`/`{ data }` 구조 표준화)
|
||||
- [ ] 페이지네이션 상태(현재 페이지/사이즈/전체) 및 필터 상태 싱크(go_router querystring 연동)
|
||||
- [ ] 정렬/검색/Include 옵션 직렬화 및 유지
|
||||
|
||||
## 11) API 연동 단계(Dio/ApiClient/DI)
|
||||
- [ ] 네트워킹 패키지 추가: `dio:^5.x`, `pretty_dio_logger`(dev 선택), 토큰 저장용 `flutter_secure_storage`(모바일)/웹 스토리지
|
||||
- [ ] `ApiClient`/`AuthInterceptor` 스켈레톤 작성(설계: `doc/API_CLIENT_SPEC.md`)
|
||||
- [ ] `Environment.initialize()` → `get_it` DI에서 ApiClient 생성/주입
|
||||
- [ ] 공통 에러 매핑(400/404/409/422) 및 토스트/필드 바인딩 연결
|
||||
- [ ] 메뉴/권한 로딩 → 버튼/액션 노출 제어
|
||||
- [ ] 각 화면 API 연결:
|
||||
- 입고/출고/대여: 목록/상세/생성/수정/삭제/복구 + include/필터/정렬/페이지네이션
|
||||
- 마스터: vendors/products/warehouses/customers/employees/menus/groups/group-permissions(+ 일괄 저장)
|
||||
- 결재: approvals(+steps/histories), actions, can-proceed, 템플릿 CRUD/단계 배치
|
||||
- 우편번호: `GET /zipcodes?...`
|
||||
- 보고서: 다운로드 엔드포인트 연동(제공 시)
|
||||
|
||||
## 12) 검증/접근성/상호작용
|
||||
- [ ] 필수/형식/업무 규칙 검증(출고/대여 고객 최소 1건 등)
|
||||
- [ ] 키보드: Esc 닫기, Enter 제출/셀 이동, Tab 포커스 이동, 포커스 트랩
|
||||
- [ ] 합계/요약 배지 실시간 반영(수량/단가 변경 시)
|
||||
|
||||
## 13) 반응형/열 가시성
|
||||
- [ ] 데스크톱/태블릿/모바일 프리셋 구현(PRD 섹션 12 규칙 적용)
|
||||
- [ ] 모바일 카드형 요약(핵심 3~4필드) 구성
|
||||
|
||||
## 14) 테스트/품질
|
||||
- [ ] `flutter analyze` 경고 0
|
||||
- [ ] 위젯 테스트: 테이블 렌더/필터/페이지네이션/모달 열기/검증 메시지
|
||||
- [ ] 내비 통합 테스트(선택): 로그인 → 대시보드 → 입/출/대여 → 결재 → 마스터
|
||||
- [ ] `dart format .` 적용
|
||||
|
||||
## 15) Definition of Done(DoD)
|
||||
- [ ] 모든 목록/폼/모달/필터/페이지네이션 동작
|
||||
- [ ] 모바일/태블릿/데스크톱 레이아웃 검증(핵심 열 가시성)
|
||||
- [ ] 실제 API로 주요 플로우(신규/수정/삭제/복구) 검증 완료
|
||||
- [ ] 문서 최신화(PRD/체크리스트)
|
||||
|
||||
## 참고
|
||||
- PRD: `doc/PRD_입출고_결재_v2.md`
|
||||
- 사양: `doc/stock_approval_system_spec_v4.md`, `doc/stock_approval_system_api_v4.md`
|
||||
- 네트워킹 설계: `doc/API_CLIENT_SPEC.md`
|
||||
- 스타일 참조: `/Users/maximilian.j.sul/Documents/flutter/superport`
|
||||
538
doc/PRD_입출고_결재_v2.md
Normal file
538
doc/PRD_입출고_결재_v2.md
Normal file
@@ -0,0 +1,538 @@
|
||||
# Superport v2 입·출고 + 결재 시스템 PRD (Draft v1)
|
||||
|
||||
본 문서는 `doc/입출고 대여 폼 정리.md`, `doc/stock_approval_system_spec_v4.md`, `doc/stock_approval_system_api_v4.md`를 근거로 Flutter 웹 프론트엔드 구현을 위한 상세 요구사항을 정리한다. 스타일은 `/Users/maximilian.j.sul/Documents/flutter/superport`의 UI/UX 패턴을 준수한다.
|
||||
|
||||
## 1. 범위 및 목표
|
||||
- 범위: 로그인/대시보드/입고/출고/대여/마스터(벤더, 제품, 창고, 고객사, 사용자, 그룹, 메뉴, 권한)/결재(결재, 단계, 이력, 템플릿)/보고서.
|
||||
- 목표: 백엔드 API와 연동하여 화면/네비게이션/상호작용(폼 검증, 필터, 페이징, 모달)을 완성. DTO/리포지토리 인터페이스를 분리해 유지보수를 용이하게 함.
|
||||
- 기술: Flutter + shadcn_ui + go_router + two_dimensional_scrollables. 반응형 웹 최적화.
|
||||
- 제약: 입력·수정 폼은 팝업 모달(ShadDialog 기반)로 노출. 테이블은 ShadTable 계열 사용.
|
||||
|
||||
## 2. 전역 UX/스타일 가이드
|
||||
- 레이아웃(AppLayout): 좌측 사이드바 내비게이션 + 상단 헤더(타이틀, 브레드크럼, 액션) + 콘텐츠.
|
||||
- 컴포넌트(슈퍼포트 준수):
|
||||
- 테이블: `ShadTable.list`(고정 헤더, 필요 시 첫 컬럼 고정, 가로 스크롤 허용).
|
||||
- 버튼: `ShadButton.(primary|outline|ghost)`, 행 액션은 `ghost` 아이콘 버튼.
|
||||
- 입력: `ShadInput`, `ShadSelect`, `SuperportShadDatePicker/DateRangePicker`, `ShadSwitch`, `ShadBadge`, `ShadTooltip`.
|
||||
- 모달: `SuperportShadDialog`(헤더/본문/푸터 구분, ESC/배경 클릭 닫기 옵션).
|
||||
- 페이징: 테이블 하단 우측 `page / perPage / total` 표시 + 페이지네이션.
|
||||
- 필터/검색 바: 테이블 상단. 기본 `검색(q)` + 주요 조건(기간/상태/창고 등). `Reset` 버튼 제공.
|
||||
- 정렬: 테이블 헤더 클릭 1열 정렬(추후 멀티 정렬 확장 가능).
|
||||
- 반응형:
|
||||
- Breakpoints: `>=1280` 데스크톱 3열, `>=1024` 2열, `>=768` 2열(compact), `<768` 1열 카드형 목록 대체 및 모달 전면(full-screen) 전환.
|
||||
- 테이블은 작은 화면에서 핵심 컬럼만 우선 노출(열 가시성 프리셋), 나머지는 가로 스크롤.
|
||||
- 접근성: 포커스 트랩, 키보드 내비게이션(Tab/Enter/Esc), 명확한 에러 메시지.
|
||||
- 로딩/빈 상태: Skeleton과 Empty 상태 메시지(“조건을 변경해 보세요”). 오류는 Toaster로 노출.
|
||||
|
||||
## 3. 권한/메뉴 정책(뷰 관점)
|
||||
- 그룹 기반 메뉴 권한(`group_menu_permissions`)은 서버 응답을 기반으로 적용: `can_create/read/update/delete`에 따라 버튼/액션 노출 제어.
|
||||
- 메뉴 트리: 대시보드, 입고, 출고, 대여, 마스터(벤더, 제품, 창고, 고객사, 사용자, 그룹, 메뉴, 권한), 결재(결재, 단계, 이력, 템플릿), 보고서.
|
||||
|
||||
## 4. 공통 데이터 소스 매핑(드롭다운/자동입력)
|
||||
- 공통 룩업:
|
||||
- 단위: `/uoms` → `uom_name` 표시
|
||||
- 트랜잭션 유형: `/transaction-types` (입고/출고/대여/반납) — 화면 진입 시 자동 지정 또는 대여구분에 따라 자동 매핑
|
||||
- 트랜잭션 상태: `/transaction-statuses`(대기/진행/보류/승인/반려 등)
|
||||
- 결재 상태: `/approval-statuses`(blocking/terminal 속성 포함)
|
||||
- 결재 행위: `/approval-actions`(approve/reject/comment)
|
||||
- 마스터:
|
||||
- 창고: `/warehouses`(우편번호/주소 포함)
|
||||
- 벤더: `/vendors`
|
||||
- 제품: `/products?include=vendor,uom`(제품 선택 시 제조사/단위 자동 세팅, RO)
|
||||
- 고객사: `/customers`(유형 플래그: 파트너/일반)
|
||||
- 사원: `/employees`
|
||||
- 공통 자동입력/읽기전용 규칙:
|
||||
- `작성자`: 로그인 사용자로 자동 세팅(RO).
|
||||
- `트랜잭션번호/결재번호`: 생성 시 자동 발번(RO)·수정 불가.
|
||||
- `생성일시/변경일시`: RO.
|
||||
- 제품 선택 시 `제조사/단위` 자동 세팅(RO). 수량/단가 변경 시 `합계` 자동 계산(표시용).
|
||||
- 고객사 유형(파트너/일반) 선택은 내부적으로 `is_partner`/`is_general` 불린 필드로 매핑하여 저장.
|
||||
|
||||
## 5. 화면별 상세 사양
|
||||
|
||||
### 5.0 로그인/로그아웃
|
||||
- 라우트: `/login`
|
||||
- 목적: 세션 시작/종료(로컬 상태). 성공 시 대시보드로 이동.
|
||||
- 입력(모달 아님): 아이디[TXT], 비밀번호[PWD].
|
||||
- 검증: 아이디/비밀번호 필수. 실제 인증 성공 후 사용자/그룹/권한/메뉴를 서버에서 로딩.
|
||||
|
||||
### 5.1 대시보드
|
||||
- 라우트: `/`
|
||||
- 목적: 당일 입고/출고/대기 결재 위젯, 최근 트랜잭션, 내 결재 대기 요약.
|
||||
- 위젯:
|
||||
- KPI 배지: 오늘 입고/출고 건수, 대기 결재 수.
|
||||
- 최근 트랜잭션: 번호, 일자, 유형, 상태, 작성자.
|
||||
- 내 결재 대기: 결재번호, 현재 단계, 요청일시.
|
||||
|
||||
### 5.2 입고(Stock Inbound)
|
||||
- 라우트: `/inbounds`
|
||||
- 역할: 구매/반입 처리. 라인에 제품/수량/단가 입력.
|
||||
- 테이블 컬럼: 번호(id), 처리일자(processed_at), 창고(warehouse_name), 트랜잭션번호(transaction_no), 상태(status_name), 작성자(employee_name), 품목수(line_count), 총수량(total_qty), 비고(note).
|
||||
- 기본 정렬: `processed_at desc`.
|
||||
- 필터: 기간, 창고, 상태, 검색(q: 번호/비고 등).
|
||||
- 행 액션: 상세(모달), 수정(모달), 삭제(소프트), 복구.
|
||||
- 신규(모달: “입고 등록”):
|
||||
- 헤더 섹션: 처리일자[DT, 필수], 창고[DD, 필수], 상태[DD, 기본=대기], 작성자[자동, RO], 비고[TXT].
|
||||
- 시스템 필드: 입출고유형[RO/숨김, `transaction_type_id`=입고] — 라우트 진입 시 고정 설정.
|
||||
- 라인 섹션(ShadTable):
|
||||
- 제품[DD/자동완성, 필수] → 선택 시 제조사[RO], 단위[RO] 자동 표시
|
||||
- 수량[NUM, >=1, 필수], 단가[NUM, >=0], 비고[TXT]
|
||||
- (+)행 추가, (−)행 삭제, 최소 1행 필수
|
||||
- 검증: 전역 에러 바인딩(상단), 행 단위 인라인 에러.
|
||||
- 수정(모달: “입고 수정”):
|
||||
- 읽기전용: 작성자, 트랜잭션번호.
|
||||
- 상태는 일부 제한(승인/반려 등 종결 상태는 수정 불가).
|
||||
|
||||
### 5.3 출고(Stock Outbound)
|
||||
- 라우트: `/outbounds`
|
||||
- 역할: 출하/반출 처리. 고객사 연결 필수.
|
||||
- 테이블 컬럼: 번호, 처리일자, 창고, 트랜잭션번호, 상태, 작성자, 고객수, 품목수, 총수량, 비고.
|
||||
- 필터: 기간, 창고, 상태, 고객사, 검색.
|
||||
- 신규/수정 모달:
|
||||
- 헤더: 처리일자[DT], 창고[DD], 상태[DD], 작성자[RO], 비고[TXT].
|
||||
- 시스템 필드: 입출고유형[RO/숨김, `transaction_type_id`=출고] — 라우트 진입 시 고정 설정.
|
||||
- 고객 연결: 고객사[DD-멀티|자동완성, 최소 1건], 비고[TXT].
|
||||
- 라인: 제품[DD/자동완성], 제조사[RO], 단위[RO], 수량[NUM], 단가[NUM], 비고.
|
||||
- 규칙: 고객 최소 1건 없으면 저장 불가.
|
||||
|
||||
### 5.4 대여(Rental)
|
||||
- 라우트: `/rentals`
|
||||
- 역할: 대여/반납 트랜잭션 관리.
|
||||
- 테이블 컬럼: 번호, 처리일자, 창고, 대여/반납(유형), 트랜잭션번호, 상태, 반납예정일, 고객수, 품목수, 비고.
|
||||
- 필터: 기간, 창고, 상태, 대여구분, 반납예정일 범위, 검색.
|
||||
- 신규/수정 모달:
|
||||
- 헤더: 처리일자[DT], 창고[DD], 상태[DD], 작성자[RO], 대여구분[DD: 대여/반납], 반납예정일[DT], 비고[TXT].
|
||||
- 시스템 필드: 입출고유형[RO/숨김, `transaction_type_id`=대여/반납(대여구분에 따라 자동 매핑)].
|
||||
- 고객 연결: 고객사[DD-멀티], 비고.
|
||||
- 라인: 제품[DD/자동완성], 제조사[RO], 단위[RO], 수량[NUM], 단가[NUM], 비고.
|
||||
- 규칙: 대여구분은 진행 중 제약(종결 후 변경 불가), 반납예정일은 수정 가능.
|
||||
|
||||
### 5.5 제조사 관리(벤더)
|
||||
- 라우트: `/masters/vendors`
|
||||
- 테이블: 번호, 벤더코드, 벤더명, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규(모달): 벤더코드[TXT, 고유], 벤더명[TXT], 사용여부[SW], 비고[TXT].
|
||||
- 수정(모달): 벤더코드[RO], 생성/변경일시[RO].
|
||||
|
||||
### 5.6 장비 모델 관리(제품)
|
||||
- 라우트: `/masters/products`
|
||||
- 테이블: 번호, 제품코드, 제품명, 제조사, 단위, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 제조사, 단위, 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규: 제품코드[TXT], 제품명[TXT], 제조사[DD], 단위[DD], 사용여부[SW], 비고.
|
||||
- 수정: 제품코드[RO], 생성일시[RO].
|
||||
|
||||
### 5.7 입고지 관리(창고)
|
||||
- 라우트: `/masters/warehouses`
|
||||
- 테이블: 번호, 창고코드, 창고명, 우편번호, 상세주소, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규/수정: 창고코드[TXT], 창고명[TXT], 우편번호[검색 모달], 상세주소[TXT], 사용여부[SW], 비고. 코드/일시는 RO.
|
||||
- 우편번호 검색: 전용 모달(입력: 검색어 → 결과 리스트에서 선택 시 필드 채움).
|
||||
|
||||
### 5.8 회사 관리(고객사)
|
||||
- 라우트: `/masters/customers`
|
||||
- 테이블: 번호, 고객사코드, 고객사명, 유형, 이메일, 연락처, 우편번호, 상세주소, 사용여부, 비고.
|
||||
- 필터: 검색(q), 유형, 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규: 고객사코드[TXT], 고객사명[TXT], 유형(파트너/일반)[DD(복수 선택 가능)], 이메일[TXT], 연락처[TXT], 우편번호[검색], 상세주소[TXT], 사용여부[SW], 비고.
|
||||
- 수정: 고객사코드/생성일시 RO.
|
||||
|
||||
### 5.9 사용자 관리(사원)
|
||||
- 라우트: `/masters/employees`
|
||||
- 테이블: 번호, 사번, 성명, 이메일, 연락처, 그룹, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 그룹, 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규: 사번[TXT], 성명[TXT], 이메일[TXT], 연락처[TXT], 그룹[DD], 사용여부[SW], 비고.
|
||||
- 수정: 사번/생성일시 RO.
|
||||
|
||||
### 5.10 그룹 관리
|
||||
- 라우트: `/masters/groups`
|
||||
- 테이블: 번호, 그룹명, 설명, 기본여부, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 기본여부, 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규: 그룹명[TXT], 설명[TXT], 기본여부[SW], 사용여부[SW], 비고.
|
||||
- 수정: 그룹명/생성일시 RO.
|
||||
|
||||
### 5.11 메뉴 관리
|
||||
- 라우트: `/masters/menus`
|
||||
- 테이블: 번호, 메뉴코드, 메뉴명, 상위메뉴, 경로, 사용여부, 비고, 변경일시.
|
||||
- 필터: 검색(q), 상위메뉴, 사용여부, 삭제 포함(고급) 토글.
|
||||
- 신규: 메뉴코드[TXT], 메뉴명[TXT], 상위메뉴[DD], 경로[TXT], 표시순서[NUM], 사용여부[SW], 비고.
|
||||
- 수정: 메뉴코드/생성일시 RO.
|
||||
|
||||
### 5.12 그룹 메뉴 권한 관리
|
||||
- 라우트: `/masters/group-permissions`
|
||||
- 테이블: 번호, 그룹명, 메뉴명, 생성, 조회, 수정, 삭제, 사용여부, 변경일시.
|
||||
- 필터: 그룹, 메뉴, 사용여부.
|
||||
- 신규: 그룹[DD], 메뉴[DD], 생성/조회/수정/삭제[CHK], 사용여부[SW].
|
||||
- 수정: 그룹/메뉴 RO.
|
||||
|
||||
### 5.13 결재 관리(Approvals)
|
||||
- 라우트: `/approvals`
|
||||
- 테이블: 번호, 결재번호, 트랜잭션번호, 상태, 상신자, 요청일시, 최종결정일시, 비고.
|
||||
- 신규: 트랜잭션번호[DD], 결재번호[자동], 결재상태[DD(기본=대기)], 상신자[자동], 비고.
|
||||
- 상세(우측 패널 또는 모달 탭):
|
||||
- 개요: 현재 상태/현재 단계/상신자/요청일시/결정일시
|
||||
- 단계 탭: 단계 리스트(step_order, 승인자, 상태, 배정/결정 일시) + [템플릿 불러오기] 버튼 → 템플릿 선택 후 단계 일괄 생성(`POST /approvals/{id}/steps`)
|
||||
- 이력 탭: 행위/변경 전/후 상태/일시/비고
|
||||
- 단계 행위(행 액션): 승인/반려/코멘트(결재 상태 규칙에 따라 전이 가능 여부 표시).
|
||||
|
||||
### 5.14 결재 단계 관리(Approval Steps)
|
||||
- 라우트: `/approval-steps`
|
||||
- 테이블: 번호, 결재ID, 단계순서, 승인자, 상태, 배정일시, 결정일시, 비고.
|
||||
- 신규/수정: 결재ID[DD], 단계순서[NUM], 승인자[DD], 단계상태[DD], 비고. (결재ID/단계순서 RO 규칙 준수)
|
||||
|
||||
### 5.15 결재 이력 조회(Logs)
|
||||
- 라우트: `/approval-histories`
|
||||
- 테이블 전용: 번호, 결재ID, 단계ID, 승인자, 행위, 변경전상태, 변경후상태, 작업일시, 비고.
|
||||
|
||||
### 5.16 결재 템플릿 관리
|
||||
- 라우트: `/approval-templates`
|
||||
- 테이블: 번호, 템플릿코드, 템플릿명, 설명, 작성자, 사용여부, 변경일시.
|
||||
- 신규/수정:
|
||||
- 헤더: 템플릿코드[TXT], 템플릿명[TXT], 설명[TXT], 작성자[RO], 사용여부[SW], 비고[TXT].
|
||||
- 단계 섹션(반복): (+추가) 순서[NUM], 승인자[DD].
|
||||
|
||||
### 5.17 우편번호 검색(모달)
|
||||
- 트리거: 창고/고객사 폼의 우편번호 필드의 “검색”.
|
||||
- 입력: 검색어[TXT]. 결과 테이블: 우편번호 | 시도 | 시군구 | 도로명 | 건물번호. 선택 시 부모 폼에 채움.
|
||||
|
||||
### 5.18 보고서
|
||||
- 라우트: `/reports`
|
||||
- 조건: 기간[DT-기간], 유형[DD], 창고[DD], 상태[DD].
|
||||
- 액션: XLSX/PDF 다운로드(백엔드 제공 엔드포인트 연동, 미제공 시 버튼 비활성 처리).
|
||||
|
||||
## 6. 입력/수정 폼 규칙(공통)
|
||||
- 모달 구조: 헤더(타이틀) / 본문(스크롤) / 푸터(취소, 저장). 모바일에서 풀스크린 모달.
|
||||
- 검증: 필수값 표기(*), 저장 시 필수/형식/업무 규칙 검사. 에러는 필드 하단 및 상단 요약으로 노출.
|
||||
- 자동입력: 작성자/번호/일시 RO. 제품 선택 시 제조사/단위 자동 표시. 합계/라인수는 표시만.
|
||||
- 멀티 선택: 고객사 다건은 토큰/칩 형태로 표시 및 제거 지원.
|
||||
- 라인 편집: 테이블 내 인라인 편집, 행 추가/삭제. 최소 1행.
|
||||
|
||||
## 7. API 연동 청사진(후속 단계)
|
||||
- 목록: `{ items, page, page_size, total }` 포맷 사용. 쿼리: `page, page_size, q, sort, order, updated_since, include, active, deleted`.
|
||||
- 단건: `{ data: { ... } }` 포맷. 생성 시 PK 미포함, 응답에 PK 포함. 수정 시 `id` 포함.
|
||||
- 소프트 삭제/복구: `DELETE /{res}/{id}`, `POST /{res}/{id}/restore`.
|
||||
- 엔드포인트 매핑 예:
|
||||
- 입고/출고/대여: `GET /stock-transactions?include=lines,customers,approval` | `POST /stock-transactions`(헤더+라인+고객 일괄) | `PATCH /stock-transactions/{id}` | `DELETE /stock-transactions/{id}` | `POST /stock-transactions/{id}/restore`
|
||||
- 결재: `GET /approvals?include=steps,histories` | `GET /approvals/{id}?include=steps,histories` | `POST /approvals/{id}/steps` | `PATCH /approvals/{id}/steps` | `POST /approval-steps/{id}/actions` | `GET /approvals/{id}/can-proceed`
|
||||
- 마스터: `/vendors`, `/products`, `/warehouses`, `/customers`, `/employees`, `/menus`, `/groups`, `/group-permissions`
|
||||
- 권한 일괄 갱신: `POST /groups/{id}/permissions` (체크박스 매트릭스 일괄 저장)
|
||||
- 룩업: `/uoms`, `/transaction-types`, `/transaction-statuses`, `/approval-statuses`, `/approval-actions`
|
||||
- 우편번호: `GET /zipcodes?zipcode=06000&road_name=세종대로` (검색 모달에서 복합 쿼리 지원)
|
||||
|
||||
## 8. 와이어프레임(텍스트)
|
||||
- 공통 리스트 스크린
|
||||
- 헤더: [타이틀] [우측: +신규, 기타액션]
|
||||
- 필터바: [검색] [기간] [상태] [창고/유형 등] [Reset]
|
||||
- 본문: ShadTable.list(컬럼들…) [좌측 체크박스(옵션)] [우측 행 액션]
|
||||
- 하단: 페이지네이션(좌: 건수, 우: 페이지 컨트롤)
|
||||
- 공통 폼 모달
|
||||
- 헤더: [타이틀]
|
||||
- 본문: [필드 그리드(2~3열)] [라인 테이블(필요 시)] [고객/단계 섹션]
|
||||
- 푸터: [취소] [저장(primary)]
|
||||
- 예시) 출고 리스트
|
||||
- 필터바: 검색 | 기간 | 창고 | 상태 | 고객사 | Reset
|
||||
- 테이블: 번호 | 처리일자 | 창고 | 트랜잭션번호 | 상태 | 작성자 | 고객수 | 품목수 | 총수량 | 비고 | (행액션)
|
||||
- 예시) 출고 등록 모달
|
||||
- 헤더 필드: 처리일자 | 창고 | 상태 | 작성자(RO) | 비고
|
||||
- 고객사(멀티) 섹션: 고객사(+추가/자동완성) | 비고
|
||||
- 라인 섹션: 제품(자동완성) | 제조사(RO) | 단위(RO) | 수량 | 단가 | 비고 | (+행)
|
||||
|
||||
## 9. 비기능 요구사항
|
||||
- 성능: 가상 스크롤 또는 배치 렌더링 고려, 페이지 당 기본 20~50행.
|
||||
- 국제화: 한국어 우선. 날짜/숫자 포맷 `intl` 사용.
|
||||
- 코드 구조: `lib/features/<domain>/presentation` 중심, 위젯 재사용은 `lib/widgets/`에 공통화. DI는 `lib/injection_container.dart`.
|
||||
- 정적 분석: `flutter analyze` 경고 0 유지. 포맷팅 `dart format .`.
|
||||
|
||||
## 10. 테스트(프론트)
|
||||
- 위젯 테스트:
|
||||
- 테이블 렌더링(컬럼/행 수), 필터 적용, 페이징 이동, 모달 열기/검증 에러 표시.
|
||||
- 위젯 테스트는 네트워크 의존 없는 UI 로직 검증에 한정(실제 API는 통합 테스트에서 검증).
|
||||
- 통합 테스트(선택): 주요 내비게이션(대시보드 → 입/출/대여 → 결재 → 마스터) 흐름 확인.
|
||||
|
||||
---
|
||||
참고 문서: `doc/입출고 대여 폼 정리.md`, `doc/stock_approval_system_spec_v4.md`, `doc/stock_approval_system_api_v4.md`
|
||||
|
||||
## 11. 화면별 필드 매트릭스(유형/검증/자동/소스)
|
||||
|
||||
표기 규칙: 유형(TXT/NUM/DT/CHK/SW/RO/DD/AA=자동완성), 소스(API/룩업/없음), 기본값, 검증(필수/형식/업무), 비고.
|
||||
|
||||
### 11.1 입고(신규/수정 모달)
|
||||
헤더 필드
|
||||
| key | 라벨 | 유형 | 소스 | 기본값 | 검증 | 비고 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| processed_at | 처리일자 | DT | 없음 | 오늘 | 필수 | SuperportShadDatePicker |
|
||||
| warehouse_id | 창고 | DD | `/warehouses` | 없음 | 필수 | 라벨=창고명 |
|
||||
| status_id | 상태 | DD | `/transaction-statuses` | 대기 | 필수 | 진행/승인/반려 등 |
|
||||
| created_by_id | 작성자 | RO | 로그인 | 로그인 사용자 | - | 자동 세팅 |
|
||||
| note | 비고 | TXT | 없음 | - | - | 다중라인 허용 |
|
||||
| transaction_type_id | 입출고유형 | RO/숨김 | `/transaction-types` | 입고 | - | 라우트로 자동 설정 |
|
||||
|
||||
라인 필드(반복)
|
||||
| key | 라벨 | 유형 | 소스 | 기본값 | 검증 | 비고 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| product_id | 제품 | AA | `/products?q=` | - | 필수 | 선택 시 제조사/단위 자동 |
|
||||
| vendor_name | 제조사 | RO | products.vendor | - | - | 제품 선택 시 자동 |
|
||||
| uom_name | 단위 | RO | products.uom | - | - | 제품 선택 시 자동 |
|
||||
| quantity | 수량 | NUM | 없음 | 1 | 필수, >=1 | 우측 정렬 |
|
||||
| unit_price | 단가 | NUM | 없음 | 0 | >=0 | 우측 정렬 |
|
||||
| line_note | 비고 | TXT | 없음 | - | - | |
|
||||
|
||||
자동 표시(요약): 품목수(line_count), 총수량(total_qty), 총금액(total_amount) — 읽기전용.
|
||||
|
||||
### 11.2 출고(신규/수정 모달)
|
||||
헤더 필드: 입고와 동일 + 고객 연결 섹션
|
||||
| key | 라벨 | 유형 | 소스 | 기본값 | 검증 | 비고 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| processed_at | 처리일자 | DT | - | 오늘 | 필수 | |
|
||||
| warehouse_id | 창고 | DD | `/warehouses` | - | 필수 | |
|
||||
| status_id | 상태 | DD | `/transaction-statuses` | 대기 | 필수 | |
|
||||
| created_by_id | 작성자 | RO | 로그인 | 로그인 사용자 | - | |
|
||||
| note | 비고 | TXT | - | - | - | |
|
||||
| transaction_type_id | 입출고유형 | RO/숨김 | `/transaction-types` | 출고 | - | 라우트로 자동 설정 |
|
||||
|
||||
고객 연결(반복 가능)
|
||||
| key | 라벨 | 유형 | 소스 | 기본값 | 검증 | 비고 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| customer_id | 고객사 | AA | `/customers?q=` | - | 최소 1건 | 토큰/칩 UI |
|
||||
| customer_note | 비고 | TXT | - | - | - | |
|
||||
|
||||
라인 필드: 입고와 동일(제품/제조사/단위/수량/단가/비고).
|
||||
|
||||
업무 규칙: 고객사 최소 1건 필수, 없으면 저장 불가(422 메시지 노출).
|
||||
|
||||
### 11.3 대여(신규/수정 모달)
|
||||
헤더 필드
|
||||
| key | 라벨 | 유형 | 소스 | 기본값 | 검증 | 비고 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| processed_at | 처리일자 | DT | - | 오늘 | 필수 | |
|
||||
| warehouse_id | 창고 | DD | `/warehouses` | - | 필수 | |
|
||||
| status_id | 상태 | DD | `/transaction-statuses` | 대기 | 필수 | |
|
||||
| rental_type | 대여구분 | DD | 로컬(대여/반납) | 대여 | 필수 | 종결 후 변경 불가 |
|
||||
| due_date | 반납예정일 | DT | - | +7일 | 선택 | 진행 중 수정 가능 |
|
||||
| created_by_id | 작성자 | RO | 로그인 | 로그인 사용자 | - | |
|
||||
| note | 비고 | TXT | - | - | - | |
|
||||
| transaction_type_id | 입출고유형 | RO/숨김 | `/transaction-types` | 대여/반납 | - | 대여구분에 따른 자동 매핑 |
|
||||
|
||||
고객 연결/라인 필드: 출고와 동일.
|
||||
|
||||
### 11.4 마스터: 벤더/제품/창고/고객/사용자/그룹/메뉴/권한
|
||||
벤더
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| vendor_code | 벤더코드 | TXT | 필수, 고유 | 수정 RO |
|
||||
| vendor_name | 벤더명 | TXT | 필수 | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
제품
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| product_code | 제품코드 | TXT | 필수, 고유 | 수정 RO |
|
||||
| product_name | 제품명 | TXT | 필수 | |
|
||||
| vendor_id | 제조사 | DD | 필수 | `/vendors` |
|
||||
| uom_id | 단위 | DD | 필수 | `/uoms` |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
창고
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| warehouse_code | 창고코드 | TXT | 필수, 고유 | 수정 RO |
|
||||
| warehouse_name | 창고명 | TXT | 필수 | |
|
||||
| zipcode | 우편번호 | TXT | 필수 | 검색 모달로 채움 |
|
||||
| address_detail | 상세주소 | TXT | 필수 | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
고객사
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| customer_code | 고객사코드 | TXT | 필수, 고유 | 수정 RO |
|
||||
| customer_name | 고객사명 | TXT | 필수 | |
|
||||
| types | 유형 | DD(멀티) | 최소 1 | 파트너/일반 |
|
||||
| email | 이메일 | TXT | 이메일형식 | |
|
||||
| phone | 연락처 | TXT | - | |
|
||||
| zipcode | 우편번호 | TXT | - | 검색 모달 |
|
||||
| address_detail | 상세주소 | TXT | - | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
사용자(사원)
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| employee_no | 사번 | TXT | 필수, 고유 | 수정 RO |
|
||||
| employee_name | 성명 | TXT | 필수 | |
|
||||
| email | 이메일 | TXT | 이메일형식 | |
|
||||
| phone | 연락처 | TXT | - | |
|
||||
| group_id | 그룹 | DD | 필수 | `/groups` |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
그룹
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| group_name | 그룹명 | TXT | 필수, 고유 | 수정 RO |
|
||||
| description | 설명 | TXT | - | |
|
||||
| is_default | 기본여부 | SW | - | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
메뉴
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| menu_code | 메뉴코드 | TXT | 필수, 고유 | 수정 RO |
|
||||
| menu_name | 메뉴명 | TXT | 필수 | |
|
||||
| parent_id | 상위메뉴 | DD | - | `/menus` |
|
||||
| route_path | 경로 | TXT | 필수 | |
|
||||
| display_order | 표시순서 | NUM | >=0 | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
그룹 메뉴 권한
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| group_id | 그룹 | DD | 필수 | RO(수정) |
|
||||
| menu_id | 메뉴 | DD | 필수 | RO(수정) |
|
||||
| can_create | 생성 | CHK | - | |
|
||||
| can_read | 조회 | CHK | - | |
|
||||
| can_update | 수정 | CHK | - | |
|
||||
| can_delete | 삭제 | CHK | - | |
|
||||
| is_active | 사용여부 | SW | - | |
|
||||
|
||||
결재
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| transaction_id | 트랜잭션번호 | DD | 필수 | |
|
||||
| approval_no | 결재번호 | RO | - | 자동 부여 |
|
||||
| approval_status_id | 상태 | DD | 필수 | 기본=대기 |
|
||||
| requested_by_id | 상신자 | RO | - | 로그인 사용자 |
|
||||
| requested_at | 요청일시 | RO | - | 자동 |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
결재 단계
|
||||
| key | 라벨 | 유형 | 검증 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| approval_id | 결재ID | DD | 필수 | 수정 RO |
|
||||
| step_order | 순서 | NUM | 필수, >=1 | 수정 RO |
|
||||
| approver_id | 승인자 | DD | 필수 | `/employees` |
|
||||
| step_status_id | 상태 | DD | 필수 | `/approval-statuses` |
|
||||
| assigned_at | 배정일시 | RO | - | 자동 |
|
||||
| decided_at | 결정일시 | RO | - | 자동 |
|
||||
| note | 비고 | TXT | - | |
|
||||
|
||||
결재 이력: 조회 전용(테이블 컬럼 정의만, 입력/수정 없음).
|
||||
|
||||
결재 템플릿: 헤더(코드/명/설명/작성자/사용여부/비고) + 단계(순서/승인자 반복).
|
||||
|
||||
우편번호 검색: 입력(검색어) → 결과 테이블에서 선택 시 부모의 `zipcode`/주소 구성요소 세팅.
|
||||
|
||||
## 12. 테이블 스펙(열/정렬/반응형)
|
||||
|
||||
공통: 정렬은 기본 `updated_at desc` 또는 업무상 자연스러운 키, 헤더 클릭으로 1열 정렬 전환. 폭(px)은 힌트 값이며 브레이크포인트에 따라 가변.
|
||||
|
||||
입고 목록
|
||||
- 컬럼: 번호(80, center, sortable=id) | 처리일자(140, center, sortable) | 창고(160) | 트랜잭션번호(180) | 상태(120, center) | 작성자(140) | 품목수(100, right) | 총수량(120, right) | 비고(1fr)
|
||||
- 모바일(<768): 번호, 처리일자, 상태, 품목수만 노출. 확장 시 나머지 표시.
|
||||
|
||||
출고 목록
|
||||
- 컬럼: 번호 | 처리일자 | 창고 | 트랜잭션번호 | 상태 | 작성자 | 고객수(100, right) | 품목수(100, right) | 총수량(120, right) | 비고(1fr)
|
||||
- 모바일: 번호/처리일자/상태/고객수.
|
||||
|
||||
대여 목록
|
||||
- 컬럼: 번호 | 처리일자 | 창고 | 대여/반납(120, center) | 트랜잭션번호 | 상태 | 반납예정일(160, center) | 고객수 | 품목수 | 비고
|
||||
- 모바일: 번호/대여구분/반납예정일/상태.
|
||||
|
||||
마스터 테이블(벤더/제품/창고/고객/사용자/그룹/메뉴/권한)과 결재/단계/이력/템플릿은 `doc/입출고 대여 폼 정리.md`의 1행 예시를 기준으로 동일한 컬럼 구성, 모바일에서는 코드/이름/상태 위주 노출.
|
||||
|
||||
열 가시성 프리셋(예시)
|
||||
- 데스크톱(≥1280): 모든 열 표시. 비고는 1fr로 확장.
|
||||
- 태블릿(≥1024): 우선순위 낮은 열(비고/표시순서 등) 일부 숨김, 총합/상태/핵심 식별자 유지.
|
||||
- 모바일(<768): 핵심 3~4열만 표시(예: 번호/상태/일자/구분). 나머지는 행 확장 또는 상세에서 제공.
|
||||
|
||||
## 13. 폼 레이아웃 & 와이어프레임(텍스트)
|
||||
|
||||
공통 모달(데스크톱)
|
||||
```
|
||||
[모달 헤더: 타이틀]
|
||||
────────────────────────────────────────────
|
||||
[필드 그리드 2~3열]
|
||||
[라벨] [입력] [라벨] [입력] [라벨] [입력]
|
||||
...
|
||||
|
||||
[섹션 타이틀] (예: 라인 품목)
|
||||
[라인 테이블: 제품 | 제조사 | 단위 | 수량 | 단가 | 비고 | (+행)]
|
||||
|
||||
[하단 합계/요약 배지]
|
||||
|
||||
[푸터: 취소][저장]
|
||||
```
|
||||
|
||||
모바일(풀스크린)
|
||||
```
|
||||
[<] 제목 [저장]
|
||||
────────────────────────────────────────
|
||||
[필드 1열 스택]
|
||||
[섹션]
|
||||
[라인: 카드형 반복]
|
||||
[합계]
|
||||
```
|
||||
|
||||
입고 등록 예시(데스크톱, 3열)
|
||||
```
|
||||
처리일자 [DT] 창고 [DD] 상태 [DD]
|
||||
작성자 [RO] 비고 [TXT···(colspan=2)]
|
||||
|
||||
라인 섹션:
|
||||
┌제품 [AA]┬제조사[RO]┬단위[RO]┬수량[NUM]┬단가[NUM]┬비고[TXT]┬(+)
|
||||
└────────┴─────────┴──────┴───────┴───────┴───────┴────
|
||||
|
||||
[품목수: n][총수량: x][총금액: ₩y]
|
||||
```
|
||||
|
||||
출고 등록: 상단 동일 + [고객사(멀티) 토큰 리스트 + (+추가) 자동완성]
|
||||
|
||||
## 14. 상호작용/플로우
|
||||
- 리스트 → +신규 클릭 → 모달 → 저장 → 성공 토스트 → 리스트 리프레시/최상단 스크롤.
|
||||
- 행 클릭 → 상세 모달(또는 우측 패널) → 수정 가능 상태면 “수정” 노출.
|
||||
- 라인 편집: 수량/단가 변경 시 합계 즉시 반영. Enter/Tab으로 다음 셀 이동. (+)는 마지막 행 뒤에 포커스.
|
||||
- 출고/대여 고객 토큰: 입력 자동완성 → Enter로 선택 → 토큰 생성. 토큰 X 클릭으로 제거.
|
||||
- 삭제: 소프트 삭제 확인 모달 → 성공 시 상태 배지/행 스타일로 삭제 표시(필터로 숨김 기본).
|
||||
|
||||
## 15. 검증/오류 메시지(예시)
|
||||
- 필수 누락: “처리일자를 입력해 주세요.”
|
||||
- 수량 음수: “수량은 1 이상이어야 합니다.”
|
||||
- 고객 미선택(출고/대여): “고객사는 최소 1건 선택해야 합니다.”
|
||||
- 결재 상태 전이 금지: “현재 단계 상태에서는 다음 단계로 이동할 수 없습니다.”
|
||||
- 네트워크 오류 시: 오류 토스트/다시 시도 버튼/오류 상세 제공(더미 데이터 사용 금지).
|
||||
|
||||
## 16. 키보드/접근성
|
||||
- 단축키: Cmd/Ctrl+S 저장, Esc 닫기, Enter 다음 필드/행 추가(라인 끝).
|
||||
- 포커스 순서: 위→아래, 좌→우. 포커스 트랩으로 모달 내에서 순환.
|
||||
- ARIA 라벨 등 시맨틱: 가능한 범위에서 위젯 라벨/설명 제공.
|
||||
|
||||
## 17. 환경/피처 토글
|
||||
- 환경 변수로 API 베이스 URL/타임아웃/로그 레벨 제어.
|
||||
- 기능 플래그로 베타 화면/행동 토글(데이터는 항상 실 API 사용).
|
||||
- 페이지네이션: 기본 20행, 최대 100행.
|
||||
|
||||
## 18. 상태 전이(결재)
|
||||
- approval_statuses: 대기(기본, blocking), 진행중(blocking), 보류(blocking), 승인(non-blocking), 반려(terminal, blocking).
|
||||
- 단계 행위: approve → 다음 단계 배정, 모든 단계 승인 시 전체 승인. reject → 전체 반려(terminal) 처리.
|
||||
- 전이 금지: blocking 상태에서는 `can_proceed=false` 처리(버튼 비활성/툴팁).
|
||||
|
||||
## 19. API 매핑(연동 시)
|
||||
- 트랜잭션 목록: `GET /stock-transactions?include=lines,customers`
|
||||
- 생성: `POST /stock-transactions` 바디 내 헤더/라인/고객 배열 동시 전달
|
||||
- 결재 상세: `GET /approvals/{id}?include=steps,histories`
|
||||
- 단계 행위: `POST /approval-steps/{id}/actions` with `approval_action_id`
|
||||
- 결재 템플릿: `GET/POST/PATCH /approval-templates`, `POST/PATCH /approval-templates/{id}/steps`
|
||||
- 룩업: `/uoms`, `/transaction-types`, `/transaction-statuses`, `/approval-statuses`, `/approval-actions`
|
||||
|
||||
## 20. 컴포넌트 매핑(shadcn_ui)
|
||||
- 입력: `ShadInput`, 숫자 입력은 우측 정렬 스타일.
|
||||
- 선택: `ShadSelect`(단일), 자동완성은 `ShadSelect + 검색` 패턴 또는 커스텀 콤보(리스트 팝오버, 키보드 선택) — 레퍼런스: 슈퍼포트 구현체.
|
||||
- 날짜: `SuperportShadDatePicker`, 기간 필터는 `SuperportShadDateRangePicker`.
|
||||
- 스위치/체크: `ShadSwitch`, `ShadCheckbox`.
|
||||
- 모달: `SuperportShadDialog`(헤더/본문/푸터), 모바일 풀스크린 전환.
|
||||
- 테이블: `ShadTable.list` + `two_dimensional_scrollables`로 스크롤 최적화.
|
||||
|
||||
---
|
||||
부록: 필요 시 각 스크린의 모바일 카드형 레이아웃 명세(요약 배지, 핵심 필드 순서)를 추가 정의한다.
|
||||
955
doc/stock_approval_system_api_v4.md
Normal file
955
doc/stock_approval_system_api_v4.md
Normal file
@@ -0,0 +1,955 @@
|
||||
# 간단 입·출고 + 결재 시스템 API 규격 (v4)
|
||||
|
||||
**기준 버전:** 2025-09-18 16:22:30Z (UTC)
|
||||
|
||||
본 문서는 `stock_approval_system_spec_full_v4.md`의 데이터 모델과 비즈니스 규칙을 기반으로 한 REST API 구성을 정의한다. 기본 CRUD를 제공하며, 목록·상세 조회 시 FK로 연결된 주요 엔터티 정보를 함께 반환한다. 모든 엔드포인트는 소프트 삭제 컬럼(`is_deleted`)을 노출하지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 공통 규칙
|
||||
- **URI 규칙:** 복수형 리소스 명 사용. 기본 경로 예) `/api/v1/vendors`.
|
||||
- **표준 응답 구조:** 목록은 `{ items: [], page, page_size, total }`, 단건은 `{ data: { ... } }`.
|
||||
- **시간대:** 모든 날짜·시간은 ISO8601 UTC 문자열.
|
||||
- **소프트 삭제:** `DELETE /{res}/{id}` 호출 시 서버는 `is_deleted=true`, `is_active=false`로 처리하고 응답 바디는 `{ data: { id, deleted_at } }` 형식을 사용.
|
||||
- **복구:** `POST /{res}/{id}/restore`.
|
||||
- **공통 컬럼:** `note`, `is_active`, `created_at`, `updated_at`는 요청·응답에 필요 시 노출하되 `is_deleted`는 절대 노출하지 않는다.
|
||||
- **기본 필터:** 목록 조회 시 기본 쿼리 `active=true`, `deleted=false`. `deleted` 파라미터가 `true`일 때에만 삭제된 항목을 반환.
|
||||
- **증분 조회:** `updated_since=ISO8601`.
|
||||
- **정렬:** `sort`(기본 `updated_at`), `order=asc|desc`(기본 desc).
|
||||
- **검색:** `q` 파라미터로 코드/명칭 부분 일치. 필요한 경우 컬럼별 필터 지원.
|
||||
- **Include 확장:** `include` 쿼리로 추가 데이터(`lines`, `customers`, `approval`, `steps`, `histories`, `permissions`, `employees` 등) 선택 가능. 포함 대상은 FK 요약 정보를 이미 반환하므로 `include`는 상세 컬렉션을 불러올 때 사용.
|
||||
- **배열 입력:** 트랜잭션 라인, 트랜잭션 고객, 결재 단계, 그룹 메뉴 권한 등 다건 작업은 항상 배열(`[]`) 기반으로 요청한다.
|
||||
- **Primary Key 규칙:** Create 요청 바디에는 PK를 포함하지 않는다. Create 응답 및 나머지 모든 요청·응답에는 PK가 포함돼야 한다(경로에 이미 포함된 경우라도 바디 내 `id`를 명시).
|
||||
- **에러 규격:**
|
||||
- `400 BAD_REQUEST` — 검증 오류, 필수값 누락.
|
||||
- `404 NOT_FOUND` — 리소스 없음 또는 삭제됨.
|
||||
- `409 CONFLICT` — 유니크 제약, 결재 단계 상태 충돌.
|
||||
- `422 UNPROCESSABLE_ENTITY` — 비즈니스 규칙 위반(출고 고객 누락, blocking 상태 전이 등).
|
||||
- 에러 응답 예: `{ "error": { "code": 422, "message": "출고 트랜잭션에는 고객이 최소 1건 필요합니다.", "details": [...] } }`.
|
||||
|
||||
---
|
||||
|
||||
## 2. 타입(룩업) API
|
||||
대상: `/uoms`, `/transaction-types`, `/transaction-statuses`, `/approval-statuses`, `/approval-actions`
|
||||
|
||||
### 2.1 목록 조회
|
||||
`GET /{type}?page=1&page_size=50&active=true`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "EA",
|
||||
"is_default": true,
|
||||
"is_active": true,
|
||||
"note": null,
|
||||
"created_at": "2025-01-01T00:00:00Z",
|
||||
"updated_at": "2025-02-01T03:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 단건 조회
|
||||
`GET /{type}/{id}`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 3,
|
||||
"name": "반려",
|
||||
"is_default": false,
|
||||
"is_blocking_next": true,
|
||||
"is_terminal": true,
|
||||
"is_active": true,
|
||||
"note": "최종 거절",
|
||||
"created_at": "2025-01-10T09:00:00Z",
|
||||
"updated_at": "2025-02-01T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 생성
|
||||
`POST /{type}`
|
||||
```json
|
||||
{
|
||||
"name": "진행중",
|
||||
"is_default": false,
|
||||
"is_blocking_next": true,
|
||||
"is_terminal": false,
|
||||
"is_active": true,
|
||||
"note": null
|
||||
}
|
||||
```
|
||||
응답:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 4,
|
||||
"name": "진행중",
|
||||
"is_default": false,
|
||||
"is_blocking_next": true,
|
||||
"is_terminal": false,
|
||||
"is_active": true,
|
||||
"note": null,
|
||||
"created_at": "2025-03-01T00:00:00Z",
|
||||
"updated_at": "2025-03-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 수정
|
||||
`PATCH /{type}/{id}`
|
||||
```json
|
||||
{
|
||||
"id": 4,
|
||||
"is_blocking_next": false,
|
||||
"note": "임시 승인 허용"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 삭제 & 복구
|
||||
- `DELETE /{type}/{id}` → `{ "data": { "id": 4, "deleted_at": "2025-03-05T09:00:00Z" } }`
|
||||
- `POST /{type}/{id}/restore` → `{ "data": { "id": 4, "restored_at": "2025-03-06T01:00:00Z" } }`
|
||||
|
||||
> `approval-statuses`는 추가 속성(`is_blocking_next`, `is_terminal`)을 사용하며, 다른 타입 테이블은 `name`, `is_default`, `is_active`, `note` 중심으로 작동한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 마스터 데이터 API
|
||||
리소스: `/vendors`, `/warehouses`, `/customers`, `/employees`, `/products`, `/menus`, `/groups`, `/zipcodes`
|
||||
|
||||
### 3.1 목록 조회
|
||||
`GET /vendors?page=1&q=한빛`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 10,
|
||||
"vendor_code": "V001",
|
||||
"vendor_name": "한빛상사",
|
||||
"note": "서울/경기 공급처",
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-01T12:00:00Z",
|
||||
"updated_at": "2025-01-03T09:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
`GET /products?page=1&include=vendor`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 101,
|
||||
"product_code": "P100",
|
||||
"product_name": "샘플",
|
||||
"vendor": {
|
||||
"id": 10,
|
||||
"vendor_code": "V001",
|
||||
"vendor_name": "한빛상사"
|
||||
},
|
||||
"uom": {
|
||||
"id": 1,
|
||||
"uom_name": "EA",
|
||||
"is_default": true
|
||||
},
|
||||
"note": "출고 우선 재고",
|
||||
"is_active": true,
|
||||
"created_at": "2025-02-01T12:00:00Z",
|
||||
"updated_at": "2025-02-03T09:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
`GET /warehouses?page=1`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 20,
|
||||
"warehouse_code": "WH-001",
|
||||
"warehouse_name": "1센터",
|
||||
"zipcode": {
|
||||
"zipcode": "06000",
|
||||
"sido": "서울특별시",
|
||||
"sigungu": "강남구",
|
||||
"road_name": "테헤란로"
|
||||
},
|
||||
"address_detail": "강남파이낸스센터 10층",
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-05T08:00:00Z",
|
||||
"updated_at": "2025-01-10T09:30:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
`GET /customers?page=1`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 301,
|
||||
"customer_code": "C001",
|
||||
"customer_name": "ABC물류",
|
||||
"is_partner": true,
|
||||
"is_general": false,
|
||||
"email": "contact@abc.com",
|
||||
"mobile_no": "010-1234-5678",
|
||||
"zipcode": {
|
||||
"zipcode": "06000",
|
||||
"sido": "서울특별시",
|
||||
"sigungu": "강남구",
|
||||
"road_name": "테헤란로"
|
||||
},
|
||||
"address_detail": "10층",
|
||||
"note": "VIP 고객",
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-15T11:00:00Z",
|
||||
"updated_at": "2025-01-20T08:10:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
`GET /employees?page=1`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인",
|
||||
"email": "approver@example.com",
|
||||
"mobile_no": "010-2222-1111",
|
||||
"group": {
|
||||
"id": 2,
|
||||
"group_name": "창고 관리자"
|
||||
},
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-02T09:00:00Z",
|
||||
"updated_at": "2025-01-10T11:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
`GET /groups?include=permissions,employees`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 2,
|
||||
"group_name": "창고 관리자",
|
||||
"group_description": "창고 및 재고 관리",
|
||||
"is_default": false,
|
||||
"is_active": true,
|
||||
"permissions": [
|
||||
{
|
||||
"id": 8,
|
||||
"menu": {
|
||||
"id": 12,
|
||||
"menu_code": "STOCK_MGMT",
|
||||
"menu_name": "입출고 관리"
|
||||
},
|
||||
"can_create": true,
|
||||
"can_read": true,
|
||||
"can_update": true,
|
||||
"can_delete": false
|
||||
}
|
||||
],
|
||||
"employees": [
|
||||
{
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
}
|
||||
],
|
||||
"created_at": "2025-01-01T00:00:00Z",
|
||||
"updated_at": "2025-01-15T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 단건 조회
|
||||
`GET /products/101`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 101,
|
||||
"product_code": "P100",
|
||||
"product_name": "샘플",
|
||||
"vendor": {
|
||||
"id": 10,
|
||||
"vendor_code": "V001",
|
||||
"vendor_name": "한빛상사",
|
||||
"note": "서울/경기 공급처"
|
||||
},
|
||||
"uom": {
|
||||
"id": 1,
|
||||
"uom_name": "EA",
|
||||
"is_default": true
|
||||
},
|
||||
"note": "출고 우선 재고",
|
||||
"is_active": true,
|
||||
"created_at": "2025-02-01T12:00:00Z",
|
||||
"updated_at": "2025-02-03T09:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 생성
|
||||
`POST /vendors`
|
||||
```json
|
||||
{
|
||||
"vendor_code": "V002",
|
||||
"vendor_name": "미래상사",
|
||||
"note": "부산 공급처",
|
||||
"is_active": true
|
||||
}
|
||||
```
|
||||
응답:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 11,
|
||||
"vendor_code": "V002",
|
||||
"vendor_name": "미래상사",
|
||||
"note": "부산 공급처",
|
||||
"is_active": true,
|
||||
"created_at": "2025-03-01T00:00:00Z",
|
||||
"updated_at": "2025-03-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 수정
|
||||
`PATCH /products/101`
|
||||
```json
|
||||
{
|
||||
"id": 101,
|
||||
"product_name": "샘플 A",
|
||||
"note": "재고 우선순위 변경"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 삭제 & 복구
|
||||
- `DELETE /products/101`
|
||||
- `POST /products/101/restore`
|
||||
|
||||
### 3.6 그룹 메뉴 권한 일괄 갱신
|
||||
`POST /groups/2/permissions`
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"entries": [
|
||||
{
|
||||
"menu_id": 12,
|
||||
"can_create": true,
|
||||
"can_read": true,
|
||||
"can_update": true,
|
||||
"can_delete": false
|
||||
},
|
||||
{
|
||||
"menu_id": 13,
|
||||
"can_create": false,
|
||||
"can_read": true,
|
||||
"can_update": false,
|
||||
"can_delete": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
응답은 갱신된 권한 목록을 반환.
|
||||
|
||||
> `zipcodes`는 대량 데이터 특성상 `GET /zipcodes?zipcode=06000&road_name=세종대로` 형태로 조회하며, 응답 항목에는 `zipcode`, `sido`, `sigungu`, `road_name`, `building_main_no` 등 주소 구성 요소가 포함된다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 트랜잭션 API
|
||||
리소스: `/stock-transactions`, 보조 리소스: `/transaction-lines`, `/transaction-customers`
|
||||
|
||||
### 4.1 생성 (헤더 + 라인 + 고객 다건)
|
||||
`POST /stock-transactions`
|
||||
```json
|
||||
{
|
||||
"transaction_no": "TXN-2025-0001",
|
||||
"transaction_type_id": 1,
|
||||
"transaction_status_id": 1,
|
||||
"warehouse_id": 1,
|
||||
"transaction_date": "2025-09-18",
|
||||
"created_by_id": 7,
|
||||
"note": "창고 입고",
|
||||
"lines": [
|
||||
{
|
||||
"line_no": 1,
|
||||
"product_id": 101,
|
||||
"quantity": 50,
|
||||
"unit_price": 1200
|
||||
},
|
||||
{
|
||||
"line_no": 2,
|
||||
"product_id": 102,
|
||||
"quantity": 20,
|
||||
"unit_price": 0
|
||||
}
|
||||
],
|
||||
"customers": []
|
||||
}
|
||||
```
|
||||
응답은 생성된 트랜잭션 전체 정보를 반환하며, 라인·고객 식별자가 포함된다.
|
||||
|
||||
### 4.2 목록 조회
|
||||
`GET /stock-transactions?include=lines,customers,approval`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 9001,
|
||||
"transaction_no": "TXN-2025-0001",
|
||||
"transaction_type": {
|
||||
"id": 1,
|
||||
"type_name": "입고"
|
||||
},
|
||||
"transaction_status": {
|
||||
"id": 1,
|
||||
"status_name": "초안"
|
||||
},
|
||||
"warehouse": {
|
||||
"id": 1,
|
||||
"warehouse_code": "WH-001",
|
||||
"warehouse_name": "1센터"
|
||||
},
|
||||
"transaction_date": "2025-09-18",
|
||||
"created_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"note": "창고 입고",
|
||||
"is_active": true,
|
||||
"created_at": "2025-09-18T05:00:00Z",
|
||||
"updated_at": "2025-09-18T05:00:00Z",
|
||||
"lines": [
|
||||
{
|
||||
"id": 12001,
|
||||
"line_no": 1,
|
||||
"product": {
|
||||
"id": 101,
|
||||
"product_code": "P100",
|
||||
"product_name": "샘플",
|
||||
"vendor": {
|
||||
"id": 10,
|
||||
"vendor_name": "한빛상사"
|
||||
},
|
||||
"uom": {
|
||||
"id": 1,
|
||||
"uom_name": "EA"
|
||||
}
|
||||
},
|
||||
"quantity": 50,
|
||||
"unit_price": 1200,
|
||||
"note": null
|
||||
}
|
||||
],
|
||||
"customers": [],
|
||||
"approval": null
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 단건 조회
|
||||
`GET /stock-transactions/9001?include=lines,customers,approval,approval.steps`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 9001,
|
||||
"transaction_no": "TXN-2025-0001",
|
||||
"transaction_type": {
|
||||
"id": 1,
|
||||
"type_name": "입고"
|
||||
},
|
||||
"transaction_status": {
|
||||
"id": 1,
|
||||
"status_name": "초안"
|
||||
},
|
||||
"warehouse": {
|
||||
"id": 1,
|
||||
"warehouse_code": "WH-001",
|
||||
"warehouse_name": "1센터",
|
||||
"zipcode": {
|
||||
"zipcode": "06000",
|
||||
"sido": "서울특별시"
|
||||
}
|
||||
},
|
||||
"transaction_date": "2025-09-18",
|
||||
"created_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"note": "창고 입고",
|
||||
"is_active": true,
|
||||
"created_at": "2025-09-18T05:00:00Z",
|
||||
"updated_at": "2025-09-18T05:00:00Z",
|
||||
"lines": [
|
||||
{
|
||||
"id": 12001,
|
||||
"line_no": 1,
|
||||
"product": {
|
||||
"id": 101,
|
||||
"product_code": "P100",
|
||||
"product_name": "샘플",
|
||||
"vendor": {
|
||||
"id": 10,
|
||||
"vendor_name": "한빛상사"
|
||||
},
|
||||
"uom": {
|
||||
"id": 1,
|
||||
"uom_name": "EA"
|
||||
}
|
||||
},
|
||||
"quantity": 50,
|
||||
"unit_price": 1200,
|
||||
"note": null
|
||||
}
|
||||
],
|
||||
"customers": [],
|
||||
"approval": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 헤더 수정
|
||||
`PATCH /stock-transactions/9001`
|
||||
```json
|
||||
{
|
||||
"id": 9001,
|
||||
"transaction_status_id": 2,
|
||||
"note": "상신 준비"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 라인 다건 추가/수정/삭제
|
||||
- **추가:** `POST /stock-transactions/9001/lines`
|
||||
```json
|
||||
{
|
||||
"id": 9001,
|
||||
"lines": [
|
||||
{
|
||||
"line_no": 2,
|
||||
"product_id": 102,
|
||||
"quantity": 20,
|
||||
"unit_price": 900
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **일괄 수정:** `PATCH /stock-transactions/9001/lines`
|
||||
```json
|
||||
{
|
||||
"id": 9001,
|
||||
"lines": [
|
||||
{
|
||||
"id": 12001,
|
||||
"line_no": 1,
|
||||
"quantity": 60,
|
||||
"note": "추가 입고"
|
||||
},
|
||||
{
|
||||
"id": 12002,
|
||||
"line_no": 2,
|
||||
"unit_price": 950
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **삭제:** `DELETE /transaction-lines/12002`
|
||||
- **복구:** `POST /transaction-lines/12002/restore`
|
||||
|
||||
### 4.6 고객 연결 다건 관리
|
||||
- **추가:** `POST /stock-transactions/9100/customers`
|
||||
```json
|
||||
{
|
||||
"id": 9100,
|
||||
"customers": [
|
||||
{
|
||||
"customer_id": 301,
|
||||
"note": "1차 납품"
|
||||
},
|
||||
{
|
||||
"customer_id": 302,
|
||||
"note": "2차 납품"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **수정:** `PATCH /stock-transactions/9100/customers`
|
||||
```json
|
||||
{
|
||||
"id": 9100,
|
||||
"customers": [
|
||||
{
|
||||
"id": 33001,
|
||||
"note": "수량 조정"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **삭제:** `DELETE /transaction-customers/33001`
|
||||
|
||||
### 4.7 상태 전이 권장 API
|
||||
- `POST /stock-transactions/9001/submit`
|
||||
- `POST /stock-transactions/9001/complete`
|
||||
|
||||
응답은 `{ "data": { "id": 9001, "transaction_status": { ... }, "updated_at": "..." } }` 형태.
|
||||
|
||||
---
|
||||
|
||||
## 5. 결재 API
|
||||
리소스: `/approvals`, 보조 리소스: `/approval-steps`, `/approval-histories`
|
||||
|
||||
### 5.1 결재 생성
|
||||
`POST /approvals`
|
||||
```json
|
||||
{
|
||||
"transaction_id": 9001,
|
||||
"approval_no": "APP-2025-0001",
|
||||
"approval_status_id": 1,
|
||||
"requested_by_id": 7,
|
||||
"note": "입고 결재"
|
||||
}
|
||||
```
|
||||
응답에는 `id`와 현재 단계 정보가 포함된다.
|
||||
|
||||
### 5.2 목록 조회
|
||||
`GET /approvals?include=steps,histories`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 5001,
|
||||
"approval_no": "APP-2025-0001",
|
||||
"transaction": {
|
||||
"id": 9001,
|
||||
"transaction_no": "TXN-2025-0001"
|
||||
},
|
||||
"approval_status": {
|
||||
"id": 1,
|
||||
"status_name": "대기",
|
||||
"is_blocking_next": true
|
||||
},
|
||||
"current_step": null,
|
||||
"requested_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"requested_at": "2025-09-18T06:00:00Z",
|
||||
"decided_at": null,
|
||||
"note": "입고 결재",
|
||||
"is_active": true,
|
||||
"created_at": "2025-09-18T06:00:00Z",
|
||||
"updated_at": "2025-09-18T06:00:00Z",
|
||||
"steps": [],
|
||||
"histories": []
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 단건 조회
|
||||
`GET /approvals/5001?include=steps,histories`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 5001,
|
||||
"approval_no": "APP-2025-0001",
|
||||
"transaction": {
|
||||
"id": 9001,
|
||||
"transaction_no": "TXN-2025-0001"
|
||||
},
|
||||
"approval_status": {
|
||||
"id": 1,
|
||||
"status_name": "대기",
|
||||
"is_blocking_next": true,
|
||||
"is_terminal": false
|
||||
},
|
||||
"current_step": null,
|
||||
"requested_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"requested_at": "2025-09-18T06:00:00Z",
|
||||
"decided_at": null,
|
||||
"note": "입고 결재",
|
||||
"steps": [
|
||||
{
|
||||
"id": 7001,
|
||||
"step_order": 1,
|
||||
"approver": {
|
||||
"id": 21,
|
||||
"employee_no": "E2025002",
|
||||
"employee_name": "박검토"
|
||||
},
|
||||
"step_status": {
|
||||
"id": 1,
|
||||
"status_name": "대기",
|
||||
"is_blocking_next": true
|
||||
},
|
||||
"assigned_at": "2025-09-18T06:05:00Z",
|
||||
"decided_at": null,
|
||||
"note": null
|
||||
}
|
||||
],
|
||||
"histories": [],
|
||||
"created_at": "2025-09-18T06:00:00Z",
|
||||
"updated_at": "2025-09-18T06:05:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 단계 구성 (배치 생성)
|
||||
`POST /approvals/5001/steps`
|
||||
```json
|
||||
{
|
||||
"id": 5001,
|
||||
"steps": [
|
||||
{
|
||||
"step_order": 1,
|
||||
"approver_id": 21,
|
||||
"note": null
|
||||
},
|
||||
{
|
||||
"step_order": 2,
|
||||
"approver_id": 34,
|
||||
"note": "재무 확인"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.5 단계 일괄 수정/재배치
|
||||
`PATCH /approvals/5001/steps`
|
||||
```json
|
||||
{
|
||||
"id": 5001,
|
||||
"steps": [
|
||||
{
|
||||
"id": 7001,
|
||||
"step_order": 1,
|
||||
"note": "서류 확인 중"
|
||||
},
|
||||
{
|
||||
"id": 7002,
|
||||
"step_order": 2,
|
||||
"approver_id": 35
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.6 단계 행위
|
||||
`POST /approval-steps/7001/actions`
|
||||
```json
|
||||
{
|
||||
"id": 7001,
|
||||
"approval_action_id": 1,
|
||||
"note": "승인합니다."
|
||||
}
|
||||
```
|
||||
응답에는 전후 상태(`from_status`, `to_status`), 차기 단계 정보가 포함되며, `approval_histories`에 기록된다.
|
||||
|
||||
### 5.7 결재 상태 확인
|
||||
`GET /approvals/5001/can-proceed`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 5001,
|
||||
"can_proceed": true,
|
||||
"reason": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.8 결재 수정·삭제·복구
|
||||
- `PATCH /approvals/5001`
|
||||
```json
|
||||
{
|
||||
"id": 5001,
|
||||
"approval_status_id": 2,
|
||||
"note": "보류 처리"
|
||||
}
|
||||
```
|
||||
- `DELETE /approvals/5001`
|
||||
- `POST /approvals/5001/restore`
|
||||
|
||||
---
|
||||
|
||||
## 6. 결재 템플릿 API
|
||||
리소스: `/approval-templates`
|
||||
|
||||
### 6.1 목록 조회
|
||||
`GET /approval-templates?page=1`
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 3001,
|
||||
"template_code": "AP_INBOUND",
|
||||
"template_name": "입고 결재 기본",
|
||||
"description": "입고 결재 2단계",
|
||||
"created_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-20T00:00:00Z",
|
||||
"updated_at": "2025-01-25T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 단건 조회
|
||||
`GET /approval-templates/3001?include=steps`
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 3001,
|
||||
"template_code": "AP_INBOUND",
|
||||
"template_name": "입고 결재 기본",
|
||||
"description": "입고 결재 2단계",
|
||||
"created_by": {
|
||||
"id": 7,
|
||||
"employee_no": "E2025001",
|
||||
"employee_name": "김승인"
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"id": 9101,
|
||||
"step_order": 1,
|
||||
"approver": {
|
||||
"id": 21,
|
||||
"employee_no": "E2025002",
|
||||
"employee_name": "박검토"
|
||||
},
|
||||
"note": null
|
||||
}
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-01-20T00:00:00Z",
|
||||
"updated_at": "2025-01-25T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 생성·수정
|
||||
- `POST /approval-templates`
|
||||
```json
|
||||
{
|
||||
"template_code": "AP_OUTBOUND",
|
||||
"template_name": "출고 결재 기본",
|
||||
"description": "출고 결재 3단계",
|
||||
"created_by_id": 7,
|
||||
"note": "표준 출고"
|
||||
}
|
||||
```
|
||||
|
||||
- `POST /approval-templates/3002/steps`
|
||||
```json
|
||||
{
|
||||
"id": 3002,
|
||||
"steps": [
|
||||
{
|
||||
"step_order": 1,
|
||||
"approver_id": 34
|
||||
},
|
||||
{
|
||||
"step_order": 2,
|
||||
"approver_id": 55
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `PATCH /approval-templates/3002`
|
||||
```json
|
||||
{
|
||||
"id": 3002,
|
||||
"template_name": "출고 결재 확장",
|
||||
"note": "정기 출고용"
|
||||
}
|
||||
```
|
||||
|
||||
- `PATCH /approval-templates/3002/steps`
|
||||
```json
|
||||
{
|
||||
"id": 3002,
|
||||
"steps": [
|
||||
{
|
||||
"id": 9105,
|
||||
"step_order": 1,
|
||||
"approver_id": 36
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- 삭제/복구: `DELETE /approval-templates/{id}`, `POST /approval-templates/{id}/restore`
|
||||
|
||||
---
|
||||
|
||||
## 7. 보고서 API (선택)
|
||||
- `GET /reports/transactions/export?from=2025-09-01&to=2025-09-30&type_id=2&warehouse_id=1&format=xlsx`
|
||||
- `GET /reports/approvals/export?status_id=1&format=pdf`
|
||||
|
||||
응답은 파일 다운로드 링크 또는 스트림. 요청 파라미터에는 대상 리소스의 PK를 포함한다.
|
||||
|
||||
---
|
||||
|
||||
## 8. 구현 참고
|
||||
- FK 요약 정보는 기본 응답에 포함하며, 상세 정보가 필요하면 `include` 파라미터를 활용해 확장한다.
|
||||
- 배열 기반 다건 작업은 전체를 트랜잭션 처리해야 한다. 실패 시 롤백하고 부분 처리 결과를 반환하지 않는다.
|
||||
- `is_active` 변경은 권한·결재 등의 즉시성 요구를 고려하여 관련 캐시를 무효화한다.
|
||||
- 결재 단계 상태 전이는 `approval_statuses.is_blocking_next` 규칙을 준수해야 하며, 반려(`is_terminal=true`) 상태 시 결재를 종료한다.
|
||||
677
doc/stock_approval_system_spec_v4.md
Normal file
677
doc/stock_approval_system_spec_v4.md
Normal file
@@ -0,0 +1,677 @@
|
||||
|
||||
# 간단 입·출고 + 결재 시스템 설계서 (최종 v4)
|
||||
|
||||
**버전:** 2025-09-18 16:22:30Z (UTC)
|
||||
**요약:** 벤더 ↔ 창고 ↔ 고객사 간 물품 이동(입고/출고)을 관리하는 최소구성 시스템.
|
||||
- 트랜잭션당 1개의 결재(1:1), **승인자 순서 기반의 순차 결재** 지원.
|
||||
- **다음 승인자로 넘어가면 안 되는 상태**를 `approval_statuses.is_blocking_next`로 제어.
|
||||
- 모든 테이블(타입/코드 테이블 포함)에 **공통 컬럼** 적용: `is_active`, `is_deleted`, `created_at`, `updated_at`.
|
||||
- **벤더는 트랜잭션 헤더에 연결하지 않음**(벤더는 제품을 통해서만 추적).
|
||||
- **customer_roles 제거**: 트랜잭션-고객은 역할 없이 다수 연결만 허용.
|
||||
- 타입값은 **별도 테이블**로 분리하며 `*_code`/정렬순서 미사용, ID 기반 참조.
|
||||
- 메뉴 접근은 `groups`와 `group_menu_permissions`를 통해 제어되며, 모든 직원은 정확히 하나의 그룹에 속함.
|
||||
|
||||
---
|
||||
|
||||
## 0) 핵심 비즈니스 규칙
|
||||
- 제품 1개는 반드시 1개의 벤더에 소속 (`products.vendor_id` 필수).
|
||||
- **트랜잭션 1건당 결재 1건**(1:1, 소프트삭제 제외).
|
||||
- 결재는 **승인자 순서(`approval_steps.step_order`)대로**만 진행.
|
||||
- 각 단계 상태가 **blocking**이면 다음 단계로 이동 불가.
|
||||
- 트랜잭션에는 **여러 고객사**를 연결할 수 있음(역할 없음).
|
||||
- 모든 직원은 **그룹**에 속하며(`employees.group_id`), 그룹-메뉴 권한(`group_menu_permissions`)으로 메뉴별 CRUD 가능 여부가 결정됨.
|
||||
- 고객사는 **유형**을 `is_partner`/`is_general` 플래그로 구분하며 둘 중 하나 이상이 true여야 함(기본: 일반 true, 파트너 false).
|
||||
- 반복되는 결재 라인은 **결재 템플릿**으로 저장 후 호출하여 재사용 가능.
|
||||
- 모든 삭제는 **소프트 삭제**(`is_deleted=true`)이며, 삭제 시 `is_active=false`로 내림.
|
||||
|
||||
---
|
||||
|
||||
## 1) 개념 ERD
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
vendors ||--o{ products : supplies
|
||||
uoms ||--o{ products : measured_in
|
||||
|
||||
warehouses ||--o{ stock_transactions : occurs_in
|
||||
transaction_types ||--o{ stock_transactions : typed_as
|
||||
transaction_statuses ||--o{ stock_transactions : has_status
|
||||
|
||||
stock_transactions ||--o{ transaction_lines : has
|
||||
products ||--o{ transaction_lines : item
|
||||
|
||||
stock_transactions ||--o{ transaction_customers : serves
|
||||
customers ||--o{ transaction_customers : party
|
||||
|
||||
stock_transactions ||--|| approvals : has_one
|
||||
approval_statuses ||--o{ approvals : overall_status
|
||||
approvals ||--o{ approval_steps : has_sequence
|
||||
approval_statuses ||--o{ approval_steps : step_status
|
||||
approval_steps ||--o{ approval_histories : logs
|
||||
approval_actions ||--o{ approval_histories : acted_as
|
||||
|
||||
approval_templates ||--o{ approval_template_steps : has_sequence
|
||||
|
||||
employees ||--o{ approvals : requested_by
|
||||
employees ||--o{ approval_steps : assigned_to
|
||||
employees ||--o{ approval_histories : actor
|
||||
employees ||--o{ stock_transactions : created_by
|
||||
employees ||--o{ approval_templates : authored
|
||||
employees ||--o{ approval_template_steps : template_approver
|
||||
groups ||--o{ employees : members
|
||||
groups ||--o{ group_menu_permissions : controls
|
||||
menus ||--o{ group_menu_permissions : target
|
||||
zipcodes ||--o{ warehouses : located
|
||||
zipcodes ||--o{ customers : addressed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2) 공통 컬럼 (모든 테이블 공통 적용)
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| note | 비고 | text | - | - | N | N | N | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | N | N | - |
|
||||
| is_deleted | 삭제여부(소프트) | boolean | - | false | Y | N | N | - |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | N | N | - |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | N | N | - |
|
||||
|
||||
> 모든 테이블(타입/코드 테이블 포함)에 위 4개 컬럼을 **명시적으로 포함**.
|
||||
> `note`는 테이블별 메모/추가 설명을 저장하는 자유 텍스트 필드.
|
||||
> `updated_at`은 UPDATE 시 자동 갱신(트리거/생성 컬럼 권장). 삭제 시 `is_deleted=true`, `is_active=false` 처리.
|
||||
|
||||
---
|
||||
|
||||
## 3) 테이블 정의
|
||||
|
||||
### 3.1 `vendors` (벤더)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| vendors | 벤더 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 벤더ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| vendor_code | 벤더코드 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| vendor_name | 벤더명 | varchar | 100 | - | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.2 `warehouses` (창고)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| warehouses | 창고 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 창고ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| warehouse_code | 창고코드 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| warehouse_name | 창고명 | varchar | 100 | - | Y | | | |
|
||||
| zipcode | 우편번호 | varchar | 5 | - | N | | | zipcodes.zipcode |
|
||||
| address_detail | 상세주소 | varchar | 200 | - | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.3 `customers` (고객사)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| customers | 고객사 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 고객사ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| customer_code | 고객사코드 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| customer_name | 고객사명 | varchar | 100 | - | Y | | | |
|
||||
| is_partner | 파트너여부 | boolean | - | false | Y | | | - |
|
||||
| is_general | 일반여부 | boolean | - | true | Y | | | - |
|
||||
| email | 이메일 | varchar | 100 | - | N | | | - |
|
||||
| mobile_no | 모바일번호 | varchar | 20 | - | N | | | - |
|
||||
| zipcode | 우편번호 | varchar | 5 | - | N | | | zipcodes.zipcode |
|
||||
| address_detail | 상세주소 | varchar | 200 | - | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.4 `employees` (사원)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| employees | 사원 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 사원ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| employee_no | 사번 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| employee_name | 성명 | varchar | 100 | - | Y | | | |
|
||||
| email | 이메일 | varchar | 100 | - | N | Y | | |
|
||||
| mobile_no | 모바일번호 | varchar | 20 | - | N | | | |
|
||||
| group_id | 그룹ID | bigint | - | - | Y | | | groups.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.5 `zipcodes` (우편번호)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| zipcodes | 우편번호 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| zipcode | 우편번호 | varchar | 5 | - | Y | Y | Y | - |
|
||||
| sido | 시도 | varchar | 50 | - | Y | | | - |
|
||||
| sido_eng | 시도영문 | varchar | 100 | - | N | | | - |
|
||||
| sigungu | 시군구 | varchar | 100 | - | Y | | | - |
|
||||
| sigungu_eng | 시군구영문 | varchar | 100 | - | N | | | - |
|
||||
| eupmyeon | 읍면 | varchar | 100 | - | N | | | - |
|
||||
| eupmyeon_eng | 읍면영문 | varchar | 100 | - | N | | | - |
|
||||
| road_code | 도로명코드 | varchar | 12 | - | Y | | | - |
|
||||
| road_name | 도로명 | varchar | 200 | - | Y | | | - |
|
||||
| road_name_eng | 도로명영문 | varchar | 200 | - | N | | | - |
|
||||
| underground_flag | 지하여부 | varchar | 1 | 'N' | Y | | | - |
|
||||
| building_main_no | 건물번호본번 | integer | - | 0 | Y | | | - |
|
||||
| building_sub_no | 건물번호부번 | integer | - | 0 | N | | | - |
|
||||
| building_mgmt_no | 건물관리번호 | varchar | 25 | - | Y | | | - |
|
||||
| bulk_receiver | 다량배달처명 | varchar | 200 | - | N | | | - |
|
||||
| sigungu_building_name | 시군구용건물명 | varchar | 200 | - | N | | | - |
|
||||
| legal_dong_code | 법정동코드 | varchar | 10 | - | Y | | | - |
|
||||
| legal_dong_name | 법정동명 | varchar | 100 | - | Y | | | - |
|
||||
| ri_name | 리명 | varchar | 100 | - | N | | | - |
|
||||
| admin_dong_name | 행정동명 | varchar | 100 | - | N | | | - |
|
||||
| mountain_flag | 산여부 | varchar | 1 | 'N' | Y | | | - |
|
||||
| land_main_no | 지번본번 | integer | - | 0 | Y | | | - |
|
||||
| town_serial_no | 읍면동일련번호 | integer | - | 0 | N | | | - |
|
||||
| land_sub_no | 지번부번 | integer | - | 0 | N | | | - |
|
||||
| old_zipcode | 구우편번호 | varchar | 6 | - | N | | | - |
|
||||
| zipcode_serial_no | 우편번호일련번호 | integer | - | 0 | Y | | | - |
|
||||
| search_text | 검색텍스트 | text | - | - | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 도로명 주소 데이터와 매핑되는 5자리 우편번호 기준. `zipcode`가 PK이며 외부 데이터 동기화를 위한 `zipcode_serial_no`를 포함.
|
||||
|
||||
---
|
||||
|
||||
### 3.6 `menus` (메뉴)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| menus | 메뉴 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 메뉴ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| menu_code | 메뉴코드 | varchar | 50 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| menu_name | 메뉴명 | varchar | 100 | - | Y | | | |
|
||||
| parent_menu_id | 상위메뉴ID | bigint | - | - | N | | | menus.id |
|
||||
| route_path | 경로 | varchar | 255 | - | N | | | - |
|
||||
| display_order | 표시순서 | integer | - | 0 | Y | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 메뉴는 계층 구조를 지원하며 `parent_menu_id`가 NULL이면 1차 메뉴로 간주.
|
||||
|
||||
---
|
||||
|
||||
### 3.8 `groups` (그룹)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| groups | 그룹 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 그룹ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| group_name | 그룹명 | varchar | 100 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| group_description | 그룹설명 | varchar | 255 | - | N | | | - |
|
||||
| is_default | 기본그룹여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> `group_menu_permissions`를 통해 각 그룹별 메뉴 CRUD 권한을 정의하며, 사원은 `employees.group_id`로 그룹에 연결됨.
|
||||
|
||||
---
|
||||
|
||||
### 3.9 `group_menu_permissions` (그룹_메뉴_권한)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| group_menu_permissions | 그룹_메뉴_권한 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 메뉴그룹권한ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| group_id | 그룹ID | bigint | - | - | Y | (복합유니크: group_id, menu_id, is_deleted) | N | groups.id |
|
||||
| menu_id | 메뉴ID | bigint | - | - | Y | (복합유니크: group_id, menu_id, is_deleted) | N | menus.id |
|
||||
| can_create | 생성권한 | boolean | - | false | Y | | | - |
|
||||
| can_read | 조회권한 | boolean | - | true | Y | | | - |
|
||||
| can_update | 수정권한 | boolean | - | false | Y | | | - |
|
||||
| can_delete | 삭제권한 | boolean | - | false | Y | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 각 메뉴에 대한 CRUD 권한을 그룹 단위로 정의하며, 권한 미설정 시 기본적으로 조회만 허용.
|
||||
|
||||
---
|
||||
|
||||
### 3.10 `uoms` (단위) — 타입 테이블
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| uoms | 단위 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 단위ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| uom_name | 단위명 | varchar | 100 | - | Y | (선택) 부분유니크 | N | - |
|
||||
| is_default | 기본여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 예시 값: `EA`(기본 단위), `BOX`, `KG`, `LITER` 등.
|
||||
|
||||
---
|
||||
|
||||
### 3.11 `products` (제품)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| products | 제품 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 제품ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| product_code | 제품코드 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| product_name | 제품명 | varchar | 100 | - | Y | | | |
|
||||
| vendor_id | 벤더ID | bigint | - | - | Y | | | vendors.id |
|
||||
| uom_id | 단위ID | bigint | - | - | Y | | | uoms.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.12 `transaction_types` (입출고_유형) — 타입 테이블
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| transaction_types | 입출고_유형 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 유형ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| type_name | 유형명 | varchar | 100 | - | Y | (선택) 부분유니크 | N | - |
|
||||
| is_default | 기본여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 예시 값: `입고`(is_default=true), `출고`.
|
||||
|
||||
---
|
||||
|
||||
### 3.13 `transaction_statuses` (트랜잭션_상태) — 타입 테이블
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| transaction_statuses | 트랜잭션_상태 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 상태ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| status_name | 상태명 | varchar | 100 | - | Y | (선택) 부분유니크 | N | - |
|
||||
| is_default | 기본여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 예시 값: `정상`(is_default), `반품`, `폐기`.
|
||||
|
||||
---
|
||||
|
||||
### 3.14 `stock_transactions` (입출고_트랜잭션)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| stock_transactions | 입출고_트랜잭션 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 트랜잭션ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| transaction_no | 트랜잭션번호 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| transaction_type_id | 입출고유형ID | bigint | - | - | Y | | | transaction_types.id |
|
||||
| transaction_status_id | 트랜잭션상태ID | bigint | - | - | Y | | | transaction_statuses.id |
|
||||
| warehouse_id | 창고ID | bigint | - | - | Y | | | warehouses.id |
|
||||
| transaction_date | 처리일자 | date | - | current_date | Y | | | - |
|
||||
| created_by_id | 작성자ID | bigint | - | - | N | | | employees.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 주의: **벤더ID 없음**. 벤더 정보는 라인의 `product_id`가 가리키는 `products.vendor_id`로 파생.
|
||||
|
||||
---
|
||||
|
||||
### 3.15 `transaction_lines` (트랜잭션_라인)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| transaction_lines | 트랜잭션_라인 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 라인ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| transaction_id | 트랜잭션ID | bigint | - | - | Y | | | stock_transactions.id |
|
||||
| line_no | 라인번호 | integer | - | 1 | Y | (복합유니크: transaction_id, line_no, is_deleted) | N | - |
|
||||
| product_id | 제품ID | bigint | - | - | Y | | | products.id |
|
||||
| quantity | 수량 | numeric | 20,6 | 0 | Y | | | - |
|
||||
| unit_price | 단가 | numeric | 20,6 | 0 | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.16 `transaction_customers` (트랜잭션_고객사)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| transaction_customers | 트랜잭션_고객사 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 키 | bigint | - | identity | Y | Y | Y | - |
|
||||
| transaction_id | 트랜잭션ID | bigint | - | - | Y | | | stock_transactions.id |
|
||||
| customer_id | 고객사ID | bigint | - | - | Y | (복합유니크: transaction_id, customer_id, is_deleted) | N | customers.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.17 `approval_statuses` (결재_상태) — 타입 테이블
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_statuses | 결재_상태 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 상태ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| status_name | 상태명 | varchar | 100 | - | Y | (선택) 부분유니크 | N | - |
|
||||
| is_default | 기본여부 | boolean | - | false | Y | | | |
|
||||
| is_blocking_next | 차기이동차단 | boolean | - | true | Y | | | |
|
||||
| is_terminal | 종결여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 예시 값:
|
||||
> - `대기`(`is_default=true`, `is_blocking_next=true`, `is_terminal=false`)
|
||||
> - `진행중`(`is_blocking_next=true`, `is_terminal=false`)
|
||||
> - `보류`(`is_blocking_next=true`, `is_terminal=false`)
|
||||
> - `승인`(`is_blocking_next=false`, `is_terminal=false`)
|
||||
> - `반려`(`is_blocking_next=true`, `is_terminal=true`).
|
||||
|
||||
---
|
||||
|
||||
### 3.18 `approval_actions` (결재_행위) — 타입 테이블
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_actions | 결재_행위 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 행위ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| action_name | 행위명 | varchar | 100 | - | Y | (선택) 부분유니크 | N | - |
|
||||
| is_default | 기본여부 | boolean | - | false | Y | | | |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 예시 값: `approve`(승인), `reject`(반려), `comment`(코멘트).
|
||||
|
||||
---
|
||||
|
||||
### 3.19 `approvals` (결재)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approvals | 결재 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 결재ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| transaction_id | 트랜잭션ID | bigint | - | - | Y | (부분유니크: is_deleted=false) | N | stock_transactions.id |
|
||||
| approval_no | 결재번호 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| approval_status_id | 전체결재상태ID | bigint | - | - | Y | | | approval_statuses.id |
|
||||
| current_step_id | 현재단계ID | bigint | - | - | N | | | approval_steps.id |
|
||||
| requested_by_id | 상신자ID | bigint | - | - | Y | | | employees.id |
|
||||
| requested_at | 상신일시 | timestamp | - | now() | Y | | | - |
|
||||
| decided_at | 최종결정일시 | timestamp | - | - | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.20 `approval_steps` (결재_단계)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_steps | 결재_단계 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 단계ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| approval_id | 결재ID | bigint | - | - | Y | | | approvals.id |
|
||||
| step_order | 단계순서 | integer | - | 1 | Y | (복합유니크: approval_id, step_order, is_deleted) | N | - |
|
||||
| approver_id | 승인자ID | bigint | - | - | Y | | | employees.id |
|
||||
| step_status_id | 단계상태ID | bigint | - | - | Y | | | approval_statuses.id |
|
||||
| assigned_at | 배정일시 | timestamp | - | now() | Y | | | - |
|
||||
| decided_at | 결정일시 | timestamp | - | - | N | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.21 `approval_histories` (결재_승인이력)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_histories | 결재_승인이력 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 이력ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| approval_id | 결재ID | bigint | - | - | Y | | | approvals.id |
|
||||
| approval_step_id | 결재단계ID | bigint | - | - | Y | | | approval_steps.id |
|
||||
| approver_id | 승인자ID | bigint | - | - | Y | | | employees.id |
|
||||
| approval_action_id | 결재행위ID | bigint | - | - | Y | | | approval_actions.id |
|
||||
| from_status_id | 변경전상태ID | bigint | - | - | N | | | approval_statuses.id |
|
||||
| to_status_id | 변경후상태ID | bigint | - | - | Y | | | approval_statuses.id |
|
||||
| action_at | 작업일시 | timestamp | - | now() | Y | | | - |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.22 `approval_templates` (결재_템플릿)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_templates | 결재_템플릿 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 템플릿ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| template_code | 템플릿코드 | varchar | 30 | - | Y | (부분유니크: is_deleted=false) | N | - |
|
||||
| template_name | 템플릿명 | varchar | 100 | - | Y | | | |
|
||||
| description | 설명 | varchar | 255 | - | N | | | - |
|
||||
| created_by_id | 작성자ID | bigint | - | - | Y | | | employees.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
---
|
||||
|
||||
### 3.23 `approval_template_steps` (결재_템플릿_단계)
|
||||
| 영문테이블명 | 한글테이블명 |
|
||||
|---|---|
|
||||
| approval_template_steps | 결재_템플릿_단계 |
|
||||
|
||||
| 영문필드명 | 한글필드명 | 타입 | 길이 | 기본값 | NOT NULL | UNIQUE | PK | FK |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| id | 템플릿단계ID | bigint | - | identity | Y | Y | Y | - |
|
||||
| template_id | 템플릿ID | bigint | - | - | Y | (복합유니크: template_id, step_order, is_deleted) | N | approval_templates.id |
|
||||
| step_order | 단계순서 | integer | - | 1 | Y | (복합유니크: template_id, step_order, is_deleted) | N | - |
|
||||
| approver_id | 승인자ID | bigint | - | - | Y | | | employees.id |
|
||||
| note | 비고 | text | - | - | N | | | - |
|
||||
| is_active | 사용여부 | boolean | - | true | Y | | | |
|
||||
| is_deleted | 삭제여부 | boolean | - | false | Y | | | |
|
||||
| created_at | 생성일시 | timestamp | - | now() | Y | | | |
|
||||
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
|
||||
|
||||
> 템플릿 단계는 실제 결재 단계 생성 시 그대로 복제되며, `step_order` 순서대로 승인자가 배치됨.
|
||||
|
||||
---
|
||||
|
||||
## 4) FK 관계 (source → target)
|
||||
- `menus.parent_menu_id` → `menus.id`
|
||||
- `employees.group_id` → `groups.id`
|
||||
- `group_menu_permissions.group_id` → `groups.id`
|
||||
- `group_menu_permissions.menu_id` → `menus.id`
|
||||
- `warehouses.zipcode` → `zipcodes.zipcode`
|
||||
- `customers.zipcode` → `zipcodes.zipcode`
|
||||
- `products.vendor_id` → `vendors.id`
|
||||
- `products.uom_id` → `uoms.id`
|
||||
- `stock_transactions.warehouse_id` → `warehouses.id`
|
||||
- `stock_transactions.created_by_id` → `employees.id`
|
||||
- `stock_transactions.transaction_type_id` → `transaction_types.id`
|
||||
- `stock_transactions.transaction_status_id` → `transaction_statuses.id`
|
||||
- `transaction_lines.transaction_id` → `stock_transactions.id`
|
||||
- `transaction_lines.product_id` → `products.id`
|
||||
- `transaction_customers.transaction_id` → `stock_transactions.id`
|
||||
- `transaction_customers.customer_id` → `customers.id`
|
||||
- `approvals.transaction_id` → `stock_transactions.id`
|
||||
- `approvals.approval_status_id` → `approval_statuses.id`
|
||||
- `approvals.current_step_id` → `approval_steps.id`
|
||||
- `approvals.requested_by_id` → `employees.id`
|
||||
- `approval_steps.approval_id` → `approvals.id`
|
||||
- `approval_steps.approver_id` → `employees.id`
|
||||
- `approval_steps.step_status_id` → `approval_statuses.id`
|
||||
- `approval_histories.approval_id` → `approvals.id`
|
||||
- `approval_histories.approval_step_id` → `approval_steps.id`
|
||||
- `approval_histories.approver_id` → `employees.id`
|
||||
- `approval_histories.approval_action_id` → `approval_actions.id`
|
||||
- `approval_histories.from_status_id` → `approval_statuses.id`
|
||||
- `approval_histories.to_status_id` → `approval_statuses.id`
|
||||
- `approval_templates.created_by_id` → `employees.id`
|
||||
- `approval_template_steps.template_id` → `approval_templates.id`
|
||||
- `approval_template_steps.approver_id` → `employees.id`
|
||||
|
||||
---
|
||||
|
||||
## 5) 비즈니스/검증 규칙
|
||||
- 제품 등록 시 `vendor_id` **필수**.
|
||||
- 입고(`transaction_type_id`=입고) 트랜잭션의 공급자 정보는 **라인 제품의 벤더**로만 해석. (헤더에 벤더 금지)
|
||||
- 출고 트랜잭션은 `transaction_customers` **최소 1건** 필요.
|
||||
- 결재는 **트랜잭션당 1건**(미삭제 기준)만 허용.
|
||||
- 단계 전이는 **현재 단계**에서만 수행 가능. blocking 상태에서는 차기 이동 불가.
|
||||
- 수량/단가 음수 금지(CHECK).
|
||||
- 그룹이 비활성(`is_active=false`) 또는 삭제되면 해당 그룹 권한/구성원은 즉시 무효 처리.
|
||||
- 사원의 소속 그룹(`employees.group_id`)에서 해당 메뉴에 대한 `can_create|can_update|can_delete` 중 하나라도 true이면 그 동작을 수행할 수 있음.
|
||||
|
||||
---
|
||||
|
||||
## 6) 인덱스/유니크 권장
|
||||
- 부분 유니크(또는 복합 유니크)로 소프트 삭제와 공존:
|
||||
- `vendors(vendor_code)`, `warehouses(warehouse_code)`, `customers(customer_code)`, `employees(employee_no)`, `menus(menu_code)`, `groups(group_name)`, `zipcodes(zipcode)`, `products(product_code)`, `stock_transactions(transaction_no)`, `approvals(approval_no)`
|
||||
- `group_menu_permissions(group_id, menu_id, is_deleted)`
|
||||
- `approvals(transaction_id)` — 미삭제 조건에서 1:1 보장
|
||||
- `transaction_lines(transaction_id, line_no, is_deleted)`
|
||||
- `transaction_customers(transaction_id, customer_id, is_deleted)`
|
||||
- FK 및 조회 인덱스: 모든 `*_id`, `updated_at`, `is_deleted`, `is_active`.
|
||||
|
||||
---
|
||||
|
||||
## 7) 에러 규격(예시)
|
||||
- `400 BAD_REQUEST` — 필수 필드 누락, 형식 오류
|
||||
- `409 CONFLICT` — 유니크 충돌(코드/번호/조합), **현재 단계 아님**
|
||||
- `422 UNPROCESSABLE_ENTITY` — 비즈니스 규칙 위반(출고인데 고객 없음, blocking 상태에서 이동 등)
|
||||
- `404 NOT_FOUND` — 리소스 없음 또는 삭제됨(`deleted=false` 기본 필터로 미노출)
|
||||
|
||||
---
|
||||
|
||||
## 8) 마이그레이션 가이드(요약)
|
||||
1) `stock_transactions`에서 `vendor_id` 드롭.
|
||||
2) `customer_roles` 테이블 및 관련 컬럼 드롭.
|
||||
3) 모든 타입/코드 테이블에 공통 컬럼 4종 추가(미존재 시).
|
||||
4) 부분 유니크 인덱스(`WHERE is_deleted=false`) 또는 `(컬럼, is_deleted)` 복합 유니크 구성.
|
||||
5) 기존 결재 이력은 `approval_step_id` 매핑(없으면 1단계로 귀속).
|
||||
6) `approval_statuses`에 `is_blocking_next`, `is_terminal` 값 시드.
|
||||
7) `menus`, `groups`, `group_menu_permissions` 신규 생성 및 기존 관리자 권한/사원-그룹 매핑을 `employees.group_id`로 이관.
|
||||
8) `zipcodes` 테이블 생성 및 도로명 주소 기준 데이터 적재.
|
||||
9) 모든 테이블에 `note`(text) 컬럼 추가 및 필요한 경우 기본값 NULL 유지.
|
||||
|
||||
---
|
||||
|
||||
## 9) 초기 시드 값(예시)
|
||||
- `transaction_types`: [입고, 출고] (`is_default`: 입고)
|
||||
- `transaction_statuses`: [초안, 상신, 승인, 반려, 완료] (`is_default`: 초안)
|
||||
- `approval_statuses`: [대기(pending, default, blocking), 진행중(in_progress, blocking), 보류(on_hold, blocking), 승인(approved, !blocking), 반려(rejected, blocking+terminal)]
|
||||
- `approval_actions`: [승인(approve), 반려(reject), 코멘트(comment)]
|
||||
- `uoms`: [EA(기본), BOX, KG ...]
|
||||
- `menus`: [대시보드, 입출고 관리, 결재 관리, 레포트 등] — 상위/하위 메뉴 구조 포함
|
||||
- `groups`: [전사 관리자(기본), 창고 관리자, 결재 담당자]
|
||||
- `group_menu_permissions`: 기본 그룹별 메뉴 권한(CRUD 플래그); 전사 관리자는 모든 메뉴 `can_*`=true, 역할별로 세분화 설정
|
||||
- `zipcodes`: 행정안전부 도로명 주소 DB(5자리) 최신본을 기준으로 일괄 적재
|
||||
|
||||
---
|
||||
|
||||
## 10) 구현 팁
|
||||
- `updated_at` 자동 갱신 트리거, 소프트 삭제 처리 트리거 권장.
|
||||
- 낙관적 잠금(선택): `version`(int) + ETag.
|
||||
- 병렬 결재 확장(선택): `approval_steps`에 `group_no`, `approval_mode(all|any)` 도입.
|
||||
225
doc/입출고 대여 폼 정리.md
Normal file
225
doc/입출고 대여 폼 정리.md
Normal file
@@ -0,0 +1,225 @@
|
||||
flutter 사용
|
||||
[flutter shadCnUI](https://github.com/nank1ro/flutter-shadcn-ui) 라이브러리 사용.
|
||||
반응형웹서비스.
|
||||
API연결없이 화면 구성만. 단 네비게이션은 작동되어야 함.
|
||||
프론트엔드 화면만 구현.
|
||||
git 저장소 없음
|
||||
|
||||
# 입·출고 + 결재 시스템 전체 UI 분석 & 와이어프레임 (v2)
|
||||
|
||||
## 0. 로그인/로그아웃
|
||||
### 입력 폼
|
||||
- 아이디(사번 또는 이메일) [TXT]
|
||||
- 비밀번호 [PWD]
|
||||
|
||||
### 수정 폼
|
||||
- 없음 (세션 기반)
|
||||
|
||||
### 테이블 리스트
|
||||
- 없음
|
||||
|
||||
---
|
||||
|
||||
## 1. 대시보드
|
||||
### 주요 위젯
|
||||
- 오늘 입고/출고 건수, 대기 결재 수
|
||||
- 최근 트랜잭션 리스트 (번호, 일자, 유형, 상태, 작성자)
|
||||
- 내 결재 요청/대기 건
|
||||
|
||||
---
|
||||
|
||||
## 2. 입고
|
||||
### 입력 폼
|
||||
- 처리일자[DT], 창고[DD], 상태[DD], 작성자[RO], 비고[TXT]
|
||||
- 라인: 제품[DD], 제조사[RO], 단위[RO], 수량[NUM], 단가[NUM], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 작성자[RO], 트랜잭션번호[RO], 상태[일부 제한]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 처리일자 | 창고 | 트랜잭션번호 | 상태 | 작성자 | 품목수 | 총수량 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 3. 출고
|
||||
### 입력 폼
|
||||
- 처리일자[DT], 창고[DD], 상태[DD], 작성자[RO], 비고[TXT]
|
||||
- 라인: 제품[DD], 제조사[RO], 단위[RO], 수량[NUM], 단가[NUM], 비고[TXT]
|
||||
- 고객사 연결: 고객사[DD-멀티], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 작성자[RO], 트랜잭션번호[RO], 고객사[수정 가능], 상태[제한]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 처리일자 | 창고 | 트랜잭션번호 | 상태 | 작성자 | 고객수 | 품목수 | 총수량 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 4. 대여
|
||||
### 입력 폼
|
||||
- 처리일자[DT], 창고[DD], 상태[DD], 작성자[RO], 대여구분[DD], 반납예정일[DT], 비고[TXT]
|
||||
- 라인: 제품[DD], 제조사[RO], 단위[RO], 수량[NUM], 단가[NUM], 비고[TXT]
|
||||
- 고객사 연결: 고객사[DD-멀티], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 작성자[RO], 트랜잭션번호[RO], 대여구분[제한], 반납예정일[수정가능]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 처리일자 | 창고 | 대여/반납 | 트랜잭션번호 | 상태 | 반납예정일 | 고객수 | 품목수 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 5. 제조사 관리 (벤더)
|
||||
### 입력 폼
|
||||
- 벤더코드[TXT], 벤더명[TXT], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 벤더코드[RO], 생성일시[RO], 수정일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 벤더코드 | 벤더명 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 6. 장비 모델 관리 (제품)
|
||||
### 입력 폼
|
||||
- 제품코드[TXT], 제품명[TXT], 제조사[DD], 단위[DD], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 제품코드[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 제품코드 | 제품명 | 제조사 | 단위 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 7. 입고지 관리 (창고)
|
||||
### 입력 폼
|
||||
- 창고코드[TXT], 창고명[TXT], 우편번호[검색], 상세주소[TXT], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 창고코드[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 창고코드 | 창고명 | 우편번호 | 상세주소 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 8. 회사 관리 (고객사)
|
||||
### 입력 폼
|
||||
- 고객사코드[TXT], 고객사명[TXT], 유형(파트너/일반)[DD], 이메일[TXT], 연락처[TXT], 우편번호[검색], 상세주소[TXT], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 고객사코드[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 고객사코드 | 고객사명 | 유형 | 이메일 | 연락처 | 우편번호 | 상세주소 | 사용여부 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 9. 사용자 관리 (사원)
|
||||
### 입력 폼
|
||||
- 사번[TXT], 성명[TXT], 이메일[TXT], 연락처[TXT], 그룹[DD], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 사번[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 사번 | 성명 | 이메일 | 연락처 | 그룹 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 10. 그룹 관리
|
||||
### 입력 폼
|
||||
- 그룹명[TXT], 그룹설명[TXT], 기본여부[SW], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 그룹명[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 그룹명 | 설명 | 기본여부 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 11. 메뉴 관리
|
||||
### 입력 폼
|
||||
- 메뉴코드[TXT], 메뉴명[TXT], 상위메뉴[DD], 경로[TXT], 표시순서[NUM], 사용여부[SW], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 메뉴코드[RO], 생성일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 메뉴코드 | 메뉴명 | 상위메뉴 | 경로 | 사용여부 | 비고 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 12. 그룹 메뉴 권한 관리
|
||||
### 입력 폼
|
||||
- 그룹[DD], 메뉴[DD], 생성권한[CHK], 조회권한[CHK], 수정권한[CHK], 삭제권한[CHK], 사용여부[SW]
|
||||
|
||||
### 수정 폼
|
||||
- 그룹[RO], 메뉴[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 그룹명 | 메뉴명 | 생성 | 조회 | 수정 | 삭제 | 사용여부 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 13. 결재 관리
|
||||
### 입력 폼
|
||||
- 트랜잭션번호[DD], 결재번호[자동생성], 결재상태[DD], 상신자[자동], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 결재번호[RO], 상신자[RO], 요청일시[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 결재번호 | 트랜잭션번호 | 상태 | 상신자 | 요청일시 | 최종결정일시 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 14. 결재 단계 관리
|
||||
### 입력 폼
|
||||
- 결재ID[DD], 단계순서[NUM], 승인자[DD], 단계상태[DD], 비고[TXT]
|
||||
|
||||
### 수정 폼
|
||||
- 결재ID[RO], 단계순서[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 결재ID | 단계순서 | 승인자 | 상태 | 배정일시 | 결정일시 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 15. 결재 이력 조회
|
||||
- 테이블 전용 (수정 없음)
|
||||
- 컬럼: 번호 | 결재ID | 단계ID | 승인자 | 행위 | 변경전상태 | 변경후상태 | 작업일시 | 비고
|
||||
|
||||
---
|
||||
|
||||
## 16. 결재 템플릿 관리
|
||||
### 입력 폼
|
||||
- 템플릿코드[TXT], 템플릿명[TXT], 설명[TXT], 작성자[RO], 사용여부[SW], 비고[TXT]
|
||||
- 단계: (+추가) 순서[NUM], 승인자[DD]
|
||||
|
||||
### 수정 폼
|
||||
- 템플릿코드[RO], 작성자[RO]
|
||||
|
||||
### 테이블 리스트 (1행)
|
||||
번호 | 템플릿코드 | 템플릿명 | 설명 | 작성자 | 사용여부 | 변경일시
|
||||
|
||||
---
|
||||
|
||||
## 17. 우편번호 관리 (검색용)
|
||||
- 모달 전용: 검색어[TXT], 결과 리스트 (우편번호 | 시도 | 시군구 | 도로명 | 건물번호)
|
||||
|
||||
---
|
||||
|
||||
## 18. 보고서
|
||||
### 화면
|
||||
- 조건 입력: 기간[DT-기간], 유형[DD], 창고[DD], 상태[DD]
|
||||
- 출력: [BTN: XLSX 다운로드], [BTN: PDF 다운로드]
|
||||
|
||||
---
|
||||
|
||||
# ✅ 최종 요약
|
||||
- 로그인 → 대시보드 → 입고/출고/대여 → 마스터 관리(벤더, 제품, 창고, 고객사, 사용자, 그룹, 메뉴, 권한) → 결재 관리(결재, 단계, 이력, 템플릿) → 보고서 → 로그아웃까지 전부 포함.
|
||||
- 각 페이지마다 입력폼, 수정폼, 테이블리스트 1행 예시를 일관되게 정리함.
|
||||
Reference in New Issue
Block a user