init.sql 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. -- 灵越智报 v2.0 数据库初始化脚本
  2. -- PostgreSQL 15+
  3. -- 创建数据库(如果不存在)
  4. -- CREATE DATABASE lingyue_zhibao;
  5. -- 连接到数据库
  6. -- \c lingyue_zhibao;
  7. -- 启用UUID扩展
  8. CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
  9. -- ============================================
  10. -- 1. 用户表 (users)
  11. -- ============================================
  12. CREATE TABLE IF NOT EXISTS users (
  13. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  14. username VARCHAR(50) UNIQUE NOT NULL,
  15. email VARCHAR(100) UNIQUE NOT NULL,
  16. password_hash VARCHAR(255) NOT NULL,
  17. avatar_url VARCHAR(500),
  18. role VARCHAR(20) NOT NULL DEFAULT 'user', -- admin/user/guest
  19. preferences JSONB DEFAULT '{}',
  20. last_login_at TIMESTAMP,
  21. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  22. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  23. );
  24. CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
  25. CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
  26. -- ============================================
  27. -- 2. 文档表 (documents)
  28. -- ============================================
  29. CREATE TABLE IF NOT EXISTS documents (
  30. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  31. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  32. name VARCHAR(255) NOT NULL,
  33. type VARCHAR(20) NOT NULL, -- pdf/word/image/markdown/other
  34. status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/uploading/parsing/completed/failed
  35. file_size BIGINT,
  36. file_url VARCHAR(500),
  37. thumbnail_url VARCHAR(500),
  38. parsed_text TEXT,
  39. parse_status VARCHAR(20), -- pending/parsing/completed/failed
  40. parse_progress INTEGER DEFAULT 0, -- 0-100
  41. parse_error TEXT,
  42. parse_started_at TIMESTAMP,
  43. parse_completed_at TIMESTAMP,
  44. metadata JSONB DEFAULT '{}', -- pageCount, ocrConfidence, layoutStructure等
  45. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  46. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  47. );
  48. CREATE INDEX IF NOT EXISTS idx_documents_user_id ON documents(user_id);
  49. CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(status);
  50. CREATE INDEX IF NOT EXISTS idx_documents_type ON documents(type);
  51. CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(created_at DESC);
  52. CREATE INDEX IF NOT EXISTS idx_documents_metadata ON documents USING GIN(metadata);
  53. CREATE INDEX IF NOT EXISTS idx_documents_parsed_text ON documents USING GIN(to_tsvector('english', parsed_text)); -- 全文搜索
  54. -- ============================================
  55. -- 3. 要素表 (elements)
  56. -- ============================================
  57. CREATE TABLE IF NOT EXISTS elements (
  58. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  59. document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  60. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  61. type VARCHAR(20) NOT NULL, -- amount/company/person/location/date/other
  62. label VARCHAR(100) NOT NULL,
  63. value TEXT NOT NULL,
  64. position JSONB, -- {page, x, y, width, height}
  65. confidence DECIMAL(3,2), -- 0.00-1.00
  66. extraction_method VARCHAR(20), -- ai/regex/rule/manual
  67. graph_node_id UUID, -- 关联的图节点ID
  68. metadata JSONB DEFAULT '{}',
  69. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  70. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  71. );
  72. CREATE INDEX IF NOT EXISTS idx_elements_document_id ON elements(document_id);
  73. CREATE INDEX IF NOT EXISTS idx_elements_user_id ON elements(user_id);
  74. CREATE INDEX IF NOT EXISTS idx_elements_type ON elements(type);
  75. CREATE INDEX IF NOT EXISTS idx_elements_graph_node_id ON elements(graph_node_id);
  76. CREATE INDEX IF NOT EXISTS idx_elements_position ON elements USING GIN(position);
  77. -- ============================================
  78. -- 4. 批注表 (annotations)
  79. -- ============================================
  80. CREATE TABLE IF NOT EXISTS annotations (
  81. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  82. document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  83. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  84. text TEXT NOT NULL,
  85. position JSONB NOT NULL, -- {page, start: {x, y}, end: {x, y}}
  86. type VARCHAR(20) NOT NULL, -- highlight/strikethrough/suggestion
  87. suggestion TEXT,
  88. ai_generated BOOLEAN DEFAULT FALSE,
  89. confidence DECIMAL(3,2),
  90. status VARCHAR(20) DEFAULT 'pending', -- pending/accepted/rejected
  91. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  92. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  93. );
  94. CREATE INDEX IF NOT EXISTS idx_annotations_document_id ON annotations(document_id);
  95. CREATE INDEX IF NOT EXISTS idx_annotations_user_id ON annotations(user_id);
  96. CREATE INDEX IF NOT EXISTS idx_annotations_type ON annotations(type);
  97. CREATE INDEX IF NOT EXISTS idx_annotations_status ON annotations(status);
  98. -- ============================================
  99. -- 5. 关系网络表 (graphs)
  100. -- ============================================
  101. CREATE TABLE IF NOT EXISTS graphs (
  102. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  103. document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  104. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  105. name VARCHAR(255) NOT NULL,
  106. nodes JSONB NOT NULL DEFAULT '[]', -- GraphNode数组
  107. edges JSONB NOT NULL DEFAULT '[]', -- GraphEdge数组
  108. calculation_result JSONB,
  109. calculation_status VARCHAR(20), -- pending/completed/failed
  110. metadata JSONB DEFAULT '{}',
  111. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  112. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  113. );
  114. CREATE INDEX IF NOT EXISTS idx_graphs_document_id ON graphs(document_id);
  115. CREATE INDEX IF NOT EXISTS idx_graphs_user_id ON graphs(user_id);
  116. CREATE INDEX IF NOT EXISTS idx_graphs_nodes ON graphs USING GIN(nodes);
  117. CREATE INDEX IF NOT EXISTS idx_graphs_edges ON graphs USING GIN(edges);
  118. -- ============================================
  119. -- 6. 解析任务表 (parse_tasks)
  120. -- ============================================
  121. CREATE TABLE IF NOT EXISTS parse_tasks (
  122. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  123. document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  124. status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/processing/completed/failed
  125. progress INTEGER DEFAULT 0, -- 0-100
  126. current_step VARCHAR(100),
  127. error_message TEXT,
  128. options JSONB DEFAULT '{}', -- 解析选项
  129. started_at TIMESTAMP,
  130. completed_at TIMESTAMP,
  131. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  132. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  133. );
  134. CREATE INDEX IF NOT EXISTS idx_parse_tasks_document_id ON parse_tasks(document_id);
  135. CREATE INDEX IF NOT EXISTS idx_parse_tasks_status ON parse_tasks(status);
  136. -- ============================================
  137. -- 7. 会话表 (sessions)
  138. -- ============================================
  139. CREATE TABLE IF NOT EXISTS sessions (
  140. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  141. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  142. token_hash VARCHAR(255) NOT NULL UNIQUE,
  143. refresh_token_hash VARCHAR(255) NOT NULL UNIQUE,
  144. expires_at TIMESTAMP NOT NULL,
  145. ip_address VARCHAR(45),
  146. user_agent TEXT,
  147. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  148. last_used_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  149. );
  150. CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
  151. CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash);
  152. CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
  153. -- ============================================
  154. -- 创建更新时间触发器函数
  155. -- ============================================
  156. CREATE OR REPLACE FUNCTION update_updated_at_column()
  157. RETURNS TRIGGER AS $$
  158. BEGIN
  159. NEW.updated_at = CURRENT_TIMESTAMP;
  160. RETURN NEW;
  161. END;
  162. $$ language 'plpgsql';
  163. -- 为所有表创建更新时间触发器
  164. CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
  165. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  166. CREATE TRIGGER update_documents_updated_at BEFORE UPDATE ON documents
  167. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  168. CREATE TRIGGER update_elements_updated_at BEFORE UPDATE ON elements
  169. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  170. CREATE TRIGGER update_annotations_updated_at BEFORE UPDATE ON annotations
  171. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  172. CREATE TRIGGER update_graphs_updated_at BEFORE UPDATE ON graphs
  173. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  174. CREATE TRIGGER update_parse_tasks_updated_at BEFORE UPDATE ON parse_tasks
  175. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
  176. CREATE TRIGGER update_sessions_updated_at BEFORE UPDATE ON sessions
  177. FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();