You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
현재 운영에서는 최신 Version 하나만 사용하더라도, 과거 Draft를 해석할 수 있도록 기존 Contract 파일을 보존한다.
Template Activation, Rollback, Digest 조합과 별도 Lifecycle 테이블은 만들지 않는다.
9. Server와 AI의 책임
Server
Server는 다음을 담당한다.
사용자·회사 권한 검증
Task와 근로자 조회
관계형 데이터 Projection
Contract 로딩
JSONB Draft 저장
허용 Field와 기본 타입 검증
읽기 전용 Field 보호
낙관적 잠금
AI Document API 호출
AI Document Service
AI Document Service는 다음을 담당한다.
Canonical Values 수신
Template Key 확인
HWP/HWPX 내부 Mapping
체크박스·표 처리
문서 생성
Renderer 오류 반환
생성 파일 반환
AI는 Server의 PostgreSQL에 직접 접근하지 않는다.
Frontend
Frontend는 다음을 담당한다.
지원 양식 선택
양식 전용 Form 표시
읽기 전용·수정 가능 Field 구분
Draft 조회·저장
Version 충돌 안내
문서 생성 요청
생성 파일 다운로드
범용 Dynamic Form은 구현하지 않는다.
10. 데이터 모델
신규 테이블은 document_generation_draft 하나만 추가한다.
document_generation_draft
draft_id UUID PK
company_id UUID NOT NULL
task_id UUID NOT NULL
template_key VARCHAR NOT NULL
schema_version VARCHAR NOT NULL
values_json JSONB NOT NULL
created_by UUID NOT NULL
updated_by UUID NOT NULL
version BIGINT NOT NULL
created_at TIMESTAMPTZ NOT NULL
updated_at TIMESTAMPTZ NOT NULL
template_key
사용한 문서 양식을 식별한다.
정적 Contract JSON의 template_key와 일치해야 한다.
schema_version
Draft 생성 당시 사용한 Contract Version이다.
values_json
문서에 입력할 전체 Canonical Values Snapshot이다.
version
JPA @Version 낙관적 잠금에 사용한다.
하나의 Task에서 같은 양식을 여러 번 작성할 수 있으므로 다음 Unique Constraint는 만들지 않는다.
UNIQUE(company_id, task_id, template_key)
11. 기존 Draft와 분리
기존 document_request_draft는 근로자에게 제출을 요청할 문서 종류, 언어와 안내 메시지를 저장한다.
새 document_generation_draft는 HWP/HWPX 양식에 실제로 입력할 값을 저장한다.
document_request_draft
→ 어떤 문서를 제출하도록 요청할지 관리
document_generation_draft
→ 특정 문서에 어떤 값을 입력할지 관리
1. Draft와 권한 조회
2. expected_version 확인
3. 전체 Snapshot 구조 검증
4. 읽기 전용 Field 존재 여부 확인
5. 읽기 전용 Field의 기존 값 유지 확인
6. 수정 가능 Field 타입·범위 검증
7. values_json 전체 교체
8. Version 증가
9. 최신 Draft 반환
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
문서 자동 생성을 위한 PostgreSQL JSONB 저장 전략
1. 목적
회사·근로자·계약 등 기존 관계형 데이터를 바탕으로 HWP/HWPX 문서에 필요한 값을 자동 입력하고, 사용자가 누락값을 보완한 뒤 최종 문서를 생성한다.
문서 양식마다 입력 필드와 구조가 달라 가변 데이터를 저장할 방법이 필요하다.
검토한 선택지는 다음과 같다.
최종적으로 별도 NoSQL을 추가하지 않고, 문서별 가변 입력값을 PostgreSQL JSONB에 저장한다.
2. 최종 결정
PostgreSQL을 계속 System of Record로 사용한다.
관계형 데이터는 기존 테이블에 유지하고, 특정 문서에 입력할 값만 JSONB Snapshot으로 저장한다.
JSONB는 관계형 데이터를 대체하지 않는다.
다음 정보는 기존 관계형 모델을 유지한다.
JSONB에는 문서에 입력할 구조화된 값만 저장한다.
3. 구현 범위
필수 범위
추가 범위
필수 흐름이 완성된 이후 다음 중 우선순위가 높은 항목을 추가한다.
확장 범위
다음 기능은 현재 범위에 포함하지 않는다.
4. 여러 문서 양식 지원
시스템 구조는 여러 문서 양식을 지원한다.
다만 사용자가 실행 중인 시스템에 새 양식을 등록하는 범용 Template Platform은 구현하지 않는다.
지원할 양식은 개발 시점에 확정된 고정 양식으로 관리한다.
현재 사용 가능한 Template Key 예시는 다음과 같다.
각 양식은 독립적인
template_key를 가진다.양식별로 HWP와 HWPX의 입력 필드 또는 지원 기능이 실질적으로 다르면 별도 Variant Key로 분리할 수 있다.
동일한 Canonical Values로 두 형식을 모두 생성할 수 있다면 하나의
template_key와supported_formats를 사용한다.5. 복수 양식 지원 방식
복수 양식은 다음 구조로 지원한다.
양식을 추가할 때는 다음 작업을 수행한다.
양식마다 새로운 Draft 테이블이나 API를 만들지 않는다.
6. Canonical Document Values
Server Domain Field, HWP 내부 Field, HWPX Label을 동일한 Key로 사용하지 않는다.
문서 Draft에는 Server와 AI가 공통으로 사용하는 Canonical Field를 저장한다.
예:
데이터 흐름:
JSONB에는 다음을 저장하지 않는다.
예시:
{ "employer": { "company_name": "주식회사 한빛정밀", "representative_name": "김민수" }, "worker": { "legal_name": "NGUYEN VAN AN", "nationality": "베트남" }, "contract": { "start_date": "2026-08-01", "end_date": "2027-07-31", "monthly_wage": 3000000, "accommodation_provided": true } }7. 양식 Contract 관리
양식 Contract는 데이터베이스 테이블이 아니라 Git으로 관리되는 정적 JSON 파일로 둔다.
예상 위치:
예시:
{ "template_key": "standard_labor_contract_v6", "schema_version": "1", "display_name": "표준근로계약서", "supported_formats": [ "hwp", "hwpx" ], "fields": { "employer.company_name": { "type": "string", "editable": true, "required": true, "max_length": 200 }, "worker.legal_name": { "type": "string", "editable": false, "required": true, "max_length": 120 }, "contract.monthly_wage": { "type": "integer", "editable": true, "required": true, "minimum": 0 }, "contract.accommodation_provided": { "type": "boolean", "editable": true, "required": false } } }Contract는 다음 정보만 포함한다.
범용 JSON Schema 전체를 구현하지 않는다.
8. Contract Version 관리
배포된 Contract 파일은 불변으로 취급한다.
예:
Draft에는 생성 당시의 다음 값을 저장한다.
현재 운영에서는 최신 Version 하나만 사용하더라도, 과거 Draft를 해석할 수 있도록 기존 Contract 파일을 보존한다.
Template Activation, Rollback, Digest 조합과 별도 Lifecycle 테이블은 만들지 않는다.
9. Server와 AI의 책임
Server
Server는 다음을 담당한다.
AI Document Service
AI Document Service는 다음을 담당한다.
AI는 Server의 PostgreSQL에 직접 접근하지 않는다.
Frontend
Frontend는 다음을 담당한다.
범용 Dynamic Form은 구현하지 않는다.
10. 데이터 모델
신규 테이블은
document_generation_draft하나만 추가한다.template_key사용한 문서 양식을 식별한다.
정적 Contract JSON의
template_key와 일치해야 한다.schema_versionDraft 생성 당시 사용한 Contract Version이다.
values_json문서에 입력할 전체 Canonical Values Snapshot이다.
versionJPA
@Version낙관적 잠금에 사용한다.하나의 Task에서 같은 양식을 여러 번 작성할 수 있으므로 다음 Unique Constraint는 만들지 않는다.
11. 기존 Draft와 분리
기존
document_request_draft는 근로자에게 제출을 요청할 문서 종류, 언어와 안내 메시지를 저장한다.새
document_generation_draft는 HWP/HWPX 양식에 실제로 입력할 값을 저장한다.목적과 생명주기가 다르므로 별도 Aggregate로 유지한다.
12. Draft 생성 API
요청:
{ "task_id": "uuid", "template_key": "standard_labor_contract_v6" }처리 순서:
Projection은 Contract Allow-list를 기준으로 명시적으로 수행한다.
응답 예:
{ "draft_id": "uuid", "task_id": "uuid", "template_key": "standard_labor_contract_v6", "schema_version": "1", "version": 0, "values": { "employer": { "company_name": "주식회사 한빛정밀" }, "worker": { "legal_name": "NGUYEN VAN AN" }, "contract": { "monthly_wage": 3000000 } }, "missing_fields": [ "contract.start_date", "contract.end_date" ] }Idempotency-Key와 Request Fingerprint는 구현하지 않는다.
Frontend는 요청 진행 중 생성 버튼을 비활성화해 중복 클릭을 줄인다.
13. Draft 조회 API
Server는 다음을 확인한다.
응답에는 다음을 포함한다.
14. Draft 수정 API
요청:
{ "expected_version": 2, "values": { "employer": { "company_name": "한빛정밀 제2사업장" }, "worker": { "legal_name": "NGUYEN VAN AN" }, "contract": { "start_date": "2026-08-01", "end_date": "2027-07-31", "monthly_wage": 3200000 } } }Client는 전체 Draft Snapshot을 전송한다.
읽기 전용 Field도 반드시 포함해야 한다.
읽기 전용 Field 규칙
처리 순서:
오류 예:
필수값이 누락돼도 Draft 저장은 허용한다.
15. 낙관적 잠금
Draft에는 JPA
@Version을 사용한다.자동 Merge는 구현하지 않는다.
Frontend는 충돌 시 다음과 같이 안내한다.
낙관적 잠금은 별도 분산 인프라 없이 전체 문서가 묵시적으로 덮어써지는 문제를 방지하므로 유지한다.
16. 입력 검증
Server 검증 범위는 다음으로 제한한다.
지원하지 않는 검증:
missing_fields는 무조건 필수인 Field만 계산한다.조건부 Field와 실제 Renderer 제약은 문서 생성 단계에서 AI Document Service가 확인한다.
17. Object와 Array 지원 범위
JSONB에는 중첩 Object를 저장할 수 있다.
범용 Object Array 검증 시스템은 구현하지 않는다.
특정 문서에 Object Array가 반드시 필요하다면 해당 배열 한 종류만 양식 전용 검증 코드로 처리한다.
양식에 실제 배열 요구가 없다면 Array 관련 구현과 완료 기준을 추가하지 않는다.
18. 문서 생성 API
요청:
{ "output_format": "hwp" }처리 순서:
외부 AI 호출을 기다리는 동안 DB Transaction을 유지하지 않는다.
잘못된 구조:
AI HTTP Client에는 다음 Timeout을 설정한다.
AI 요청 예:
{ "template_id": "standard_labor_contract_v6", "format": "hwp", "values": { "employer": { "company_name": "주식회사 한빛정밀" }, "worker": { "legal_name": "NGUYEN VAN AN" }, "contract": { "monthly_wage": 3200000 } } }다음 문제가 실제로 확인될 때만 비동기 Generation을 검토한다.
19. HWP와 HWPX 지원
각 양식과 출력 Format 조합을 독립적으로 검증한다.
예:
양식 Contract의
supported_formats에 지원 여부를 기록한다.HWP와 HWPX의 필드 구조가 다르면 별도 Template Key를 사용한다.
Format별 Capability가 필요하면 Contract에 간단히 기록한다.
{ "capabilities": { "hwp": { "photo": true, "signature": true }, "hwpx": { "photo": false, "signature": false } } }별도 Renderer Manifest나 Capability Revision 시스템은 만들지 않는다.
20. 직접 편집된 HWP/HWPX
생성된 HWP/HWPX는 JSONB Draft에서 만들어진 파생 산출물이다.
사용자가 생성 파일을 직접 열어 수정할 수는 있지만, 해당 변경을 JSONB Draft로 역동기화하지 않는다.
수정된 파일을 재업로드해 값을 역추출하는 기능은 구현하지 않는다.
21. 개인정보
현재는 가상 데이터를 사용한다.
사용 가능한 예:
사용하지 않는 정보:
실제 개인정보를 적용할 때는 별도로 다음을 결정해야 한다.
22. JSONB Index
현재는 JSONB 내부 Field 검색을 지원하지 않는다.
Draft는 다음 관계형 컬럼으로 조회한다.
GIN Index는 추가하지 않는다.
실제 JSON 내부 검색 요구가 생긴 뒤 Query와 PostgreSQL 실행계획을 기준으로 추가한다.
23. 테스트
Contract 테스트
Draft 테스트
문서 생성 테스트
PostgreSQL 통합 테스트
@Version24. 인수 기준
필수 완료
대표 양식 하나에 대해 다음 수직 흐름이 동작해야 한다.
추가 완료
다음 중 하나 이상을 추가한다.
확장 완료
시스템 구조는 복수 양식을 지원하지만, 모든 양식·포맷 조합의 완성을 필수 인수 조건으로 두지 않는다.
25. 완료 기준
26. 최종 결론
문서별 입력 구조가 달라도 핵심 업무 데이터가 PostgreSQL에 존재하므로, 별도 NoSQL을 도입하지 않는다.
최종 구조는 다음과 같다.
여러 문서 양식 지원은 유지한다.
다만 다음과 같은 Template 운영 플랫폼 기능은 구현하지 않는다.
우선 대표 양식 하나의 전체 수직 흐름을 완성하고, 같은 구조를 재사용해 HWPX와 추가 양식을 순차적으로 확장한다.
All reactions