mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 12:59:11 +00:00
Merge feat/meeting-ai into main
회의 종료 API 및 AI 회의록 통합 기능을 main 브랜치에 병합 주요 기능: - 회의 종료 시 AI 자동 요약 생성 - 안건별 논의사항/결정사항 자동 정리 - 주요 키워드 추출 - Todo 및 보류사항 자동 식별 충돌 해결: - MinutesSectionEntity: id 필드명으로 통일 - AgendaSection 관련 파일들: feat/meeting-ai 버전 사용 - application.yml: AI Service 포트 8086 설정 유지 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
-- ========================================
|
||||
-- V3: 회의종료 기능을 위한 스키마 확장
|
||||
-- ========================================
|
||||
-- 작성일: 2025-10-28
|
||||
-- 설명: 참석자별 회의록, 안건별 섹션, AI 요약 결과 캐싱, Todo 자동 추출 지원
|
||||
|
||||
-- ========================================
|
||||
-- 1. minutes 테이블 확장
|
||||
-- ========================================
|
||||
-- 참석자별 회의록 지원 (user_id로 구분)
|
||||
-- user_id가 NULL이면 AI 통합 회의록, NOT NULL이면 참석자별 회의록
|
||||
|
||||
ALTER TABLE minutes
|
||||
ADD COLUMN IF NOT EXISTS user_id VARCHAR(100);
|
||||
|
||||
-- 인덱스 추가
|
||||
CREATE INDEX IF NOT EXISTS idx_minutes_meeting_user ON minutes(meeting_id, user_id);
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON COLUMN minutes.user_id IS '작성자 사용자 ID (NULL: AI 통합 회의록, NOT NULL: 참석자별 회의록)';
|
||||
|
||||
-- ========================================
|
||||
-- 2. agenda_sections 테이블 생성
|
||||
-- ========================================
|
||||
-- 안건별 AI 요약 결과 저장
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agenda_sections (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
minutes_id VARCHAR(36) NOT NULL,
|
||||
meeting_id VARCHAR(50) NOT NULL,
|
||||
|
||||
-- 안건 정보
|
||||
agenda_number INT NOT NULL,
|
||||
agenda_title VARCHAR(200) NOT NULL,
|
||||
|
||||
-- AI 요약 결과
|
||||
ai_summary_short TEXT,
|
||||
discussions TEXT,
|
||||
decisions JSON,
|
||||
pending_items JSON,
|
||||
opinions JSON,
|
||||
|
||||
-- 메타데이터
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 외래키
|
||||
CONSTRAINT fk_agenda_sections_minutes
|
||||
FOREIGN KEY (minutes_id) REFERENCES minutes(id)
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT fk_agenda_sections_meeting
|
||||
FOREIGN KEY (meeting_id) REFERENCES meetings(meeting_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 인덱스 생성
|
||||
CREATE INDEX IF NOT EXISTS idx_sections_meeting ON agenda_sections(meeting_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sections_agenda ON agenda_sections(meeting_id, agenda_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_sections_minutes ON agenda_sections(minutes_id);
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON TABLE agenda_sections IS '안건별 회의록 섹션 - AI 요약 결과 저장';
|
||||
COMMENT ON COLUMN agenda_sections.id IS '섹션 고유 ID';
|
||||
COMMENT ON COLUMN agenda_sections.minutes_id IS '회의록 ID (통합 회의록 참조)';
|
||||
COMMENT ON COLUMN agenda_sections.meeting_id IS '회의 ID';
|
||||
COMMENT ON COLUMN agenda_sections.agenda_number IS '안건 번호 (1, 2, 3...)';
|
||||
COMMENT ON COLUMN agenda_sections.agenda_title IS '안건 제목';
|
||||
COMMENT ON COLUMN agenda_sections.ai_summary_short IS 'AI 생성 짧은 요약 (1줄, 20자 이내)';
|
||||
COMMENT ON COLUMN agenda_sections.discussions IS '논의 사항 (핵심 내용 3-5문장)';
|
||||
COMMENT ON COLUMN agenda_sections.decisions IS '결정 사항 배열 (JSON)';
|
||||
COMMENT ON COLUMN agenda_sections.pending_items IS '보류 사항 배열 (JSON)';
|
||||
COMMENT ON COLUMN agenda_sections.opinions IS '참석자별 의견 (JSON: [{speaker, opinion}])';
|
||||
|
||||
-- ========================================
|
||||
-- 3. ai_summaries 테이블 생성
|
||||
-- ========================================
|
||||
-- AI 요약 결과 캐싱 및 성능 최적화
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ai_summaries (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
meeting_id VARCHAR(50) NOT NULL,
|
||||
summary_type VARCHAR(50) NOT NULL,
|
||||
|
||||
-- 입력 정보
|
||||
source_minutes_ids JSON NOT NULL,
|
||||
|
||||
-- AI 처리 결과
|
||||
result JSON NOT NULL,
|
||||
processing_time_ms INT,
|
||||
model_version VARCHAR(50) DEFAULT 'claude-3.5-sonnet',
|
||||
|
||||
-- 통계 정보
|
||||
keywords JSON,
|
||||
statistics JSON,
|
||||
|
||||
-- 메타데이터
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 외래키
|
||||
CONSTRAINT fk_ai_summaries_meeting
|
||||
FOREIGN KEY (meeting_id) REFERENCES meetings(meeting_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 인덱스 생성
|
||||
CREATE INDEX IF NOT EXISTS idx_summaries_meeting ON ai_summaries(meeting_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_summaries_type ON ai_summaries(meeting_id, summary_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_summaries_created ON ai_summaries(created_at);
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON TABLE ai_summaries IS 'AI 요약 결과 캐시 테이블';
|
||||
COMMENT ON COLUMN ai_summaries.id IS '요약 결과 고유 ID';
|
||||
COMMENT ON COLUMN ai_summaries.meeting_id IS '회의 ID';
|
||||
COMMENT ON COLUMN ai_summaries.summary_type IS '요약 타입 (CONSOLIDATED: 통합 요약, TODO_EXTRACTION: Todo 추출)';
|
||||
COMMENT ON COLUMN ai_summaries.source_minutes_ids IS '통합에 사용된 회의록 ID 배열 (JSON)';
|
||||
COMMENT ON COLUMN ai_summaries.result IS 'AI 응답 전체 결과 (JSON)';
|
||||
COMMENT ON COLUMN ai_summaries.processing_time_ms IS 'AI 처리 시간 (밀리초)';
|
||||
COMMENT ON COLUMN ai_summaries.model_version IS '사용한 AI 모델 버전';
|
||||
COMMENT ON COLUMN ai_summaries.keywords IS '주요 키워드 배열 (JSON)';
|
||||
COMMENT ON COLUMN ai_summaries.statistics IS '통계 정보 (참석자 수, 안건 수 등, JSON)';
|
||||
|
||||
-- ========================================
|
||||
-- 4. todos 테이블 확장
|
||||
-- ========================================
|
||||
-- AI 자동 추출 정보 추가
|
||||
|
||||
ALTER TABLE todos
|
||||
ADD COLUMN IF NOT EXISTS extracted_by VARCHAR(50) DEFAULT 'AI',
|
||||
ADD COLUMN IF NOT EXISTS section_reference VARCHAR(200),
|
||||
ADD COLUMN IF NOT EXISTS extraction_confidence DECIMAL(3,2) DEFAULT 0.00;
|
||||
|
||||
-- 인덱스 추가
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_extracted ON todos(extracted_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_meeting ON todos(meeting_id);
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON COLUMN todos.extracted_by IS 'Todo 추출 방법 (AI: AI 자동 추출, MANUAL: 사용자 수동 작성)';
|
||||
COMMENT ON COLUMN todos.section_reference IS '관련 회의록 섹션 참조 (예: "안건 1", "결정사항 #3")';
|
||||
COMMENT ON COLUMN todos.extraction_confidence IS 'AI 추출 신뢰도 점수 (0.00~1.00)';
|
||||
|
||||
-- ========================================
|
||||
-- 5. 제약조건 및 트리거 추가
|
||||
-- ========================================
|
||||
|
||||
-- updated_at 자동 업데이트 함수 (PostgreSQL)
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- agenda_sections 테이블에 updated_at 트리거 추가
|
||||
DROP TRIGGER IF EXISTS update_agenda_sections_updated_at ON agenda_sections;
|
||||
CREATE TRIGGER update_agenda_sections_updated_at
|
||||
BEFORE UPDATE ON agenda_sections
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- ========================================
|
||||
-- 6. 샘플 데이터 (개발 환경용)
|
||||
-- ========================================
|
||||
-- 실제 운영 환경에서는 주석 처리
|
||||
|
||||
-- 샘플 회의록 (참석자별)
|
||||
-- INSERT INTO minutes (id, meeting_id, user_id, content, created_at)
|
||||
-- VALUES
|
||||
-- ('sample-minutes-1', 'sample-meeting-1', 'user1@example.com', '회의록 내용 1...', CURRENT_TIMESTAMP),
|
||||
-- ('sample-minutes-2', 'sample-meeting-1', 'user2@example.com', '회의록 내용 2...', CURRENT_TIMESTAMP);
|
||||
|
||||
-- 샘플 통합 회의록 (user_id가 NULL)
|
||||
-- INSERT INTO minutes (id, meeting_id, user_id, content, created_at)
|
||||
-- VALUES
|
||||
-- ('sample-minutes-consolidated', 'sample-meeting-1', NULL, 'AI 통합 회의록...', CURRENT_TIMESTAMP);
|
||||
|
||||
-- 샘플 안건 섹션
|
||||
-- INSERT INTO agenda_sections (id, minutes_id, meeting_id, agenda_number, agenda_title, ai_summary_short, discussions, decisions, pending_items, opinions)
|
||||
-- VALUES
|
||||
-- ('sample-section-1', 'sample-minutes-consolidated', 'sample-meeting-1', 1, '신제품 기획 방향성',
|
||||
-- '타겟 고객을 20-30대로 설정...',
|
||||
-- '신제품의 주요 타겟 고객층을 20-30대 직장인으로 설정하고...',
|
||||
-- '["타겟 고객: 20-30대 직장인", "UI/UX 개선을 최우선 과제로 설정"]'::json,
|
||||
-- '[]'::json,
|
||||
-- '[{"speaker": "김민준", "opinion": "타겟 고객층을 명확히 설정하여 마케팅 전략 수립 필요"}]'::json);
|
||||
|
||||
-- ========================================
|
||||
-- 7. 권한 설정 (필요시)
|
||||
-- ========================================
|
||||
-- GRANT SELECT, INSERT, UPDATE, DELETE ON agenda_sections TO meeting_service_user;
|
||||
-- GRANT SELECT, INSERT, UPDATE, DELETE ON ai_summaries TO meeting_service_user;
|
||||
-- GRANT SELECT, INSERT, UPDATE, DELETE ON ai_summaries TO ai_service_user;
|
||||
@@ -0,0 +1,37 @@
|
||||
-- ========================================
|
||||
-- V4: agenda_sections 테이블에 todos 컬럼 추가
|
||||
-- ========================================
|
||||
-- 작성일: 2025-10-28
|
||||
-- 설명: AI가 추출한 Todo를 안건별 섹션에 저장
|
||||
|
||||
-- ========================================
|
||||
-- 1. agenda_sections 테이블에 todos 컬럼 추가
|
||||
-- ========================================
|
||||
|
||||
ALTER TABLE agenda_sections
|
||||
ADD COLUMN IF NOT EXISTS todos JSON;
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON COLUMN agenda_sections.todos IS 'AI 추출 Todo 목록 (JSON: [{title, assignee, dueDate, description, priority}])';
|
||||
|
||||
-- ========================================
|
||||
-- 2. 샘플 데이터 구조 (참고용)
|
||||
-- ========================================
|
||||
--
|
||||
-- todos JSON 구조:
|
||||
-- [
|
||||
-- {
|
||||
-- "title": "시장 조사 보고서 작성",
|
||||
-- "assignee": "김민준",
|
||||
-- "dueDate": "2025-02-15",
|
||||
-- "description": "20-30대 타겟 시장 조사",
|
||||
-- "priority": "HIGH"
|
||||
-- },
|
||||
-- {
|
||||
-- "title": "UI/UX 개선안 초안 작성",
|
||||
-- "assignee": "이서연",
|
||||
-- "dueDate": "2025-02-20",
|
||||
-- "description": "모바일 우선 UI 개선",
|
||||
-- "priority": "MEDIUM"
|
||||
-- }
|
||||
-- ]
|
||||
@@ -0,0 +1,52 @@
|
||||
-- ========================================
|
||||
-- V5: minutes_sections 테이블 재생성
|
||||
-- ========================================
|
||||
-- 작성일: 2025-10-28
|
||||
-- 설명: minutes_sections 테이블을 Entity 구조에 맞게 재생성
|
||||
|
||||
-- 1. 기존 테이블이 있으면 삭제
|
||||
DROP TABLE IF EXISTS minutes_sections CASCADE;
|
||||
|
||||
-- 2. Entity 구조에 맞는 테이블 생성
|
||||
CREATE TABLE minutes_sections (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
minutes_id VARCHAR(50) NOT NULL,
|
||||
type VARCHAR(50),
|
||||
title VARCHAR(200),
|
||||
content TEXT,
|
||||
"order" INTEGER,
|
||||
verified BOOLEAN DEFAULT FALSE,
|
||||
locked BOOLEAN DEFAULT FALSE,
|
||||
locked_by VARCHAR(50),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT fk_minutes_sections_minutes
|
||||
FOREIGN KEY (minutes_id) REFERENCES minutes(id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 3. 인덱스 생성
|
||||
CREATE INDEX idx_minutes_sections_minutes ON minutes_sections(minutes_id);
|
||||
CREATE INDEX idx_minutes_sections_order ON minutes_sections(minutes_id, "order");
|
||||
CREATE INDEX idx_minutes_sections_type ON minutes_sections(type);
|
||||
CREATE INDEX idx_minutes_sections_verified ON minutes_sections(verified);
|
||||
|
||||
-- 4. 코멘트 추가
|
||||
COMMENT ON TABLE minutes_sections IS '참석자별 회의록 안건 섹션 - AI 통합 회의록 생성 입력 데이터';
|
||||
COMMENT ON COLUMN minutes_sections.id IS '섹션 고유 ID';
|
||||
COMMENT ON COLUMN minutes_sections.minutes_id IS '참석자별 회의록 ID (minutes.id 참조)';
|
||||
COMMENT ON COLUMN minutes_sections.type IS '섹션 타입 (AGENDA: 안건, DISCUSSION: 논의사항, DECISION: 결정사항 등)';
|
||||
COMMENT ON COLUMN minutes_sections.title IS '섹션 제목';
|
||||
COMMENT ON COLUMN minutes_sections.content IS '섹션 내용 (참석자가 작성한 메모)';
|
||||
COMMENT ON COLUMN minutes_sections."order" IS '섹션 순서';
|
||||
COMMENT ON COLUMN minutes_sections.verified IS '검증 완료 여부';
|
||||
COMMENT ON COLUMN minutes_sections.locked IS '편집 잠금 여부';
|
||||
COMMENT ON COLUMN minutes_sections.locked_by IS '잠금 설정한 사용자 ID';
|
||||
|
||||
-- 5. updated_at 자동 업데이트 트리거
|
||||
DROP TRIGGER IF EXISTS update_minutes_sections_updated_at ON minutes_sections;
|
||||
CREATE TRIGGER update_minutes_sections_updated_at
|
||||
BEFORE UPDATE ON minutes_sections
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
-- ========================================
|
||||
-- V7: minutes 테이블에 decisions 추가 및 agenda_sections 리팩토링
|
||||
-- ========================================
|
||||
-- 작성일: 2025-10-29
|
||||
-- 설명:
|
||||
-- 1. minutes 테이블에 decisions (결정사항) 컬럼 추가
|
||||
-- 2. agenda_sections 테이블에서 discussions, decisions, opinions를 summary로 통합
|
||||
|
||||
-- ========================================
|
||||
-- 1. minutes 테이블에 decisions 컬럼 추가
|
||||
-- ========================================
|
||||
-- 회의 전체 결정사항을 TEXT 형식으로 저장
|
||||
|
||||
ALTER TABLE minutes
|
||||
ADD COLUMN IF NOT EXISTS decisions TEXT;
|
||||
|
||||
COMMENT ON COLUMN minutes.decisions IS '회의 전체 결정사항 (회의록 수정 시 입력)';
|
||||
|
||||
-- ========================================
|
||||
-- 2. agenda_sections 테이블 백업 및 데이터 마이그레이션
|
||||
-- ========================================
|
||||
-- 기존 데이터 보존을 위한 임시 백업 테이블 생성
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agenda_sections_backup AS
|
||||
SELECT * FROM agenda_sections;
|
||||
|
||||
-- ========================================
|
||||
-- 3. agenda_sections 테이블 컬럼 변경
|
||||
-- ========================================
|
||||
-- discussions, decisions, opinions → summary 통합
|
||||
|
||||
-- summary 컬럼 추가 (기존 discussions 내용으로 초기화)
|
||||
ALTER TABLE agenda_sections
|
||||
ADD COLUMN IF NOT EXISTS summary TEXT;
|
||||
|
||||
-- 기존 데이터 마이그레이션: discussions 내용을 summary로 복사
|
||||
UPDATE agenda_sections
|
||||
SET summary = COALESCE(discussions, '');
|
||||
|
||||
-- 기존 컬럼 삭제
|
||||
ALTER TABLE agenda_sections
|
||||
DROP COLUMN IF EXISTS discussions,
|
||||
DROP COLUMN IF EXISTS decisions,
|
||||
DROP COLUMN IF EXISTS opinions;
|
||||
|
||||
-- 코멘트 추가
|
||||
COMMENT ON COLUMN agenda_sections.summary IS '안건별 회의록 요약 (사용자가 입력한 회의록 내용을 AI가 요약한 결과)';
|
||||
|
||||
-- ========================================
|
||||
-- 4. 인덱스 및 트리거 유지
|
||||
-- ========================================
|
||||
-- 기존 인덱스 및 트리거는 그대로 유지됨
|
||||
|
||||
-- ========================================
|
||||
-- 5. 백업 테이블 정리 안내
|
||||
-- ========================================
|
||||
-- agenda_sections_backup 테이블은 수동으로 검증 후 삭제
|
||||
COMMENT ON TABLE agenda_sections_backup IS 'V7 마이그레이션 백업 - 검증 후 수동 삭제 필요';
|
||||
Reference in New Issue
Block a user