-- 트리 구조 메모장 테이블 생성 -- 005_create_memo_tree_tables.sql -- 메모 트리 (프로젝트/워크스페이스) CREATE TABLE memo_trees ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, tree_type VARCHAR(50) DEFAULT 'general', -- 'novel', 'research', 'project', 'general' template_data JSONB, -- 템플릿별 메타데이터 settings JSONB DEFAULT '{}', -- 트리별 설정 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, is_public BOOLEAN DEFAULT FALSE, is_archived BOOLEAN DEFAULT FALSE ); -- 메모 노드 (트리의 각 노드) CREATE TABLE memo_nodes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tree_id UUID NOT NULL REFERENCES memo_trees(id) ON DELETE CASCADE, parent_id UUID REFERENCES memo_nodes(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- 기본 정보 title VARCHAR(500) NOT NULL, content TEXT, -- 실제 메모 내용 (Markdown) node_type VARCHAR(50) DEFAULT 'memo', -- 'folder', 'memo', 'chapter', 'character', 'plot' -- 트리 구조 관리 sort_order INTEGER DEFAULT 0, depth_level INTEGER DEFAULT 0, path TEXT, -- 경로 저장 (예: /1/3/7) -- 메타데이터 tags TEXT[], -- 태그 배열 node_metadata JSONB DEFAULT '{}', -- 노드별 메타데이터 (캐릭터 정보, 플롯 정보 등) -- 상태 관리 status VARCHAR(50) DEFAULT 'draft', -- 'draft', 'writing', 'review', 'complete' word_count INTEGER DEFAULT 0, -- 시간 정보 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- 제약 조건 CONSTRAINT no_self_reference CHECK (id != parent_id) ); -- 메모 노드 버전 관리 (선택적) CREATE TABLE memo_node_versions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), node_id UUID NOT NULL REFERENCES memo_nodes(id) ON DELETE CASCADE, version_number INTEGER NOT NULL, title VARCHAR(500) NOT NULL, content TEXT, node_metadata JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, created_by UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, UNIQUE(node_id, version_number) ); -- 메모 트리 공유 (협업 기능) CREATE TABLE memo_tree_shares ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tree_id UUID NOT NULL REFERENCES memo_trees(id) ON DELETE CASCADE, shared_with_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, permission_level VARCHAR(20) DEFAULT 'read', -- 'read', 'write', 'admin' created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, created_by UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, UNIQUE(tree_id, shared_with_user_id) ); -- 인덱스 생성 CREATE INDEX idx_memo_trees_user_id ON memo_trees(user_id); CREATE INDEX idx_memo_trees_type ON memo_trees(tree_type); CREATE INDEX idx_memo_nodes_tree_id ON memo_nodes(tree_id); CREATE INDEX idx_memo_nodes_parent_id ON memo_nodes(parent_id); CREATE INDEX idx_memo_nodes_user_id ON memo_nodes(user_id); CREATE INDEX idx_memo_nodes_path ON memo_nodes USING GIN(string_to_array(path, '/')); CREATE INDEX idx_memo_nodes_tags ON memo_nodes USING GIN(tags); CREATE INDEX idx_memo_nodes_type ON memo_nodes(node_type); CREATE INDEX idx_memo_node_versions_node_id ON memo_node_versions(node_id); CREATE INDEX idx_memo_tree_shares_tree_id ON memo_tree_shares(tree_id); -- 트리거 함수: updated_at 자동 업데이트 CREATE OR REPLACE FUNCTION update_memo_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 트리거 생성 CREATE TRIGGER memo_trees_updated_at BEFORE UPDATE ON memo_trees FOR EACH ROW EXECUTE FUNCTION update_memo_updated_at(); CREATE TRIGGER memo_nodes_updated_at BEFORE UPDATE ON memo_nodes FOR EACH ROW EXECUTE FUNCTION update_memo_updated_at(); -- 트리거 함수: 경로 자동 업데이트 CREATE OR REPLACE FUNCTION update_memo_node_path() RETURNS TRIGGER AS $$ BEGIN -- 루트 노드인 경우 IF NEW.parent_id IS NULL THEN NEW.path = '/' || NEW.id::text; NEW.depth_level = 0; ELSE -- 부모 노드의 경로를 가져와서 확장 SELECT path || '/' || NEW.id::text, depth_level + 1 INTO NEW.path, NEW.depth_level FROM memo_nodes WHERE id = NEW.parent_id; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 경로 업데이트 트리거 CREATE TRIGGER memo_nodes_path_update BEFORE INSERT OR UPDATE OF parent_id ON memo_nodes FOR EACH ROW EXECUTE FUNCTION update_memo_node_path(); -- 샘플 데이터 (개발용) -- 소설 템플릿 예시 INSERT INTO memo_trees (user_id, title, description, tree_type, template_data) SELECT u.id, '내 첫 번째 소설', '판타지 소설 프로젝트', 'novel', '{ "genre": "fantasy", "target_length": 100000, "chapters_planned": 20, "main_characters": [], "world_building": {} }'::jsonb FROM users u WHERE u.email = 'admin@test.com' LIMIT 1;