# 数据库表结构设计 (`database_schema_design.md`)

## 1. 核心设计哲学与技术选型

经过深入讨论，我们确立了以**“为不同形态的数据建立专属的、高度优化的持久化方案”**为核心的设计哲学。这完美契合了项目追求稳定、健壮的“Rustic”风格。

我们的数据库技术栈将统一在 **PostgreSQL** 上，并通过其强大的扩展生态来满足特定的数据存储需求。

### 1.1. 时间序列数据: PostgreSQL + TimescaleDB

对于系统中最核心、数据量最大的**时间序列数据**（如财务指标、市场行情），我们明确采用 **TimescaleDB** 扩展。

- **为什么选择 TimescaleDB?**
  - **解决性能瓶颈**: 它通过 **Hypertables (超表)** 机制，将一张巨大的时序表在物理上切分为按时间范围管理的小块 (Chunks)。这使得写入和基于时间的查询性能能够保持恒定的高速，不会随数据量增长而衰减。
  - **支持稀疏与乱序数据**: 它的架构天然支持稀疏和乱序的数据写入，完美契合我们“有啥就存啥、随时补齐”的数据采集模式。
  - **内置高级功能**: 它提供了强大的**持续聚合 (Continuous Aggregates)** 功能，可以高效地、自动化地将高频数据（如 Ticks）降采样为分钟、小时、天等级别的聚合数据（K线），且查询速度极快。
  - **零技术栈增加**: 它是一个 PostgreSQL 扩展，我们仍然使用标准 SQL 进行所有操作，无需引入和维护新的数据库系统。

### 1.2. 其他数据类型

- **生成式分析内容**: 使用标准的关系表，将结构化的元数据作为索引字段，将非结构化的文本存入 `TEXT` 字段。
- **静态与半静态数据**: 使用标准的关系表进行存储。
- **工作流与应用配置**: **优先使用 YAML 配置文件** (`config/analysis-config.yaml` 等) 来定义静态的工作流和分析模块。数据库仅用于存储需要通过管理界面动态修改的系统级配置。
- **执行过程元数据**: 使用标准的关系表来记录任务执行的结构化日志。

## 2. 详细 Schema 设计

### 2.1. 时间序列数据表

#### 2.1.1. `time_series_financials` (财务指标表)

```sql
-- 1. 创建标准的关系表
CREATE TABLE time_series_financials (
    symbol VARCHAR(32) NOT NULL,
    metric_name VARCHAR(64) NOT NULL,      -- 标准化指标名 (e.g., 'roe', 'revenue')
    period_date DATE NOT NULL,             -- 报告期 (e.g., '2023-12-31')
    value NUMERIC NOT NULL,                -- 指标值
    source VARCHAR(64),                    -- 数据来源 (e.g., 'tushare')
    PRIMARY KEY (symbol, metric_name, period_date)
);

-- 2. 将其转换为 TimescaleDB 的超表
SELECT create_hypertable('time_series_financials', 'period_date');

COMMENT ON TABLE time_series_financials IS '存储标准化的、以时间序列格式存在的财务指标，由 TimescaleDB 管理';
```

#### 2.1.2. `daily_market_data` (每日市场数据表)

```sql
-- 1. 创建标准的关系表
CREATE TABLE daily_market_data (
    symbol VARCHAR(32) NOT NULL,
    trade_date DATE NOT NULL,
    open_price NUMERIC,
    high_price NUMERIC,
    low_price NUMERIC,
    close_price NUMERIC,
    volume BIGINT,
    pe NUMERIC,
    pb NUMERIC,
    total_mv NUMERIC,                      -- 总市值
    PRIMARY KEY (symbol, trade_date)
);

-- 2. 将其转换为 TimescaleDB 的超表
SELECT create_hypertable('daily_market_data', 'trade_date');

COMMENT ON TABLE daily_market_data IS '存储每日更新的股价、成交量和关键估值指标，由 TimescaleDB 管理';
```

---

### 2.2. `analysis_results` (AI分析结果表)

```sql
CREATE TABLE analysis_results (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    symbol VARCHAR(32) NOT NULL,
    module_id VARCHAR(64) NOT NULL,        -- 分析模块ID (e.g., 'bull_case')
    generated_at TIMESTAMTz NOT NULL DEFAULT NOW(),
    model_name VARCHAR(64),                -- 使用的AI模型
    content TEXT NOT NULL,                 -- AI生成的完整文本
    meta_data JSONB                        -- 用于存储token用量、耗时等元数据
);

COMMENT ON TABLE analysis_results IS '存储由AI大模型生成的分析报告文本';
CREATE INDEX idx_analysis_results_symbol_module ON analysis_results (symbol, module_id, generated_at DESC);
```

---

### 2.3. `company_profiles` (公司基本信息表)

```sql
CREATE TABLE company_profiles (
    symbol VARCHAR(32) PRIMARY KEY,       -- 标准化股票代码
    name VARCHAR(255) NOT NULL,            -- 公司名称
    industry VARCHAR(255),                 -- 行业
    list_date DATE,                        -- 上市日期
    additional_info JSONB,                 -- 其他信息
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE company_profiles IS '存储公司的基本、相对静态的信息';
```

---

### 2.4. `system_config` (系统配置表)

```sql
CREATE TABLE system_config (
    config_key VARCHAR(255) PRIMARY KEY,
    config_value JSONB NOT NULL,
    description TEXT,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE system_config IS '存储可通过UI动态修改的系统级配置，敏感信息(API Key)不应存储于此';
```

---

### 2.5. `execution_logs` (执行过程日志表)

```sql
CREATE TABLE execution_logs (
    id BIGSERIAL PRIMARY KEY,
    report_id UUID NOT NULL,               -- 关联的报告ID
    step_name VARCHAR(255) NOT NULL,       -- 步骤名称
    status VARCHAR(32) NOT NULL,           -- 'running', 'completed', 'failed'
    start_time TIMESTAMPTZ NOT NULL,
    end_time TIMESTAMPTZ,
    duration_ms INTEGER,
    token_usage JSONB,                     -- { "prompt": 100, "completion": 200 }
    error_message TEXT,
    log_details JSONB
);

COMMENT ON TABLE execution_logs IS '记录报告生成过程中每个步骤的结构化日志';
CREATE INDEX idx_execution_logs_report_id ON execution_logs (report_id);
```
