Metadata-Version: 2.4
Name: root_db_api
Version: 0.5.0
Summary: A core API service for database operations.
Author-email: Cheng Li <tbd@tbd.com>
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: flask>=3.1.1
Requires-Dist: flasgger==0.9.7b2
Requires-Dist: geoalchemy2==0.17.1
Requires-Dist: shapely>=2.1.1
Requires-Dist: numpy==2.3.1
Requires-Dist: folium==0.20.0
Requires-Dist: tenacity==9.1.2
Requires-Dist: tqdm==4.67.1
Requires-Dist: pytz==2025.2
Requires-Dist: prometheus-client==0.22.1
Requires-Dist: flask-caching>=2.3.1
Requires-Dist: redis>=6.4.0
Requires-Dist: cos-python-sdk-v5==1.9.37
Requires-Dist: python-dotenv==1.1.1
Requires-Dist: requests==2.32.4
Requires-Dist: pyyaml==6.0.2
Requires-Dist: pydantic==2.11.7
Requires-Dist: sqlalchemy==2.0.41
Requires-Dist: psycopg2-binary==2.9.10
Requires-Dist: openpyxl>=3.1.0
Requires-Dist: gunicorn>=23.0.0
Requires-Dist: pytest==8.4.1
Requires-Dist: pytest-cov==6.2.0
Requires-Dist: pytest-mock==3.14.0
Requires-Dist: flask-sqlalchemy>=3.1.1

# ROOT DB API

A core API service for database operations in the FST (File System Tree) data pipeline.

![Version](https://img.shields.io/badge/version-0.5.0-blue.svg)
![Python](https://img.shields.io/badge/python-3.12+-green.svg)
![Flask](https://img.shields.io/badge/flask-3.1.1+-red.svg)

## 📝 Description

ROOT DB API 是基于Flask的REST API服务，为自动驾驶数据管理提供全面的数据库操作功能，包括bag文件、FST节点、项目、标签、主题、几何数据和真值数据的管理。具备完整的Swagger/OpenAPI中文文档和强大的数据管理能力。

## 🚀 Features

- **REST API接口** 提供全面的数据管理功能
- **Swagger/OpenAPI文档** 提供交互式UI界面
- **PostgreSQL数据库** 采用SQLAlchemy ORM
- **地理空间支持** 集成PostGIS和Shapely
- **完善测试覆盖** 基于pytest框架
- **生产环境就绪** 支持Gunicorn部署

## 🛠 Tech Stack

| 组件 | 技术栈 |
|------|--------|
| **Web框架** | Flask 3.1.1+ |
| **数据库** | PostgreSQL + SQLAlchemy ORM |
| **API文档** | Swagger/OpenAPI (Flasgger) |
| **地理空间** | GeoAlchemy2 + Shapely + Folium |
| **部署服务** | Gunicorn |
| **测试框架** | pytest + pytest-cov + pytest-mock |
| **包管理器** | uv |

## 📋 API Endpoints

### 🗂️ Bag管理 API (`/api/bags`)

#### `GET /api/bags/all`
Get all bags grouped by project with complete Pangu and Minerva data.

**Response Schema:**
```json
{
  "type": "object",
  "patternProperties": {
    "^[a-zA-Z0-9_-]+$": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "project_id": {"type": "integer"},
          "update_time": {"type": "string", "format": "date-time"},
          "tile_id": {"type": "string"},
          "is_decoded": {"type": "boolean"},
          "pangu_data": {"type": "object"},
          "minerva_data": {"type": "object"}
        }
      }
    }
  }
}
```

**Example Response:**
```json
{
  "project_dfdi": [
    {
      "bag_name": "PL061763_event_ld_gps_event_20230807-115627_0.bag.dir",
      "project_id": 1,
      "update_time": "2023-08-07T11:56:27Z",
      "tile_id": "12345",
      "is_decoded": true,
      "pangu_data": {
        "vehicle": "PL061763",
        "datetime": "2023-08-07T11:56:27Z",
        "bag_path": "/path/to/bag",
        "data_path": "/path/to/data"
      },
      "minerva_data": null
    }
  ]
}
```

#### `POST /api/bags/pangu`
Get basic Pangu data by bag names.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["names"],
  "properties": {
    "names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "vehicle": {"type": "string"},
          "datetime": {"type": "string", "format": "date-time"},
          "bag_path": {"type": "string"},
          "data_path": {"type": "string"}
        }
      }
    }
  }
}
```

**Example Request:**
```json
{
  "names": [
    "PL061763_event_ld_gps_event_20230807-115627_0.bag.dir",
    "PL061763_event_manual_recording_20230726-150140_0.bag.dir"
  ]
}
```

**Example Response:**
```json
{
  "data": [
    {
      "bag_name": "PL061763_event_ld_gps_event_20230807-115627_0.bag.dir",
      "vehicle": "PL061763",
      "datetime": "2023-08-07T11:56:27Z",
      "bag_path": "/pangu/bags/PL061763_event_ld_gps_event_20230807-115627_0.bag.dir",
      "data_path": "/pangu/data/PL061763_event_ld_gps_event_20230807-115627_0"
    }
  ]
}
```

#### `POST /api/bags/pangu/detail`
Get detailed Pangu information including file paths for all sensors.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["names"],
  "properties": {
    "names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "pangu_basic": {"type": "object"},
          "pangu_paths": {
            "type": "object",
            "properties": {
              "lidar_gt_pandar128": {"type": "string"},
              "camera_fisheye_left": {"type": "string"},
              "camera_fisheye_right": {"type": "string"},
              "camera_front_wide": {"type": "string"},
              "raw_gps": {"type": "string"},
              "raw_imu": {"type": "string"},
              "ego_motion": {"type": "string"},
              "calibration": {"type": "string"}
            }
          }
        }
      }
    }
  }
}
```

#### `POST /api/bags/topics`
Get topics information by bag names.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["names"],
  "properties": {
    "names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "topics": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "topic_name": {"type": "string"},
                "message_type": {"type": "string"},
                "key_data": {"type": "string"}
              }
            }
          }
        }
      }
    }
  }
}
```

#### `POST /api/bags/tags`
Get tags associated with specific bags.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["names"],
  "properties": {
    "names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "tags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tag_name": {"type": "string"},
                "tag_type": {"type": "string"},
                "creator": {"type": "string"},
                "update_time": {"type": "string", "format": "date-time"}
              }
            }
          }
        }
      }
    }
  }
}
```

#### `GET /api/bags/search/pangu`
Search Pangu data with various filter conditions.

**Query Parameters:**
- `project_id` (optional, integer): Filter by project ID
- `vehicle` (optional, string): Filter by vehicle name
- `start_date` (optional, string): Start date filter (YYYY-MM-DD format)
- `end_date` (optional, string): End date filter (YYYY-MM-DD format)
- `limit` (optional, integer): Limit results (default: 100, max: 1000)
- `offset` (optional, integer): Offset for pagination (default: 0)

**Example Request:**
```
GET /api/bags/search/pangu?project_id=1&vehicle=PL061763&limit=50&offset=0
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "vehicle": {"type": "string"},
          "datetime": {"type": "string", "format": "date-time"},
          "project_id": {"type": "integer"},
          "data_path": {"type": "string"}
        }
      }
    },
    "pagination": {
      "type": "object",
      "properties": {
        "total": {"type": "integer"},
        "limit": {"type": "integer"},
        "offset": {"type": "integer"},
        "has_more": {"type": "boolean"}
      }
    }
  }
}
```

### 🌳 FST管理 API (`/api/fst`)

#### `GET /api/fst/print_tree`
Get complete FST tree structure with hierarchical relationships.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "tree_structure": {
      "type": "object",
      "properties": {
        "root_nodes": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {"type": "integer"},
              "name": {"type": "string"},
              "bag_sum": {"type": "integer"},
              "children": {"type": "array"}
            }
          }
        }
      }
    },
    "statistics": {
      "type": "object",
      "properties": {
        "total_nodes": {"type": "integer"},
        "total_bags": {"type": "integer"},
        "max_depth": {"type": "integer"}
      }
    }
  }
}
```

#### `GET /api/fst/all_nodes`
Get all FST nodes with metadata.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "success": {"type": "boolean"},
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "label": {"type": "string"},
          "parent_id": {"type": "integer", "nullable": true}
        }
      }
    }
  }
}
```

#### `POST /api/fst/bags/nodes`
Get FST node assignments for specific bags with pagination support.

**Query Parameters:**
- `page` (optional, integer, default: 1): Page number
- `per_page` (optional, integer, default: 20, max: 100): Items per page

**Request Schema:**
```json
{
  "type": "array",
  "items": {"type": "string"},
  "example": ["fst_node1", "fst_node2"]
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "sts": {"type": "string"}
        }
      }
    },
    "page": {"type": "integer"},
    "per_page": {"type": "integer"},
    "total": {"type": "integer"}
  }
}
```

#### `GET /api/fst/bags/path/{name}`
Get bags under an FST node and its descendants.

**Path Parameters:**
- `name` (required, string): The FST node name

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "object",
    "properties": {
      "bags": {
        "type": "array",
        "items": {"type": "string"}
      }
    }
  }
}
```

#### `GET /api/fst/baglist`
Get complete FST tree structure with associated bags including event timing and comments.

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "object",
    "properties": {
      "id": {"type": "integer"},
      "name": {"type": "string"},
      "parent_id": {"type": "integer", "nullable": true},
      "parent_name": {"type": "string", "nullable": true},
      "bags": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "bag_name": {"type": "string"},
            "event_start_time": {"type": "integer", "nullable": true},
            "event_end_time": {"type": "integer", "nullable": true},
            "comments": {"type": "string", "nullable": true}
          }
        }
      },
      "children": {
        "type": "object",
        "description": "Child FST nodes with same structure"
      }
    }
  }
}
```

**Example Response:**
```json
{
  "1": {
    "id": 1,
    "name": "highway_scenarios",
    "parent_id": null,
    "parent_name": null,
    "bags": [
      {
        "bag_name": "PL061763_highway_20230807-115627_0.bag.dir",
        "event_start_time": 1000,
        "event_end_time": 2000,
        "comments": "Highway driving scenario with lane changes"
      }
    ],
    "children": {
      "2": {
        "id": 2,
        "name": "lane_change",
        "parent_id": 1,
        "parent_name": "highway_scenarios",
        "bags": [],
        "children": {}
      }
    }
  }
}
```

#### `POST /api/fst/bags/update`
Batch create or update FST-Bag associations.

**Request Schema:**
```json
{
  "type": "array",
  "items": {
    "type": "object",
    "required": ["bag_name", "nodes", "start", "end"],
    "properties": {
      "bag_name": {"type": "string"},
      "nodes": {
        "type": "array",
        "items": {"type": "string"},
        "description": "Ordered FST node names (parent → child)"
      },
      "start": {"type": "integer", "description": "Event start time"},
      "end": {"type": "integer", "description": "Event end time"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "bag_name": {"type": "string"},
      "success": {"type": "boolean"},
      "reason": {"type": "string", "nullable": true}
    }
  }
}
```

#### `DELETE /api/fst/{name}`
Delete an FST node by name.

**Path Parameters:**
- `name` (required, string): FST node name to delete

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "ok": {"type": "boolean"}
  }
}
```

#### `GET /api/fst/{name}/bags`
Get bags and Pangu details under an FST and its descendants.

**Path Parameters:**
- `name` (required, string): The FST node name

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "success": {"type": "boolean"},
    "data": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "bags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "bagName": {"type": "string"},
                "decodedDir": {"type": "string"},
                "tosPath": {"type": "string"},
                "mVizUrl": {"type": "string"},
                "mbVizUrl": {"type": "string"},
                "comment": {"type": "string"}
              }
            }
          }
        }
      }
    }
  }
}
```

#### `GET /api/fst/{name}`
Get specific FST node by name.

**Path Parameters:**
- `name` (required, string): FST node name

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "id": {"type": "integer"},
    "name": {"type": "string"},
    "parent_id": {"type": "integer"},
    "bag_sum": {"type": "integer"},
    "update_time": {"type": "string", "format": "date-time"},
    "children": {"type": "array"},
    "parent_path": {"type": "string"}
  }
}
```

#### `POST /api/fst/update`
Update FST node information.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["name"],
  "properties": {
    "name": {"type": "string"},
    "parent_id": {"type": "integer"},
    "reserved_json": {"type": "object"}
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "success": {"type": "boolean"},
    "message": {"type": "string"},
    "updated_node": {
      "type": "object",
      "properties": {
        "id": {"type": "integer"},
        "name": {"type": "string"},
        "parent_id": {"type": "integer"},
        "update_time": {"type": "string", "format": "date-time"}
      }
    }
  }
}
```

### 📁 项目管理 API (`/api/projects`)

#### `GET /api/projects/all`
Get all projects with bag statistics.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "projects": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "update_time": {"type": "string", "format": "date-time"},
          "bag_count": {"type": "integer"},
          "decoded_count": {"type": "integer"},
          "active_count": {"type": "integer"}
        }
      }
    }
  }
}
```

### 🏷️ 标签管理 API (`/api/tags`)

#### `GET /api/tags/all`
Get all available tags.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "tags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "type": {"type": "string"},
          "creator": {"type": "string"},
          "update_time": {"type": "string", "format": "date-time"},
          "comments": {"type": "string"},
          "is_deleted": {"type": "boolean"}
        }
      }
    }
  }
}
```

#### `GET /api/tags/bags`
Get tags with associated bag counts.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "tag_statistics": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "tag_name": {"type": "string"},
          "tag_type": {"type": "string"},
          "bag_count": {"type": "integer"},
          "creator": {"type": "string"}
        }
      }
    }
  }
}
```

#### `GET /api/tags/bags`
Get bags by tag names with intersection or union logic.

**Query Parameters:**
- `tags` (required, string): Comma-separated tag names (e.g., "A,B,C")
- `op` (optional, string): Operation type - "and" for intersection, "or" for union (default: "and")

**Example Request:**
```
GET /api/tags/bags?tags=driving,city&op=and
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "bags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"}
        }
      }
    }
  }
}
```

#### `GET /api/tags/creators/{creator}`
Get tags created by a specific creator.

**Path Parameters:**
- `creator` (required, string): Creator identifier (username or email)

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "tags": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

#### `POST /api/tags/{tag_name}/bags`
Batch apply tags to bags with creator tracking.

**Path Parameters:**
- `tag_name` (required, string): Tag name

**Query Parameters:**
- `creator` (optional, string, default: "system"): Creator identifier

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "tag_name": {"type": "string"},
    "creator": {"type": "string"},
    "total": {"type": "integer"},
    "succeeded": {"type": "integer"},
    "skipped": {"type": "integer"},
    "failed": {"type": "integer"},
    "details": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "status": {"type": "string", "enum": ["success", "skipped", "failed"]},
          "message": {"type": "string"}
        }
      }
    }
  }
}
```

### 📖 主题管理 API (`/api/topics`)

#### `GET /api/topics/all`
Get all available ROS topics.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "topics": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "type": {"type": "string"},
          "key_data": {"type": "string"},
          "update_time": {"type": "string", "format": "date-time"}
        }
      }
    }
  }
}
```

#### `GET /api/topics/bags/{topic_name}`
Get bags containing specific topic.

**Path Parameters:**
- `topic_name` (required, string): Topic name (URL encoded)

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "topic_name": {"type": "string"},
    "topic_info": {
      "type": "object",
      "properties": {
        "type": {"type": "string"},
        "key_data": {"type": "string"}
      }
    },
    "bags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "project_id": {"type": "integer"},
          "update_time": {"type": "string", "format": "date-time"}
        }
      }
    }
  }
}
```

### 🗺️ 几何数据管理 API (`/api/geometry`)

#### `POST /api/geometry/`
Process geospatial geometry data and perform spatial operations.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["rosbag_names"],
  "properties": {
    "rosbag_names": {
      "type": "array",
      "items": {"type": "string"}
    },
    "operation": {
      "type": "string",
      "enum": ["get_trajectory", "check_overlap", "get_bounds"],
      "default": "get_trajectory"
    },
    "downsample_factor": {"type": "integer", "default": 1}
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "rosbag_name": {"type": "string"},
          "trajectory": {
            "type": "object",
            "properties": {
              "type": {"type": "string", "enum": ["LineString", "MultiPoint"]},
              "coordinates": {"type": "array"}
            }
          },
          "is_overlapped": {"type": "boolean"},
          "update_time": {"type": "string", "format": "date-time"}
        }
      }
    }
  }
}
```

### 🎯 真值数据管理 API (`/api/gt`)

#### `GET /api/gt/types`
Get all available Ground Truth data types.

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "gt_types": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "type": {"type": "string"},
          "path": {"type": "string"},
          "update_time": {"type": "string", "format": "date-time"},
          "comment": {"type": "string"}
        }
      }
    }
  }
}
```

#### `GET /api/gt/{gt_name}/bags`
Get bags associated with specific Ground Truth data.

**Path Parameters:**
- `gt_name` (required, string): Ground Truth name

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "gt_name": {"type": "string"},
    "gt_info": {
      "type": "object",
      "properties": {
        "type": {"type": "string"},
        "path": {"type": "string"},
        "comment": {"type": "string"}
      }
    },
    "bags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "bag_name": {"type": "string"},
          "project_id": {"type": "integer"},
          "update_time": {"type": "string", "format": "date-time"},
          "comment": {"type": "string"}
        }
      }
    }
  }
}
```

#### `POST /api/bags/minerva`
Get Minerva data by session IDs.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["session_ids"],
  "properties": {
    "session_ids": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Example Request:**
```json
{
  "session_ids": ["session_123", "session_456"]
}
```

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "session_id": {"type": "string"},
        "vin": {"type": "string"},
        "start_ts": {"type": "number"},
        "end_ts": {"type": "number"},
        "platform": {"type": "string"},
        "path": {"type": "string"},
        "converted_path": {"type": "string"},
        "gt_path": {"type": "string"},
        "datetime": {"type": "string", "format": "date-time"},
        "length": {"type": "number"},
        "reserved_json": {"type": "object"}
      }
    }
  }
}
```

#### `POST /api/bags/minerva/detail`
Get detailed Minerva information by bag names.

**Request Schema:**
```json
{
  "type": "array",
  "items": {"type": "string"},
  "example": ["bag1.bag", "bag2.bag"]
}
```

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "object",
    "properties": {
      "session_id": {"type": "string"},
      "vin": {"type": "string"},
      "platform": {"type": "string"},
      "path": {"type": "string"},
      "converted_path": {"type": "string"},
      "gt_path": {"type": "string"},
      "datetime": {"type": "string", "format": "date-time"}
    }
  }
}
```

#### `POST /api/bags/life_cycle`
Get lifecycle information for specific bags.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "object",
    "properties": {
      "collect_time": {"type": "string", "format": "date-time"},
      "clone2dev_time": {"type": "string", "format": "date-time"},
      "decode_time": {"type": "string", "format": "date-time"},
      "mining_time": {"type": "string", "format": "date-time"},
      "auto_annotate_time": {"type": "string", "format": "date-time"},
      "manual_annotate_time": {"type": "string", "format": "date-time"},
      "fst_index_time": {"type": "string", "format": "date-time"}
    }
  }
}
```

#### `GET /api/bags/joined`
Get related bags before/after a specified bag by datetime.

**Query Parameters:**
- `bag_name` (required, string): Name of the central bag
- `before` (optional, integer, default: 5): How many bags to return before
- `after` (optional, integer, default: 5): How many bags to return after

**Response Schema:**
```json
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id": {"type": "integer"},
      "name": {"type": "string"},
      "vehicle": {"type": "string"},
      "datetime": {"type": "string", "format": "date-time"},
      "bag_path": {"type": "string"},
      "data_path": {"type": "string"}
    }
  }
}
```

#### `POST /api/bags/joined/create`
Create a merged parent bag from sub-bags.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"},
      "minItems": 1
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "joined_id": {"type": "integer"},
    "joined_name": {"type": "string"}
  }
}
```

#### `POST /api/bags/joined/query`
Query existing merged relationships by bag names.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"},
      "minItems": 1
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "array",
    "items": {"type": "string"}
  },
  "example": {
    "parent_merged": ["child1", "child2", "child3"],
    "parent2_merged": ["child4", "child5"]
  }
}
```

#### `POST /api/bags/joined/delete`
Delete merged parent bags and restore child bags.

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"},
      "minItems": 1
    }
  }
}
```

**Response Schema:**
```json
{
  "type": "object",
  "properties": {
    "deleted_parents": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}
```

#### `GET /api/bags/version`
Query bags by software/hardware version patterns.

**Query Parameters:**
- `sw` (optional, string): Software version pattern (supports * wildcards)
- `hw` (optional, string): Hardware version pattern (supports * wildcards)

**Example Request:**
```
GET /api/bags/version?sw=1.2.*&hw=*rev3*
```

**Response Schema:**
```json
{
  "type": "array",
  "items": {"type": "string"},
  "example": ["bag1.bag", "bag2.bag"]
}
```

### 🔄 重计算管理 API (`/api/recompute`)

#### `POST /api/recompute/versions`
Get recompute versions for bags (batch).

**Request Schema:**
```json
{
  "type": "object",
  "required": ["bag_names"],
  "properties": {
    "bag_names": {
      "type": "array",
      "items": {"type": "string"},
      "description": "List of bag names"
    }
  }
}
```

**Example Request:**
```json
{
  "bag_names": ["bag1.bag", "bag2.bag", "bag3.bag"]
}
```

**Response Schema:**
```json
{
  "type": "object",
  "additionalProperties": {
    "type": "array",
    "items": {"type": "string"}
  },
  "example": {
    "bag1.bag": ["v1.0", "v1.1", "v2.0"],
    "bag2.bag": ["v1.0", "v2.0"],
    "bag3.bag": []
  }
}
```

#### `POST /api/recompute/storage`
Get storage paths for bags and versions (batch).

**Request Schema:**
```json
{
  "type": "object",
  "required": ["requests"],
  "properties": {
    "requests": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["bag_name", "recompute_version"],
        "properties": {
          "bag_name": {"type": "string"},
          "recompute_version": {"type": "string"}
        }
      }
    }
  }
}
```

**Example Request:**
```json
{
  "requests": [
    {"bag_name": "bag1.bag", "recompute_version": "v1.0"},
    {"bag_name": "bag2.bag", "recompute_version": "v1.1"}
  ]
}
```

**Response Schema:**
```json
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "bag_name": {"type": "string"},
      "recompute_version": {"type": "string"},
      "results": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "result_id": {"type": "integer"},
            "bag_name": {"type": "string"},
            "recompute_version": {"type": "string"},
            "result_type": {"type": "string"},
            "storage_path": {"type": "string"},
            "status": {"type": "string"},
            "created_time": {"type": "string", "format": "date-time"},
            "reserved_json": {"type": "object"}
          }
        }
      }
    }
  }
}
```

## 🚀 Quick Start

### Prerequisites

- Python 3.12+
- PostgreSQL database
- uv package manager

### Installation

1. **Clone the repository**
   ```bash
   cd /home/cheng/Codes/fst_data_pipeline/fst_data_pipeline/apps/root_db_api
   ```

2. **Create virtual environment**
   ```bash
   uv venv
   source .venv/bin/activate
   ```

3. **Install dependencies**
   ```bash
   uv sync
   ```

4. **Set up environment variables**
   ```bash
   cp .env.example .env
   # Edit .env with your database configurations
   ```

5. **Initialize database**
   ```bash
   # Run database migrations or setup scripts
   python -m alembic upgrade head
   ```

### Running the Application

#### Development Mode
```bash
python src/app.py
```

#### Production Mode
```bash
gunicorn --bind 0.0.0.0:5232 --workers 4 src.app:app
```

API服务访问地址:
- **API基础URL**: `http://localhost:5232/api`
- **Swagger UI文档**: `http://localhost:5232/apidocs/`

## 🔧 Configuration

### Environment Variables

Create a `.env` file with the following variables:

```env
# Database Configuration
DATABASE_URL=postgresql://username:password@localhost:5432/dbname

# Flask Configuration
FLASK_ENV=development
FLASK_DEBUG=True

# API Configuration
API_VERSION=0.5.0

# Feishu sync switch for version activation (backend)
# Default is off. Set to true only when you want to sync to Feishu.
ENABLE_FEISHU_SYNC=false
```

### Database Configuration

The application uses PostgreSQL with SQLAlchemy. Key models include:
- **Project**: Project information
- **Bag**: Bag file metadata
- **FST**: File system tree nodes
- **Tag**: Data tagging system
- **Topic**: Topic classification
- **GT**: Ground truth data

## 🧪 Testing

Run the test suite:

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=src --cov-report=html

# Run specific test module
pytest src/test/api/test_bags.py -v
```

## 📚 API Documentation

### Swagger/OpenAPI 中文文档

交互式中文API文档，当服务器运行时可通过 `/apidocs/` 访问。

**主要功能:**
- 🌐 **完整中文界面** - 所有API标签、描述都已中文化
- 📋 **8大功能模块** - Bag管理、标签管理、FST管理、项目管理、主题管理、几何数据管理、真值数据管理、重计算管理
- 🔄 **实时测试** - 可直接在文档中测试API接口
- 📝 **详细示例** - 每个接口都包含完整的请求/响应示例

### Example API Calls

#### Get All Bags
```bash
curl -X GET "http://localhost:5232/api/bags/all" \
     -H "accept: application/json"
```

#### Get Pangu Data by Names
```bash
curl -X POST "http://localhost:5232/api/bags/pangu" \
     -H "accept: application/json" \
     -H "Content-Type: application/json" \
     -d '{
       "names": [
         "PL061763_event_ld_gps_event_20230807-115627_0.bag.dir"
       ]
     }'
```

#### Search Pangu Data
```bash
curl -X GET "http://localhost:5232/api/bags/search/pangu?project_id=1&limit=10" \
     -H "accept: application/json"
```

#### Get FST Tree
```bash
curl -X GET "http://localhost:5232/api/fst/print_tree" \
     -H "accept: application/json"
```

#### Update FST Node
```bash
curl -X POST "http://localhost:5232/api/fst/update" \
     -H "accept: application/json" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "highway_scenarios",
       "description": "Updated highway driving scenarios",
       "parent_id": null
     }'
```

## 🔒 Security

- Input validation with Pydantic models
- SQL injection protection via SQLAlchemy ORM
- Error handling and logging
- Rate limiting (configure as needed)

## 📈 Performance

- Database connection pooling
- Optimized SQL queries
- Configurable Gunicorn workers
- Efficient SQLAlchemy ORM queries

## 🚀 Deployment

### Docker Deployment
```bash
# Build Docker image
docker build -t root-db-api .

# Run container
docker run -p 5232:5232 --env-file .env root-db-api
```

### Production Checklist
- [ ] Configure environment variables
- [ ] Set up PostgreSQL database
- [ ] Set up reverse proxy (nginx)
- [ ] Configure logging
- [ ] Set up monitoring
- [ ] Configure SSL/TLS
- [ ] Set up database backups

## 📝 Development

### Project Structure
```
src/
├── api/                    # API接口模块
│   ├── bags.py            # Bag管理API
│   ├── fst.py             # FST管理API
│   ├── projects.py        # 项目管理API
│   ├── tags.py            # 标签管理API
│   ├── topics.py          # 主题管理API
│   ├── geometry.py        # 几何数据管理API
│   ├── recompute.py       # 重计算管理API
│   └── gt.py              # 真值数据管理API
├── core/                   # Core business logic
│   ├── models.py          # Database models
│   └── service.py         # Business logic services
├── db/                     # Database layer
│   └── connection.py      # Database connection
├── test/                   # Test files
└── app.py                  # Application entry point
```

### Contributing

1. Fork the repository
2. Create a feature branch
3. Write tests for new features
4. Ensure all tests pass
5. Submit a pull request

## 📊 Monitoring

### Health Check Endpoint
```bash
curl http://localhost:5232/
# Returns: "Hello World!"
```

### Metrics
- Prometheus metrics integration available
- Monitor API response times
- Track database query performance
- Monitor database connection pool usage

## 🆘 Troubleshooting

### Common Issues

1. **Database Connection Error**
   - Check PostgreSQL service status
   - Verify DATABASE_URL configuration
   - Ensure database exists and is accessible

2. **Import Errors**
   - Ensure virtual environment is activated
   - Run `uv sync` to install dependencies

3. **Port Already in Use**
   - Change port in app.py or use environment variable
   - Kill existing processes on port 5232

4. **Geospatial Query Errors**
   - Ensure PostGIS extension is installed
   - Check spatial data formats and coordinates

## 📞 Support

- **Author**: Cheng Li
- **Email**: tbd@tbd.com
- **Version**: 0.5.0

## 📄 License

[Add your license information here]

---

**Happy Coding! 🚀**
