Files
superport_v2/doc/stock_approval_system_spec_v4.md

34 KiB

간단 입·출고 + 결재 시스템 설계서 (최종 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 기반 참조.
  • 메뉴 접근은 groupsgroup_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

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_idmenus.id
  • employees.group_idgroups.id
  • group_menu_permissions.group_idgroups.id
  • group_menu_permissions.menu_idmenus.id
  • warehouses.zipcodezipcodes.zipcode
  • customers.zipcodezipcodes.zipcode
  • products.vendor_idvendors.id
  • products.uom_iduoms.id
  • stock_transactions.warehouse_idwarehouses.id
  • stock_transactions.created_by_idemployees.id
  • stock_transactions.transaction_type_idtransaction_types.id
  • stock_transactions.transaction_status_idtransaction_statuses.id
  • transaction_lines.transaction_idstock_transactions.id
  • transaction_lines.product_idproducts.id
  • transaction_customers.transaction_idstock_transactions.id
  • transaction_customers.customer_idcustomers.id
  • approvals.transaction_idstock_transactions.id
  • approvals.approval_status_idapproval_statuses.id
  • approvals.current_step_idapproval_steps.id
  • approvals.requested_by_idemployees.id
  • approval_steps.approval_idapprovals.id
  • approval_steps.approver_idemployees.id
  • approval_steps.step_status_idapproval_statuses.id
  • approval_histories.approval_idapprovals.id
  • approval_histories.approval_step_idapproval_steps.id
  • approval_histories.approver_idemployees.id
  • approval_histories.approval_action_idapproval_actions.id
  • approval_histories.from_status_idapproval_statuses.id
  • approval_histories.to_status_idapproval_statuses.id
  • approval_templates.created_by_idemployees.id
  • approval_template_steps.template_idapproval_templates.id
  • approval_template_steps.approver_idemployees.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_statusesis_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_stepsgroup_no, approval_mode(all|any) 도입.